Fork me on GitHub
如何在ViewModel中正确地使用Timer(定时器)

内容摘要:

这是我在某个客户那边讲课的时候遇到一个小问题,在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");
                }
            }
        }
    }
}

 

 

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>
 
 
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();
        }
    }
}
posted on 2012-05-05 20:22  HackerVirus  阅读(495)  评论(0编辑  收藏  举报