COleChangeSourceDialog不能Change Source的解决方法

本文解决了OClient中更改OLE对象源时出现的错误。通过分析COleChangeSourceDialog类的构造函数及关联函数,发现m_pDocument为空导致的问题,并提供了一个继承自COleChangeSourceDialog的新类来解决该问题。

 

在微软给的例子OClient中,有选中一个OLE对象然后Change Source的功能,但是会报错。分析了一下是这样的:

void CMainView::OnOleChangeSource()

{

    ASSERT(m_pSelection != NULL && m_pSelection->GetType() == OT_LINK);

 

    COleChangeSourceDialog dlg(m_pSelection);

    dlg.DoModal();

}

 

然后找到COleChangeSourceDialog 的定义,在c:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\atlmfc\include\afxodlgs.h中。

可以看到里面有个成员m_xLinkInfo.

然后找到COleChangeSourceDialog的实现文件,在C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\oledlgs3.cpp。

先看构造函数:

COleChangeSourceDialog::COleChangeSourceDialog(COleClientItem* pItem,

    CWnd* pParentWnd) : COleDialog(pParentWnd), m_xLinkInfo(NULL)

{

    ASSERT_VALID(pItem);

 

    memset(&m_cs, 0, sizeof(m_cs)); // initialize structure to 0/NULL

 

    // fill in common part

    m_cs.cbStruct = sizeof(m_cs);

    m_cs.dwFlags = 0;

    if (AfxHelpEnabled())

        m_cs.dwFlags |= CSF_SHOWHELP;

    m_cs.lpfnHook = AfxOleHookProc;

    m_nIDHelp = AFX_IDD_CHANGESOURCE;

 

    // specific to this dialog

    m_cs.lpOleUILinkContainer = &m_xLinkInfo;

    COleDocument* pDoc = pItem->GetDocument();

    DWORD dwItem = 0;

    if (pDoc != NULL)

    {

        POSITION posItem = pDoc->GetStartPosition();

        ULONG iItem = 1;

        while ((posItem != NULL) && (dwItem == 0))

        {

            COleClientItem* pSearchItem = pDoc->GetNextClientItem(posItem);

            if (pSearchItem == pItem)

            {

                dwItem = iItem;

            }

            iItem++;

        }

    }

    m_cs.dwLink = dwItem;

}

 

可以看到,这里面把成员m_xLinkInfo设置为NULL.

这里面用到了pItem,就是我们在CMainView::OnOleChangeSource传进来的m_pSelection, pItem->GetDocument()得到的就是我们主程序的CMainDoc指针,构造函数利用这个指针,获得当前文档中被选中的OLE对象的索引,比如第一个就是1.

m_xLinkInfo被赋给了m_cs.lpOleUILinkContainer,m_cs的定义如下:

OLEUICHANGESOURCE m_cs

 

构造函数根据传入的pItem,初始化m_cs成员,以备它的其他函数调用。

现在我们回头看CMainView::OnOleChangeSource事件,这个事件中调用了COleChangeSourceDialog.DoModal函数。下面是这个函数的代码:

INT_PTR COleChangeSourceDialog::DoModal()

{

    ASSERT_VALID(this);

    ASSERT(m_cs.lpfnHook != NULL); // can still be a user hook

 

    m_cs.hWndOwner = PreModal();

    INT_PTR iResult = MapResult(::OleUIChangeSource(&m_cs));

    PostModal();

    return iResult;

}

 

可以看到这里用到了m_cs变量。

然后执行这步的时候报错了,报错点在这个文件的这个函数:

C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\atlmfc\src\mfc\oledlgs1.cpp

COleClientItem* COleUILinkInfo::GetLinkItem( DWORD dwLink )

{

    POSITION posItem = m_pDocument->GetStartPosition();

    COleClientItem* pItem = NULL;

    for (ULONG iLink = 0; iLink < dwLink; ++iLink)

    {

        pItem = m_pDocument->GetNextClientItem(posItem);

    }

 

    return pItem;

}

 

调试了一下发现m_pDocument为NULL(0x00000000)

为什么那?

我们看COleUILinkInfo的构造函数:

 

COleUILinkInfo::COleUILinkInfo(COleDocument* pDocument)

{

    ASSERT(pDocument == NULL ||

        pDocument->IsKindOf(RUNTIME_CLASS(COleDocument)));

    m_pDocument = pDocument;

    m_pSelectedItem = NULL;

    m_pos = NULL;

    m_bUpdateLinks = FALSE;

    m_bUpdateEmbeddings = FALSE;

}

 

现在问题明确了,因为在COleChangeSourceDialog的构造函数中把成员m_xLinkInfo设置为NULL, 所以传给COleUILinkInfo构造函数的参数也是空,所以COleUILinkInfo的m_pDocument成员为空,所以m_pDocument->GetStartPosition()会报错。

【解决方法】

继承COleChangeSourceDialog类自己写一个类来修复这个问题。

#pragma once

#include "afxodlgs.h"

 

class MyOleChangeSourceDialog :

    public COleChangeSourceDialog

{

public:

    MyOleChangeSourceDialog(COleClientItem* pItem, CWnd* pParentWnd = NULL);

};

 

#include "MyOleChangeSourceDialog.h"

 

