开发者

Subscribe weakly to events obtained by reflection

I'm making a MessageBox control in WPF using the MVVM pattern. This MessageBox will be used in multiple applications with different appearances, so ideally I want to keep code out of code-behind.

I'm trying to make the MessageBox appear when an event is raised, specified in the declaration of the MessageBox.

For example, this would be specified in the XAML of the window in which the MessageBox should appear.

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

The way this currently works: in the MessageBox ViewModel I'm using reflection to get the EventInfo for the event, then subscribing directly:

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

This shows the MessageBox when the event is raised, as expected.

However, the event handler means that the MessageBox ViewModel is not GC'd when the main window's View is disposed. This means that if another view for the main window is created, another MessageBox is created, so if the event is raised, both MessageBoxs will show.

I tried getting around this by u开发者_开发百科sing a WeakEventManager, but the Weak Event Patterns documentation specify that an implementation of WeakEventManager should only handle one event - which means that I can't make a ShowOnEventEventManager with the event name as a string property and subscribe using that.

Does anyone have any ideas for the best way to go about this?


Having a weak event won't solve your problem because you won't be unsubscribed until the GC decides to run (unless you're explicitly calling GC.Collect()). As Will suggests in the comments, you can try to unsubscribe at the appropriate time or what might be even easier is just have your MessageBox check if it IsLoaded before showing itself.

I wouldn't worry about code-behind in your MessageBox unless you know of some reason why it would hurt its reusability. It's fine to have MessageBox code reference its view directly as long as the consumers of the MessageBox have a MVVM-friendly API.


The PRISM EventAggregator implements eventing using weak references by default. You need to be able to alter the code where events are published to implement this in your app.

There are proper code examples at the linked page as well as the obligatory flow diagrams. The event aggregator is fairly simple to use: you Publish with a strongly typed payload and Subscribe in as many places as you need. (And it's free to download)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