如何在ViewModel中正确地使用Timer(定时器)
如何在ViewModel中正确地使用Timer(定时器)<div id="cnblogs_post_body">内容摘要:
这是我在某个客户那边讲课的时候遇到一个小问题,在ViewModel中创建的一个Timer,并不会被自动停止,即便使用该ViewModel的View已经被关闭了。这个问题的原因在于Timer的特殊工作机制,它是运行在一个独立的工作线程的,除非明确地停止他,或者整个程序关闭了,它才会停止。这一讲中,我通过实例重现了这个问题,然后提供了一个可行的解决方法。
视频地址:
http://www.tudou.com/programs/view/uO4b2j0N4L8/
示例代码:
备注:该范例使用了MvvmLight作为MVVM框架,请自行安装
Model:
using System;using System.Diagnostics;using System.Linq;namespace SilverlightApplicationSample{ public class DataService { public static Customer[] GetCustomers() { Debug.WriteLine(string.Format("[{0}]正在调用数据服务",DateTime.Now)); var rnd = new Random(); return Enumerable.Range(1, rnd.Next(100)).Select(x => new Customer() { CompanyName = "Company " + x.ToString() }).ToArray(); } } public class Customer { public string CompanyName { get; set; } }} ViewModel:using System;using System.Windows.Threading;using GalaSoft.MvvmLight;namespace SilverlightApplicationSample{ /// <summary> /// 使用MVVMLight实现的MVVM ViewModel /// </summary> public class CustomerWindowViewModel : ViewModelBase { /// <summary> /// 这个方法也不会自动调用 /// </summary> public override void Cleanup() { base.Cleanup(); timer.Stop(); } DispatcherTimer timer = null; public CustomerWindowViewModel() { //正常情况下的绑定 //Customers = DataService.GetCustomers(); //使用定时器调用服务 timer = new DispatcherTimer(); timer.Interval = TimeSpan.FromSeconds(1); timer.Tick += (o, a) => { Customers = DataService.GetCustomers(); }; timer.Start(); } private Customer[] _Customers; public Customer[] Customers { get { return _Customers; } set { if (_Customers != value) { _Customers = value; RaisePropertyChanged("Customers"); } } } }}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
View:
<controls:ChildWindow x:Class="SilverlightApplicationSample.CustomerWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls" Width="400" Height="300" Title="CustomerWindow" xmlns:local="clr-namespace:SilverlightApplicationSample"> <controls:ChildWindow.DataContext> <local:CustomerWindowViewModel></local:CustomerWindowViewModel> </controls:ChildWindow.DataContext> <Grid x:Name="LayoutRoot" Margin="2"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ListBox ItemsSource="{Binding Customers}" DisplayMemberPath="CompanyName"> </ListBox> <Button x:Name="CancelButton" Content="Cancel" Click="CancelButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,0,0" Grid.Row="1" /> <Button x:Name="OKButton" Content="OK" Click="OKButton_Click" Width="75" Height="23" HorizontalAlignment="Right" Margin="0,12,79,0" Grid.Row="1" /> </Grid></controls:ChildWindow>.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }Page:using System.Windows;using System.Windows.Controls;namespace SilverlightApplicationSample{ public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); } private void Button_Click(object sender, RoutedEventArgs e) { var window = new CustomerWindow(); window.Closed += (o, a) => { var vm = window.DataContext as CustomerWindowViewModel; vm.Cleanup(); }; window.Show(); } }}.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }.csharpcode, .csharpcode pre{font-size: small;color: black;font-family: consolas, "Courier New", courier, monospace;background-color: #ffffff;/*white-space: pre;*/}.csharpcode pre { margin: 0em; }.csharpcode .rem { color: #008000; }.csharpcode .kwrd { color: #0000ff; }.csharpcode .str { color: #006080; }.csharpcode .op { color: #0000c0; }.csharpcode .preproc { color: #cc6633; }.csharpcode .asp { background-color: #ffff00; }.csharpcode .html { color: #800000; }.csharpcode .attr { color: #ff0000; }.csharpcode .alt {background-color: #f4f4f4;width: 100%;margin: 0em;}.csharpcode .lnum { color: #606060; }
页:
[1]