Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

OnDetaching function of behavior is not called

I have WPF behavior on specific control. When I close the window that hold the control the OnDetaching function is not called.

The behavior continues to exist (because of the events to which it's registered), although the window does not exist anymore (memory leak).

Why does the OnDetaching function not fire, and how can I solve it?

protected override void OnAttached()
{
     base.OnAttached();

     this.AssociatedObject.MouseLeftButtonDown += AssociatedObject_PlotAreaMouseLeftButtonDown;
     this.AssociatedObject.MouseLeftButtonUp += AssociatedObject_PlotAreaMouseLeftButtonUp;
     this.AssociatedObject.MouseMove += AssociatedObject_PlotAreaMouseMove;
}

protected override void OnDetaching()
{
     base.OnDetaching();

     this.AssociatedObject.MouseLeftButtonDown -= AssociatedObject_PlotAreaMouseLeftButtonDown;
     this.AssociatedObject.MouseLeftButtonUp -= AssociatedObject_PlotAreaMouseLeftButtonUp;
     this.AssociatedObject.MouseMove -= AssociatedObject_PlotAreaMouseMove;
}
like image 207
Hodaya Shalom Avatar asked Jun 04 '15 08:06

Hodaya Shalom


2 Answers

The OnAttached is called when XAML parser parses XAML and creates an instance of a behaviour that adds to the BehaviorCollection of the target control which is exposed as DependencyAttached property.

However when if the view is disposed, the collection (Behavior collection) was disposed of, it will never trigger OnDetaching method.

If the behaviour is not properly cleanup it will not be collected by GC and will also hold BehaviorCollection and other behaviors in that collection. The behaviours are designed to extend AssociatedObject, as long as you are subscribing to AssociatedObject events its fine as the AssociatedObject (publisher) will die and your behaviour will be collected by garbage collector.

A good source.


An alternative is to handle the "Closing" event (when a user clicks the upper right 'X' button) of the window, and OnDetaching there.

 <i:Interaction.Triggers>
        <i:EventTrigger EventName="Closing">
            <cmd:EventToCommand Command="{Binding CloseCommand}" />
        </i:EventTrigger>
 </i:Interaction.Triggers>

Then associate the handler in the View constructor:

MyWindow() 
{
    // Set up ViewModel, assign to DataContext etc.
    Closing += viewModel.OnWindowClosing;
}

And add the handler to the ViewModel:

public void OnWindowClosing(object sender, CancelEventArgs e) 
{
   // Cancel, OnDetaching, etc
}
like image 115
Noam M Avatar answered Nov 17 '22 11:11

Noam M


Try to subscribe to AssociatedObject.Unloaded event and inside the eventHander unsubscribe to all the mouse events. Behaviors OnDetaching() func. not always invoked at "time".

like image 4
Omri Aviv Avatar answered Nov 17 '22 10:11

Omri Aviv