陈希章@中国 发表于 2013-1-3 15:37:31

如何在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]
查看完整版本: 如何在ViewModel中正确地使用Timer(定时器)