【问题标题】:Update ViewModel property from task从任务更新 ViewModel 属性
【发布时间】:2017-02-08 14:48:02
【问题描述】:

我正在使用 WPF 和 Caliburn.Micro 构建一个应用程序。我想从任务/线程更新 ProgressBar,我想知道正确更新 UI 需要什么:

public class DemoViewModel : PropertyChangedBase
{
    private int m_Progress;

    public int Progress
    {
        get { return m_Progress; }
        set
        {
            if (value == m_Progress) return;
            m_Progress = value;

            NotifyOfPropertyChange();
            NotifyOfPropertyChange(nameof(CanStart));
        }
    }

    public bool CanStart => Progress == 0 || Progress == 100;

    public void Start()
    {
        Task.Factory.StartNew(example);
    }

    private void example()
    {
        for (int i = 0; i < 100; i++)
        {
            Progress = i + 1; // this triggers PropertChanged-Event and leads to the update of the UI
            Thread.Sleep(20);
        }
    }
}

从其他编程语言中,我知道我需要与 UI 线程同步以更新 UI,但我的代码可以正常工作。是否有什么我遗漏了并且可能导致零星错误的东西,或者是否有一些幕后的魔法可以处理同步?

【问题讨论】:

  • INPC 事件会自动编组到 UI 线程,因此您不必担心。但是...如果您每 20 毫秒更新一次 UI(Thread.Sleep(20)!!!!!!!),您将不会在 UI 中看到 jack,因为它会忙于实际更新。跨度>

标签: wpf mvvm caliburn.micro


【解决方案1】:

这取决于您如何实现 INotifyPropertyChanged。实现应该将所有 UI 更新委托给适当的调度程序。

示例实现:

public void RaisePropertyChanged([CallerMemberName]string name) {
        Application.Current.Dispatcher.Invoke(() => {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }, System.Windows.Threading.DispatcherPriority.Background);
    }

还要清理任务启动一下:

编辑: 移除了不必要的 bool 返回值,并设置 ConfigureAwait 在任务完成时远离 UI 线程。

public async void Start()
{
    await Task.Run(() => example()).ConfigureAwait(false);
}

private async Task example()
{
    for (int i = 0; i < 100; i++)
    {
        Progress = i + 1; // this triggers PropertChanged-Event and leads to the update of the UI
        await Task.Delay(20);
    }
}

【讨论】:

  • 谢谢。我检查了 Caliburn.Micro 的源代码,如果您从 PropertyChangedBase 派生 ViewModel,则同步由 Caliburn.Micro 完成。 CM 中有一个方便的 Execute 助手类,用于同步我也学到了。
  • 在这种情况下使用 await/async 有什么好处?方法 example() 没有返回值,但我猜 Task 需要一个返回值。
  • @Ragna 有几种方法可以解决这个问题。您可能只需返回一个任务即可。真的,我只是想解除阻塞Thread.Sleep。见编辑。
猜你喜欢
  • 2020-07-18
  • 1970-01-01
  • 2020-10-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
相关资源
最近更新 更多