Как удалить событие click из пользовательского элемента управления с помощью отражения? - PullRequest
0 голосов
/ 28 октября 2019

У меня есть пользовательский элемент управления (MenuButton) в WPF, который подписывается на событие Click. Теперь я хочу использовать рефлексию, чтобы отписаться от события. Вот как мой код выглядит в настоящее время:

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);

Как мне обойти это, если я перестаю использоватьЛямбда-выражения?

Ответы [ 2 ]

1 голос
/ 28 октября 2019

Если вместо того, чтобы использовать лямбды для подписки на ваши события, вы используете методы, отписаться просто:

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;
    }
}
0 голосов
/ 28 октября 2019

С этим довольно легко справиться, не используйте лямбда-выражения!

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;
        }
    }
}
...