虚拟订阅反射获得的事件

时间:2011-07-18 13:39:12

标签: c# wpf mvvm weak-references

我正在使用MVVM模式在WPF中进行MessageBox控制。这个MessageBox将在具有不同外观的多个应用程序中使用,因此理想情况下我希望将代码保留在代码隐藏之外。

我正在尝试在MessageBox的声明中指定引发事件时显示MessageBox

例如,这将在MessageBox出现的窗口的XAML中指定。

<dialog:MessageBox
    ShowOnEvent="EventRaised"
    EventContext="{Binding}"
    Message="I am a message box"
    IconType="Warning"
    ButtonsType="YesNo" />

目前的工作方式:在MessageBox ViewModel中,我使用反射来获取事件的EventInfo,然后直接订阅:

if (eventContext != null && showOnEvent != string.Empty)
{
    EventInfo eventInfo = eventContext.GetType ().GetEvent (showOnEvent);
    if (eventInfo != null)
    {
        eventInfo.AddEventHandler (eventContext, eventHandler);
    }
    else
    {
        Debug.WriteLine (string.Format ("Dialog: Couldn't find event {0} on {1}, check event name.", showOnEvent, eventContext));
    }
}

按预期显示事件引发时的MessageBox

但是,事件处理程序意味着在放置主窗口的View时MessageBox ViewModel不是GC'd。这意味着如果创建了主窗口的另一个视图,则会创建另一个MessageBox,因此如果引发了该事件,则会显示MessageBox个。{/ p>

我尝试使用WeakEventManager解决此问题,但Weak Event Patterns documentation指定WeakEventManager的实现只应处理一个事件 - 这意味着我无法生成{ {1}}将事件名称作为字符串属性并使用它进行订阅。

有没有人对最佳方法有任何想法?

2 个答案:

答案 0 :(得分:1)

弱事件无法解决您的问题,因为在GC决定运行之前您不会被取消订阅(除非您明确调用GC.Collect())。正如Will在评论中建议的那样,你可以尝试在适当的时候取消订阅,或者更容易的是让你的MessageBox在显示之前检查它是否IsLoaded

我不担心你的MessageBox中的代码隐藏,除非你知道它会损害其可重用性的某些原因。只要MessageBox的使用者拥有一个MVVM友好的API,就可以让MessageBox代码直接引用它的视图。

答案 1 :(得分:0)

PRISM EventAggregator默认使用弱引用实现事件。您需要能够更改发布事件的代码,以便在您的应用中实现此功能。

链接页面上有正确的代码示例以及强制性流程图。事件聚合器使用起来非常简单:您Publish具有强类型有效负载,Subscribe可以在您需要的任意位置使用。 (它是free to download