视图关闭时如何停止视图模型中的调度计时器?

Posted

技术标签:

【中文标题】视图关闭时如何停止视图模型中的调度计时器?【英文标题】:How to stop a dispatchtimer in the viewmodel when the view is closed? 【发布时间】:2022-01-20 09:34:18 【问题描述】:

当视图关闭时,我想关闭 ViewModel 中的计时器。

我的代码:

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();
        

有没有办法在 MainWindow 关闭时停止这个计时器?或者不再打开。我更喜欢在我的 viewModel 中有这段代码,有没有在 MVVM 中解决这个问题的好方法?

【问题讨论】:

视图模型应该公开一个停止计时器的 Shutdown 方法。应该从 MainWindow 中的 Closed 或 Closing 事件处理程序调用该方法。 【参考方案1】:

向停止计时器的视图模型添加某种公共 API:

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

从视图中以一种或另一种方式调用此方法。

例如,您可以在代码隐藏中处理事件或覆盖方法:

protected override void OnClosing(CancelEventArgs e)

    base.OnClosing(e);
    (DataContext as UnitViewModel)?.Stop();

...或在调用命令的 XAML 标记中使用 EventTrigger

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

这两种方法都符合 MVVM 设计模式。

【讨论】:

【参考方案2】:

就个人而言,我根本不会在视图模型中使用调度程序计时器。 我可能会改用异步和循环。 600 毫秒的延迟将由

引入
await Task.Delay(600);

这将进入一个最适合的while循环。

我也会首先在单个窗口应用程序中使用视图模型,以便从该视图模型中对视图进行模板化。处理视图模型,视图消失。

如果它绝对必须是与视图模型的单独窗口,则使视图模型成为该视图的私有成员。关闭窗口并处理视图模型。如有必要,使用弱引用/事件将视图模型与任何模型分离。 不过,我的模型通常是 Web api。

【讨论】:

【参考方案3】:

只需将您的窗口传递给 ViewModel 并将 Closing 事件绑定到 OnClosing 方法:

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);

【讨论】:

"将你的窗口传递给 ViewModel" 不是 MVVM。视图模型不知道视图,当然也不知道视图的任何特定事件,例如关闭。

以上是关于视图关闭时如何停止视图模型中的调度计时器?的主要内容,如果未能解决你的问题,请参考以下文章

如何从 mvvm 中的视图模型关闭视图?

如何使用 MVC 模型动态过滤 javafx 中的列表视图控件,同时以多种方式更新? [关闭]

solidworks工程图如何更换视图中的模型文件

如何在 Xamarin 表单中的视图模型之间最好地传递信息 - Prism [关闭]

视图模型应该对视图控制器中的事件做出反应吗?

如何在推送前关闭模型视图控制器?