Home > Net >  How to stop a dispatchtimer in the viewmodel when the view is closed?
How to stop a dispatchtimer in the viewmodel when the view is closed?

Time:12-18

I want to close the timer inside of my ViewModel when the view is closed.

My code:

MainWindow.xaml.cs:

 public MainWindow()
        {
            InitializeComponent();
            this.DataContext = new UnitViewModel();
            Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory);
        }

UnitViewModel.cs

class UnitViewModel : ObservableObject
    {
        DispatcherTimer dispatcherTimer = new DispatcherTimer();
  public UnitViewModel()
        {
          StartTimer();
        }

        private void StartTimer()
        {
            dispatcherTimer.Tick  = new EventHandler(dispatcherTimer_Tick);
            dispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, 600);
            dispatcherTimer.Start();
        }

        private void dispatcherTimer_Tick(object sender, EventArgs e)
        {
            UpdateUnit();
        }
}

Is there a way to stop this timer when the MainWindow is closed? Or is not opened anymore. I prefer to have this code in my viewModel, is there a good way to solve this pronblem within MVVM ?

CodePudding user response:

Add a public API of some kind to the view model that stops the timer:

public void Stop() => dispatcherTimer.Stop();

Call this method from the view one way or another.

You could for example handle an event or override a method in the code-behind:

protected override void OnClosing(CancelEventArgs e)
{
    base.OnClosing(e);
    (DataContext as UnitViewModel)?.Stop();
}

...or use an EventTrigger in the XAML markup that invokes a command:

<i:Interaction.Triggers>
    <i:EventTrigger EventName="Closing" >
        <i:InvokeCommandAction Command="{Binding StopCommand}" />
    </i:EventTrigger>
</i:Interaction.Triggers>

Both approaches comply with the MVVM design pattern.

CodePudding user response:

Simply pass your window to ViewModel and bind Closing event to OnClosing method:

public class UnitViewModel
{
    public UnitViewModel(Window w)
    {
        mainWindow = w;
        mainWindow.Closing  = OnMainWindowClosing;
    }

    private Window mainWindow;

    private void OnMainWindowClosing(object sender, EventArgs e)
    {
        dispatcherTimer.Stop();
        //anything else you want
    }
}
public MainWindow()
{
    InitializeComponent();
    this.DataContext = new UnitViewModel(MainWindow);
    Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory);
}

CodePudding user response:

Personally, I wouldn't use a dispatcher timer in a viewmodel at all. I'd probably use async and a loop instead. The 600 ms delay would be introduced by

await Task.Delay(600);

And that would go in a while loop of whatever best suits.

I'd also work viewmodel first in a single window app so the view would be templated from that viewmodel. Dispose the viewmodel and the view goes away.

If it absolutely must be a separate window with the viewmodel then make the viewmodel a private member of that view. Close the window and the viewmodel is disposed. Decouple the viewmodel from any model using weak reference/event if necessary. Often my model is a web api though.

  • Related