0

Most of my UserControls and classes need to be able to add entry (log) to ObservableCollection in MainWindow which is bound by a ListBox.

Is there an elegant way to do it without passing MainWindow to each of these classes and controls and without usage of events so I don't need to worry about memory leaks?

EDIT: Good idea that I could pass only Log class but I would still like to avoid passing Log on instantiating to every class.

I am hoping for existence of some application wide listener that would be able to receive message from anywhere, keeping code clean.

7
  • 1
    what makes you think that there will be Memory Leaks are you writing code where you are not either implementing the Auto Disposing of Objects i. using(){} or not cleaning up objects yourself.. You need to implement the INotifyPropertyChanged if you are not familiar with how to do that then here is where you can start reading Daniel INotifyPropertyChange Commented Dec 4, 2014 at 17:16
  • @DJKRAZE Not -=ing event handlers can pin otherwise properly disposed objects in the heap and prevent the GC from cleaning them up. That's not to say that there isn't an easy solution to the problem (ie : removing handlers that you've added), but there are more ways to provoke a memory leak than you've suggested. Commented Dec 4, 2014 at 17:18
  • Why are you passing MainWindow? Just pass the log. Commented Dec 4, 2014 at 17:18
  • J I am well aware of the many ways that Memory Leaks can be Introduced I was just asking in general Commented Dec 4, 2014 at 17:20
  • 1
    The only way that this would be leaking memory is if these other controls are going to outlive the main window by a long period of time. That sounds unlikely, and so having the main window attach a handler to those other controls with a reference to itself isn't going to be a problem. Commented Dec 4, 2014 at 17:37

3 Answers 3

2

Prism provides you with an EventAggregator and takes care of managing the object. Using the aggregator you only publish and subscribe for events. If you need to pass some data you can publish them with the event.

this.eventAggregator.GetEvent<MyEvent>().Publish(myCustomData);

And when subscribing for the event you also can include a handler to process the data.

this.eventAggregator.GetEvent<MyEvent>).Subscribe(this.HandleMyCustomData);

With handler like that:

private void HandleMyCustomData(MyCustomData data) { }

Although it's still event based the solution is much more elegant than using classic events and handlers.

Under this link you can find much more thorough explanation: http://msdn.microsoft.com/en-us/library/ff921122.aspx

Sign up to request clarification or add additional context in comments.

5 Comments

Even though is seems simple I would like to try avoiding adding Prism to my solution just to have a log.
Fair enough. Still it might be a useful clue for anyone who is at the stage of planning rather than implementing.
@Daniel You can write your own simple EventAggregator quite easily. You can even look around the Internet to find an existing one without full Prism behind it.
I am trying to implement github.com/shiftkey/Reactive.EventAggregator but how I see it I need global object eventAggregator which needs to be accessible from all classes. This seems the same as if I called MainWindow.LogCollection.Add
Using above mentioned: If I understood I make public static EventAggregator eventAggregator and use it to publish and subscribe. It works and looks simple. Is that how it is done?
0

Yes the Prism EventAggregator is very nice for this sort of thing.

But if you don't want to sip the Prism Kool-Aid another approach that may work is for your MainWindow to register a custom TraceListener and have your other code use Trace methods to populate the log. The MainWindow TraceListener can then do whatever you want with the Trace data.

Comments

0

I ended up using github.com/shiftkey/Reactive.EventAggregator as I already use Reactive in my program and it is quite simple

In MainWindow I have

using Reactive.EventAggregator;
MyEventAggregator.MessageAggregator = new EventAggregator();
MyEventAggregator.MessageAggregator.GetEvent<MessageEvent>().Subscribe(se =>
myMessageControl.Add(se)
);

Then there is a UserControl that has a ListBox LB

using Reactive.EventAggregator;
public partial class MessageControl : UserControl
{
    public MessageControl()
    {
        InitializeComponent();
        LB.SetBinding(ListBox.ItemsSourceProperty, new Binding { Source = this.MessageCollection });
    }
    public ObservableCollection<MessageEvent> MessageCollection = new ObservableCollection<MessageEvent>();

    public void Add(MessageEvent m)
    {
        MessageCollection.Add(m);
    }
}

public class MyEventAggregator
{
    public static EventAggregator MessageAggregator { get; set; }
    public static void PostMessage(string message)
    {
        MessageAggregator.Publish(new MessageEvent(message));
    }
}

From anywhere in program I can use

MyEventAggregator.PostMessage("This message appears in MessageControl's Listbox");

It can be even simplified but I want the MessageEvent to hold more than just a string in the future.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.