【问题标题】:How do I remove a click event from a custom control using reflection?如何使用反射从自定义控件中删除单击事件?
【发布时间】:2019-10-28 12:29:09
【问题描述】:

我在 WPF 中有一个订阅 Click 事件的自定义控件 (MenuButton)。我现在想使用反射来取消订阅该事件。这是我的代码目前的样子:

private void RemoveClickEvent(MenuButton mbButton)
{
    FieldInfo fiFieldInfo = mbButton.GetType().GetField("Click", BindingFlags.Public | BindingFlags.NonPublic |
                                                        BindingFlags.Instance |BindingFlags.Static | BindingFlags.GetField);
    object objValue = fiFieldInfo.GetValue(mbButton);
    PropertyInfo piProprtyInfo = mbButton.GetType().GetProperty("Events", BindingFlags.Public | BindingFlags.NonPublic |
                                                                BindingFlags.Instance | BindingFlags.Static | BindingFlags.GetField | BindingFlags.GetProperty);

    EventHandlerList ehEventHandlers = (EventHandlerList)piProprtyInfo.GetValue(mbButton, null);
    ehEventHandlers.RemoveHandler(objValue, ehEventHandlers[objValue]);
}

我可以成功获取 FieldInfo 对象,但 PropertyInfo 对象显示为空。如何修复我的代码以使该方法正常工作?作为记录,我的目标是 .NET Framework 4。

编辑:

这是我订阅事件的方式。

private void PageStart()
{
    //Subscribe to the necessary event when a page is first loaded
    foreach (MenuButton mbItem in mbMenuButtonsList)
    {
        if (mbItem.HideExtraInfo == true)
        {
            mbButton.Click += (sender, e) => ShowOrHideControls(sender, e, true);
        }
        else
        {
            mbButton.Click += (sender, e) => ShowOrHideControls(sender, e, false);
        }
    }
}

private void PageEnd()
{
    //When moving to the next page, unsubscribe from the events
    foreach (MenuButton mbItem in mbMenuButtonsList)
    {
        RemoveClickEvent(mbItem);
    }
}

编辑#2:

我忽略了一点,我在项目中使用的一些事件也需要传入 MenuButton,如下所示:

UIElementCollection ctrlControls = MainCanvas.Children;
mbButton.Click += (sender, e) => ChangeControls(sender, e, mbButton, ctrlControls, false);

如果我停止使用 Lambda 表达式,我该如何解决这个问题?

【问题讨论】:

  • WPF 中的事件是RoutedEvent,我不确定您是否可以简单地使用反射来修改处理程序列表。
  • @TanveerBadar 如果我尝试的方法在 WPF 中是不可能的,你能建议另一种方法吗?
  • 事件是如何订阅的?你能显示那个代码吗?一旦我们知道事件是如何连接起来的,取消订阅就会容易得多。
  • @TanveerBadar 问题已更新以显示此内容。
  • sender 是 MenuButton 本身。

标签: c# wpf events reflection


【解决方案1】:

如果您不使用 lambda 订阅您的事件,而是使用方法,那么取消订阅很容易:

if (mbItem.HideExtraInfo == true)
{
    mbButton.Click += ShowControls;
}
else
{
    mbButton.Click += HideControls;
}

private void ShowControls(object sender, EventArgs e) => ShowOrHideControls(sender, e, true);
private void HideControls(object sender, EventArgs e) => ShowOrHideControls(sender, e, false);

private void PageEnd()
{
    //When moving to the next page, unsubscribe from the events
    foreach (MenuButton mbItem in mbMenuButtonsList)
    {
        mbItem.Click -= ShowControls;
        mbItem.Click -= HideControls;
    }
}

【讨论】:

  • 如果没有为 Click 事件分配该方法,取消订阅该事件是否有任何后果?即如果 Click 只订阅 ShowControls,尝试取消订阅它和 HideControls 都没有问题?
  • 不,您可以随时安全地退订 - 即使您没有先订阅。
  • 感谢您的帮助,但我遇到了另一个问题。我更新了问题,添加了一些我之前忽略的信息。
【解决方案2】:

这很容易处理,不要使用 lambda 表达式!

private void PageStart()
{
    //Subscribe to the necessary event when a page is first loaded
    foreach (MenuButton mbItem in mbMenuButtonsList)
    {
        if (mbItem.HideExtraInfo == true)
        {
            mbButton.Click += true_handler;
        }
        else
        {
            mbButton.Click += false_handler;
        }
    }
}

void true_handler(object sender, EventArgs args)
{
    ShowOrHideControls(sender, e, true);
}

void false_handler(object sender, EventArgs args)
{
    ShowOrHideControls(sender, e, false);
}

private void PageEnd()
{
    //When moving to the next page, unsubscribe from the events
    foreach (MenuButton mbItem in mbMenuButtonsList)
    {
        if (mbItem.HideExtraInfo == true)
        {
            mbButton.Click -= true_handler;
        }
        else
        {
            mbButton.Click -= false_handler;
        }
    }
}

【讨论】:

  • 感谢您的帮助,但我遇到了另一个问题。我更新了问题,添加了一些我之前忽略的信息。
  • sender 是菜单按钮。在ShowOrHideControls 中将其类型转换为正确的类型。
猜你喜欢
  • 2013-11-24
  • 1970-01-01
  • 1970-01-01
  • 2022-01-14
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 2021-12-19
相关资源
最近更新 更多