由于不同的线程拥有该对象,因此调用线程无法访问此对象

6
namespace PizzaSoftware.UI
{
    /// <summary>
    /// Interaction logic for LoginForm.xaml
    /// </summary>
    public partial class LoginForm : Window
    {
        public LoginForm()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            Timer timer = new Timer(1000);
            timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
            timer.Enabled = true;
        }

        void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            lblCurrentTime.Content = DateTime.Now.ToShortTimeString();
        }
    }
}

基本上,我只是想在我的表单上有一个显示当前时间的标签。正如我在另一个SO问题中提到的那样,我正在使用一个定时器。

我收到了标题中的错误。我该怎么办才能解决这个问题?

2个回答

26

最简单的方法是使用DispatcherTimer - 它会在调度程序线程中触发其Tick事件:

DispatcherTimer timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromMilliseconds(1000);
timer.IsEnabled = true;
timer.Tick += timer_Elapsed;

或者,您可以使用 Dispatcher.Invoke / BeginInvoke 在调度程序线程中执行委托...但这会更加复杂。如果您需要在每个计时器滴答声上进行重要工作,然后仅使用结果更新UI,则这将是更好的方法-但由于您在这里几乎没有做任何工作,所以只需在UI线程中完成所有操作即可。


谢谢Jon,阅读了MSDN上的摘要后,似乎DispatcherTimer默认在UI线程上运行,是吗? - delete

2

没意识到这是一个WPF应用程序。您需要获取Dispatcher,可以在构造函数中实现:

    private Dispatcher _dispathcer;

    public LoginForm()
    {
        InitializeComponent();
        _dispathcer = Dispathcer.CurrentDispather;
    }



    void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        _dispathcer.Invoke(new Action( ()=> { lblCurrentTime.Content = DateTime.Now.ToShortTimeString();});
    }

你可以在 timer_Elapsed 方法中直接访问 Dispatcher 属性,无需在构造函数中设置它。如果你使用 DispatcherTimer,那么根本不需要这么麻烦 :) - Jon Skeet
@Jon:那么你不是在访问后台线程的Dispatcher吗?我的理解是timer_Elapsed会在后台线程上调用,因此Dispatcher.CurrentDispatcher将是来自后台线程的Dispatcher。 - BFree
不,你将访问窗口的调度程序。我并不建议使用Dispatcher.CurrentDispatcher——我建议使用Window从DispatcherObject继承的Dispatcher属性。 - Jon Skeet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接