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.