【问题标题】:WPF MVVM update collections so that UI updatesWPF MVVM 更新集合以便 UI 更新
【发布时间】:2010-11-15 15:59:12
【问题描述】:

我想更新我的用户界面。我应该使用 BackgroundWorker 吗?我是将 BackgroundWorker 放在 MainWindowViewModel 中并再次实例化存储库,还是将它放在 OrdersQueueViewModel 中并对属性做一些事情?

UI 只显示由 LINQ 创建的列表的内容。这些列表是 ObservableCollection 并且是 OrdersQueueViewModel 的属性。我有一个创建集合 ViewModels 的 ViewModel MainWindowViewModel,以便我可以从 MainWindow.xaml(视图)绑定到该集合。

MainWindowViewModel.cs:

public MainWindowViewModel()
{
    _printQueueRepos = new OrdersPrintQueueRepository();
    _holdQueueRepos = new OrdersHoldQueueRepository();            
    _linesToPickRepos = new LinesToPickRepository();
    _linesPerHourRepos = new LinesPerHourRepository();

    //create an instance of viewmodel and add it to the collection            
    OrdersQueueViewModel viewModel = new OrdersQueueViewModel(_printQueueRepos, _holdQueueRepos, _linesToPickRepos, _linesPerHourRepos);
    this.ViewModels.Add(viewModel);              
}

MainWindow.xaml:

<Window.Resources>
    <DataTemplate DataType="{x:Type vm:OrdersQueueViewModel}">
        <vw:OrdersQueueView></vw:OrdersQueueView>
    </DataTemplate>
</Window.Resources>

OrderQueueViewModel 中使用存储库的属性示例:

public ObservableCollection<LinesToPick> LinesToPick
{
    get
    {
        return new ObservableCollection<LinesToPick>(_linesToPickRepos.GetLinesToPick());
    }
}

所以我在 OrdersQueueView 中绑定了LinesToPick,并且随着数据库的更新,UI 中的列表应该会发生变化。我花了一些时间阅读有关 BackgroundWorker 的信息,但我不太确定如何更新列表。我希望因为它们是ObservableCollections 我可以“刷新”它们,它们将使用 INotifyPropertyChanged 并自动更新 UI。对这一切都非常陌生,我试图理解它,在此先感谢您的帮助。

编辑:使用 James 的建议,我在我的 OrdersQueueViewModel 中得到了这个结果。但是,当代码到达 2 个列表上的 .Clear() 时,我收到错误“这种类型的 CollectionView 不支持从不同于 Dispatcher 线程的线程更改其 SourceCollection”,这是我认为调度程序的用途。有什么建议吗?

Action workAction = delegate
{
    _worker = new BackgroundWorker();
    _worker.DoWork += delegate
    {
        LinesThroughput.Clear();
        LinesToPick.Clear();

        //refresh LinesToPick
        foreach (var item in _linesToPickRepos.GetLinesToPick())
        {
            LinesToPick.Add(item);
        }

       //refresh LinesThroughput
       List<LinesThroughput> Lines = new List<LinesThroughput>    (_linesPerHourRepos.GetLinesThroughput());

       foreach (var item in GetLinesThroughput(Lines))
       {
           LinesThroughput.Add(item);
       }
   };
   _worker.RunWorkerAsync();
};
Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Normal, workAction);

【问题讨论】:

    标签: wpf mvvm backgroundworker observablecollection


    【解决方案1】:

    您可以采用任何一种方式 - 在 MainWindowViewModel 或其中一个子视图模型中。我会根据哪种方式在组件之间产生更低的耦合和更高的内聚来进行选择。 (更低的耦合 - 更少的依赖关系。更高的内聚 - 逻辑上属于一起的事物在一起。)

    BackgroundWorker 是一种合理的技术。只记得调度到 UI 线程来更新集合。至于您的 ObservableCollection 代码......这需要一些工作。不要重新实例化 ObservableCollection。做这样的事情:

    public ObservableCollection<LinesToPick> LinesToPick { get; private set; }  // Don't forget to nstantiate in ctor
    
    public void Refresh()
    {
        LinesToPick.Clear();
        foreach(var item in _linesToPickRepos.GetLinesToPick())
        {
            LinesToPick.Add(item);
        }
    }
    

    通过保持与数据绑定相同的 ObservableCollection,您的 UI 将自动获取对集合的更改。如果您替换该集合,您将失去与它的绑定,并且您的 UI 将不会更新,直到您通知它包含该集合的属性已更改。保持相同的集合更容易。

    【讨论】:

    • 我最初的问题已经得到解答,我并不想开始一个新的话题,希望你也能在这个新部分上为我指出正确的方向。
    • 您的调度程序代码由内而外。您想从 BackgroundWorker 内部调用调度程序,而不是相反。顺便说一句 - 我的 Refresh() 代码有点幼稚。您应该真正在后台线程上获取新项目列表并将其传递给 Refresh(newItems) 而不是从 Refresh 中调用 repo。
    猜你喜欢
    • 1970-01-01
    • 2021-12-20
    • 2014-11-23
    • 2012-10-20
    • 2016-12-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多