Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unsubscribe event using dispose in MVVM

Tags:

c#

mvvm

wpf

Actually I m trying to close my window by firing the event from my ViewModel. Everything works fine and awesome, but I know that I must unsbscribe my event to avoid memory leaks. thus I implement the IDisposable interface and I unsbscribe the event inside the Dispose method.

Below is my code :

public partial class MainWindow : Window, IDisposable
{
    private MainViewModel viewModel;
    public MainWindow()
    {
        InitializeComponent();
        DataContext = viewModel =  new MainViewModel();
        this.viewModel.RequestClose += CloseWindow;
    }

    void CloseWindow(object sender, EventArgs e)
    {
        this.Close();
    }

    public void Dispose()
    {
        ////here we need to unsubscribe the event
        this.viewModel.RequestClose -= this.CloseWindow;
    }
}

What I need to know :

  1. Is that code correct
  2. When the GC will be called and excute the dispose method
  3. Is there a better way to do such a thing
like image 762
Moez Rebai Avatar asked Jan 25 '26 10:01

Moez Rebai


1 Answers

but I know that I must unsbscribe my event to avoid memory leaks

Memory leak occurs, when short-lived object subscribes an event of long-lived objects (or static event), and does not unsubscribe later (e.g., see this answer). I suppose, that this is not your case.

When the GC will be called and excute the dispose method

GC doesn't call IDisposable.Dispose (e.g., see this answer). At all. If you haven't any code, that calls MainWindow.Dispose explicitly, it will be called never.

Is there a better way to do such a thing

I'd avoid IDisposable and events. Attached behavior here is more convenient, IMO (at least, this is reusable):

public static class WindowClosingBehavior
{
        public static bool GetIsClosingInitiated(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsClosingInitiatedProperty);
        }

        public static void SetIsClosingInitiated(DependencyObject obj, bool value)
        {
            obj.SetValue(IsClosingInitiatedProperty, value);
        }

        public static readonly DependencyProperty IsClosingInitiatedProperty = DependencyProperty.RegisterAttached(
            "IsClosingInitiated", 
            typeof(bool), 
            typeof(WindowClosingBehavior),
            new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsClosingInitiatedChanged));

        private static void IsClosingInitiatedChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
        {
            var window = target as Window;
            if (window != null && (bool)e.NewValue)
            {
                window.Close();
            }
        }
}

Somewhere in window's XAML:

behaviors:WindowClosingBehavior.IsClosingInitiated="{Binding IsClosingInitiated}"

where IsClosingInitiated is a property from view model:

public class SomeViewModel
{
     // ...

     private void Foo()
     {
         // ...
         IsClosingInitiated = true;
     }
}
like image 188
Dennis Avatar answered Jan 27 '26 22:01

Dennis