MyOleChangeSourceDialog::MyOleChangeSourceDialog(COleClientItem* pItem,

                                                 CWnd* pParentWnd) : COleChangeSourceDialog(pItem, pParentWnd)

{

    m_xLinkInfo = COleUILinkInfo(pItem->GetDocument());

}

 

然后调用新类。

void CMainView::OnOleChangeSource()

{

    ASSERT(m_pSelection != NULL && m_pSelection->GetType() == OT_LINK);

 

    MyOleChangeSourceDialog dlg(m_pSelection);

    

    dlg.DoModal();

}

 

运行起来后,成功!选择Change Source的时候不再报错了。

<think>嗯,用户遇到了jQuery的.change方法不起作用的问题,需要解决。首先,我得回想一下常见的可能原因和解决方法。根据提供的引用内容,有几个可能性:事件绑定问题、动态元素未正确绑定、第三方插件冲突,或者手动触发的问题。 首先,引用[1]提到了用.off("change")来解绑之前的change事件,防止多次绑定。这可能适用于用户重复绑定事件的情况,导致事件触发多次或者不触发。这时候需要先解绑再重新绑定。 然后,引用[2]提到当使用jQuery UI自定义select元素时,原生的change事件可能不生效,需要改用jQuery UI提供的事件。例如,如果用户用jQuery UI的样式覆盖了原生select,可能需要触发selectmenuchange事件而不是原生的change事件。这种情况下,用户需要检查是否使用了第三方UI库修改了元素,导致事件监听方式不同。 引用[3]则指出第三方插件可能不支持原生的change方法,需要手动配置或者使用插件提供的方法。例如,searchableSelect插件可能需要特定的配置才能支持change事件,或者需要调用插件自己的方法来实现联动效果。这时候用户需要查阅插件的文档,找到正确的事件绑定方式。 接下来,我需要将这些可能性整理成步骤,帮助用户逐步排查问题。第一步应该是检查元素是否正确绑定事件,确认选择器是否正确,元素是否存在。如果元素是动态生成的,可能需要使用事件委托,如.on()方法。第二步是查看是否重复绑定了事件,导致之前的回调干扰,这时候需要用.off()解绑。第三步是检查是否第三方插件修改了元素的事件,需要改用插件特定的事件。第四步是确保在修改值后手动触发change事件,比如使用.trigger('change')。 此外,还要考虑其他可能因素,比如jQuery版本问题,或者DOM未加载完成就绑定事件。因此,建议用户将代码放在$(document).ready()中,并检查控制台是否有错误。 最后,根据用户的具体情况,可能需要结合引用的解决方案,比如使用off解绑、改用特定事件或配置第三方插件。提供示例代码会帮助用户更直观地理解解决方法,比如动态元素的事件委托示例,或者处理jQuery UI select的示例。</think>### 如何解决 jQuery .change 方法不起作用的问题? #### 1. **检查事件绑定是否正确** - **问题原因**:元素未正确绑定事件,或选择器错误导致事件未生效。 - **解决方法**: - 确保元素选择器正确,例如 `$("#id")` 而非 `$(".class")`。 - 若元素是动态生成的,需使用事件委托: ```javascript $(document).on('change', '#dynamicElement', function() { ... }); ``` #### 2. **解绑重复事件** - **问题原因**:同一事件被多次绑定,导致回调函数重复执行或冲突[^1]。 - **解决方法**: 使用 `.off('change')` 解绑后再重新绑定: ```javascript $("#id").off("change").change(function() { ... }); ``` #### 3. **处理第三方插件冲突** - **问题原因**:第三方插件(如 jQuery UI)可能覆盖原生事件逻辑[^2][^3]。 例如,自定义 `select` 元素可能需改用插件特定事件。 - **解决方法**: - 查阅插件文档,改用对应事件(如 `selectmenuchange`): ```javascript $("#selectID").selectmenu().on("selectmenuchange", function() { ... }); ``` - 若插件不支持原生事件,尝试手动触发: ```javascript pluginInstance.trigger('customChange'); ``` #### 4. **手动触发事件** - **问题原因**:通过代码修改元素值后,需手动触发 `change` 事件。 - **解决方法**: 使用 `.trigger('change')`: ```javascript $("#inputID").val("new value").trigger('change'); ``` #### 5. **检查 jQuery 版本兼容性** - **问题原因**:旧版本 jQuery 可能对动态元素支持不足。 - **解决方法**: 升级到最新版本 jQuery(需测试兼容性)。 --- ### 示例代码 **场景**:动态生成的输入框绑定 `change` 事件 ```javascript // 事件委托绑定动态元素 $(document).on('change', '#dynamicInput', function() { console.log("Value changed:", $(this).val()); }); // 若使用 jQuery UI 的 select $("#customSelect").selectmenu().on("selectmenuchange", function() { console.log("Selection changed"); }); ``` --- ### 相关问题 1. 如何为动态生成的元素绑定事件? 2. jQuery 事件委托(`.on()`)的使用场景是什么? 3. 如何处理第三方插件与原生事件的冲突? --- 通过以上步骤,可覆盖大多数 `.change` 方法失效的场景。若仍存在问题,建议检查浏览器控制台报错或提供代码片段进一步分析。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值