当另一个线程中的事件更改属性时,视图不会更新

时间:2013-11-22 18:33:09

标签: c# wpf multithreading mvvm

我正在尝试运行类似后台线程的东西,并通过引发事件来通知ViewModel此后台线程的状态。 ViewModel反过来引发OnPropertyChanged事件。不幸的是,相应的视图不会更新。

我通知ViewModel的后台线程部分可以在这里看到:

private void RunThread() {
        while(true) {
            suspendEvent.WaitOne(Timeout.Infinite);
            if (shutDownEvent.WaitOne(0)) {
                break;
            }
            if (pauseEvent.WaitOne(0)) {
                pauseEvent.Reset();
            }
            Notify("Cleaning started!");
            pauseEvent.WaitOne(TimeSpan.FromSeconds(5));
            Clean();
            Notify("Cleaning finished!");
            pauseEvent.WaitOne(TimeSpan.FromSeconds(5));

        }
    }

private void Notify( String status ) {
        NotifyOfCleanerStatusHandler handler = NotifyOfcleanerStatus;
        if (handler != null) {
            handler(status);
        }
    }

我收到该事件的ViewModel部分可以在这里看到:

public void SetCleanerStatus( String status ) {
        CleanerStatus = status; 
    }

最后,我将我的视图绑定到的属性可以在这里看到:

public String CleanerStatus {
        get {
            return cleanerStatus;
        }
        set {
            if (value != null) {
                cleanerStatus = value;
                OnPropertyChanged("CleanerStatus");
            }
        }
    }

有趣的是:视图将显示上述状态之一,“清理开始!”或“清洁完毕!”。人们会认为它们应该以5秒的间隔交替。不是这种情况。

如果我删除第一个waithandle调用(pauseEvent.WaitOne(TimeSpan.FromSeconds(5));)视图中的消息是“Cleaning finished”并保持这种状态。如果我保留该行,则消息为“正在清理!”并保持这种方式。调试显示已到达OnPropertyChanged(..)行。

我做错了什么?

1 个答案:

答案 0 :(得分:0)

简化您的RunThread方法:

private ManualResetEvent suspendEvent = new ManualResetEvent(false);
private bool shutdown;

private void RunThread()
{
    while (!shutdown)
    {
        suspendEvent.WaitOne();

        if (shutdown)
        {
            break;
        }

        Notify("Cleaning started!");
        Thread.Sleep(TimeSpan.FromSeconds(5));
        Notify("Cleaning finished!");
        Thread.Sleep(TimeSpan.FromSeconds(5));
    }
}

更新UI时,可能还需要在UI线程中调用PropertyChanged处理程序:

public string CleanerStatus
{
    get { return cleanerStatus; }
    set
    {
        cleanerStatus = value;
        App.Current.Dispatcher.BeginInvoke(
            new Action(() => OnPropertyChanged("CleanerStatus")));
    }
}