E.g. for a general type, which subscribe to some events in constructor:
class SomeType
{
public SomeType(...)
{
someEvent1 += ...
someEvent2 += ...
}
}
Where do I unsubscribe from events?
Finalizer?
IDisposable ?
Some method DontForgetToCallMeSoICanUnsubscribeFromEvents()?
Use weak events pattern?
I know it depends. In case of controls (wpf, winforms) there are some events what can be used to subscribe/unsubscribe like Loaded/Unloaded, HandleCreated/HandleDestroyed, etc. But what if parent is a simple object?
And some more specific example: nested ViewModels, where each level is a List<NextLevelVM>, at any level ViewModel can be deleted, does that means what each ViewModel must implement IDisposable (if e.g. it is the right way) where it call Dispose for each item in their list? I tried to use weak events, but that doesn't go well.
I've found a really good way to handle this issue is to create two methods in the page's code behind, that calls methods on your ViewModel to start/stop listening to events depending on whether it's visible or not.
Below I'm using the Appearing functions, but depending on the framework you're using it might be slightly different, but the strategy should work.
In Page class:
protected override void OnAppearing()
{
base.OnAppearing();
_myViewModel.StartListeningToEvents();
}
protected override void OnDisappearing()
{
base.OnDisappearing();
_myViewModel.StopListeningToEvents();
}
Then in my ViewModel, I actually subscribe to the events I require:
public void StartListeningToEvents()
{
SomeProperty.PropertyChanged += PropertyUpdated;
}
public void StopListeningToEvents()
{
SomeProperty.PropertyChanged -= PropertyUpdated;
}
void PropertyUpdated(object sender, PropertyChangedEventArgs e)
{
// do stuff
}
My example is for a property change event. But similar code should work for any event.
In this way you're guaranteed that your page is only listening to events when it's open, and you don't need to worry about disposing anything besides calling the one event when the page is no longer open.
Related
I'm trying to use the Repository pattern to manage my Service Access in a WPF application.
So basically I plan on using Ninject to inject my Singleton ServiceManager into each view that needs it.
I've built the ServiceManager so that each method call is asynchronous.
Now I've hit a snag. I'm creating a View that contains a DataGrid, populated by a slow, asychronous method. Currently I have the call in teh constructor but I obviously can't make the constructor asynchronous.
public partial class OffersView : UserControl
{
public OffersView(ISvcManager svcManager)
{
InitializeComponent();
Offers.ItemsSource = await svcManager.GetLatestOffers();
}
}
I can think of a couple of ways around this, eg I could separate the interface into fast methods and slow methods, and use async only for the slow ones with the synchronous fast methods being the ones called in Constructors. Not sure if this is the best approach to use though - and where would be the best place to call a long-running method to populate the datagrid?
Alternatively, I put a Wait() in there and only set the ItemSource after this completes. I REALLY don't like that approach.
So how should I be setting this one up?
Use an asynchronous event handler like Loaded, which will allow for async calls.
For example
public partial class OffersView : UserControl {
private readonly ISvcManager svcManager;
public OffersView(ISvcManager svcManager) {
this.svcManager = svcManager;
InitializeComponent();
Loaded += onLoaded;
}
private async void onLoaded(Object sender, RoutedEventArgs e) {
Loaded -= onLoaded; // Unsubscribe to prevent repeated firing.
Offers.ItemsSource = await svcManager.GetLatestOffers();
}
}
I think the answer is NO but I thought of asking to see if it's possible at all
Scenario: I have a WPF application that uses a class with static events to subscribe interactions between different controls
Basically,
public class EventNotifier
{
public static event EventHandler<SomeEventArgs> EventTriggered;
public static void NotifyEventTriggered(object source, SomeEventArgs eventArgs)
{
if (EventTriggered!= null)
{
EventTriggered(source, eventArgs);
}
}
}
Then from some controls some methods get subscribed:
EventNotifier.EventTriggered+= new EventHandler<SomeEventArgs>(SomeMethodToReceiveEvent);
And from some other controls the events are triggered:
EventNotifier.NotifyEventTriggered(null, eventArgs);
This is all very straightforward. When the controls that subscribed their methods are disposed the events are disposed as well:
EventNotifier.EventTriggered-= new EventHandler<SomeEventArgs>(SomeMethodToReceiveEvent);
Given the nature of WPF that makes memory leaks rife where events are not unsubscribed correctly, until now I've had to manually test every control every time a leak was happening to ensure events were being disposed correctly. This is very time consuming
Some tools that analyze memory usage that I've used are completely incompetent at identifying the event that wasn't unsubscribed that was causing a memory leak
This is why I've been dreaming of creating my own tool to detect every time a method is subscribed to an event and also detect every time it's unsubscribed
I know I could do it in code using properties like:
private static event EventHandler<SomeEventArgs> eventTriggered
public static event EventHandler<SomeEventArgs> EventTriggered
{
add
{
eventTriggered-= value;
eventTriggered+= value;
//Add code here to keep track somewhere of event
}
remove
{
eventTriggered-= value;
//Add code here to keep track somewhere of event
}
}
But my dream tool would be one that is external to my application and hooks up to a process to monitor its events. Am I just dreaming or is this possible in any way?
I am dynamically instantiating a Form. I cannot interact with the components (such as a TextBox) on the Form until the handle has been created (else, an exception will be thrown).
Currently I block the thread using a while loop:
public void OutputDesktopFrame(MessagingService service, DesktopFrame desktopFrame)
{
IRemoteDesktopView view = GetView(service);
view.UpdateFrame(desktopFrame);
}
private IRemoteDesktopView GetView(MessagingService service)
{
T view;
bool viewExists = _views.TryGetValue(service, out view);
if (viewExists == false)
{
view = CreateAndShowView(service);
}
return view;
}
private T CreateAndShowView(MessagingService service)
{
T remoteDesktopView = new T();
_views.Add(service, remoteDesktopView);
Thread pumpThread = new Thread(() => remoteDesktopView.ShowDialog());
pumpThread.Start();
while (remoteDesktopView.IsHandleCreated == false)
{
//Do not return until the handle has been created!
}
return remoteDesktopView;
}
I do not like this mechanism. I am looking for an elegant solution.
Please take into account that I am coding against an interface. I thought about using a ManualResetEvent or something of the like but having to implement and handle the ManualResetEvent within each Form that implements the interface doesn't sound appealing to me. If you don't agree with me. that's just fine. I merely suspect my current solutions are not the most elegant.
You can add code to a HandleCreated event handler like this:
private void Form1_HandleCreated(object sender, EventArgs e){
//your code
}
The event is not listed in Properties window, you have to register the event handler using code:
HandleCreated += Form1_HandleCreated;
You have to wait for the handle to be created somehow.
So you will end up with something like while (form.IsHandleCreated == false) { ... } somewhere in your code.
The only question is where to put it.
If you do it like in your example above, you need to code the while loop every time you create a form If you choose the alternative you mentioned, using an event raised by the form, you need to implement it in each form (and create an event handler and hook it up).
I don't know if CreateAndShowForm() is a framework method, or something you can change yourself. If you can change it, that's where I would put the waiting. That way you only need to code it once.
Another approach to avoid the code duplication would be handling it in the form, implementing it in your own abstract form base class, and deriving you actual forms from that class. In my opinion, that is complete overkill for this issue - way too much work for very little gain.
If you can't change CreateAndShowForm(), I recommend going with the example above - yes, it definitely isn't elegant, but it gets the work done, the source code is easy to understand, and it doesn't require the additional work of event handling.
I have a static class which publishes a few events. So I have many different small classes that have different lifetimes that subscribe to this event.
I found out now that this leads to memory "leaks" because of the subscribing classes staying alive when they subscribed a longer-living event. I know that this is happening by using a memoryprofiler and I read about this problem.
I am not able to manually unsubscribe, as I might have hundreds of "clients" in a list. This list will just get cleared. So I can't (and don't want to) unsubscribe by hand.
I read that the "weak event pattern" might help here. Could someone please lead me to an "easy" way to implement this? All I found until now is either too simple to use in practice or too complicated to understand it in the beginning.
Or is there any "best practice" for this case?
Thanks in advance!
UPDATE:
Based on jbl's answer I found this (http://blogs.msdn.com/b/greg_schechter/archive/2004/05/27/143605.aspx) as a possible solution. Any comments here? It's rather old (2004), so there might be better solutions out there?
Never implemented something like that, but I would try (with a static class or a singleton, your choice) :
having the static class maintain a static collection of WeakReference to the client event handlers
the clients do not subscribe directly to the event. The static class exposes subscribe and unsubscribe methods which add/remove the handlers from the weak references collection
the static class is the only one subscribing directly to the event
upon event triggering, the static class enumerates the weak references collection and runs the handlers for the references which are still alive (removing the null ones)
Hope this will help
Best practice: always implement the Dispose pattern when a class subscribes to an event generated by an object not constructed by this class.
Then in the Dispose method remove the handler.
public NotificationServiceAccessor(ObjectWithEvent objectWithEvent)
{
_notificationService = new NotificationService();
_notificationService.StatusChanged += NotificationService_StatusChanged; // Local object, no Dipose
_objectWithEvent = objectWithEvent;
_objectWithEvent.AnEvent += AnEventHandler(); // Event that has to be disposed.
}
#region IDisposable Members
protected bool Disposed { get; private set; }
private void Dispose(bool disposing)
{
if (!this.Disposed)
{
this.InternalDispose(disposing);
}
this.Disposed = true;
}
protected virtual void InternalDispose(bool disposing)
{
if (disposing)
{
// Dispose here the event handlers
_objectWithEvent.AnEvent -= AnEventHandler()
}
// Dispose here only unmanaged objects
// Don’t use managed objects here because maybe
// they have been finalized already
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
~NotificationServiceAccessor()
{
this.Dispose(false);
}
#endregion
There is a private void btnContBalloon_Click(object sender, EventArgs e). Can I make this static because I want to invoke this from static method but I can not.
Making events static is a great way to shoot the foot. A static event has an unlimited life-time. Which makes any event handlers you register for the event live forever too. Which makes any form that contains such an event handler live forever too. A leak.
Registering an event handler for a static event requires code in, say, the FormClosing event handler that explicitly unregisters the handler. You can see this explicitly documented in the MSDN Library article for the SystemEvents class, one of the few examples of a class in the .NET framework that has static events.
The better approach is to keep track of the form instance whose button's Click event should be activated. Something like this:
public partial class Form1 : Form {
public static Form1 MainForm { get; private set; }
public Form1() {
InitializeComponent();
MainForm = this;
}
public void RunClickMethod() {
button1.PerformClick();
}
protected override void OnFormClosing(FormClosingEventArgs e) {
MainForm = null;
base.OnFormClosing(e);
}
}
Which allows client code to do this:
Form1.MainForm.RunClickMethod();
Yes, if that method doesn't need the instance members of the enclosing class you can make it static. Nothing prevents an event handler from being static, if that is the real question.
Bottom line: If that method only uses the sender object (probably the button) and the event args or other static members, then this is perfectly valid and possible.
In general: Yes, eventhandlers can be made static. But the normal rules for static methods apply.
But often the autogenerated code gets into trouble when you change a autogenerated eventhandler to static. I'd do that with manual added eventhandlers, only.