WPF MVVM 更新集合以便 UI 更新

发布于 2024-10-02 17:38:29 字数 2589 浏览 6 评论 0原文

我想更新我的用户界面。我应该使用BackgroundWorker吗?我是否将BackgroundWorker 放入MainWindowViewModel 中并再次实例化存储库,或者将其放入OrdersQueueViewModel 中并对属性执行某些操作?

UI 仅显示 LINQ 创建的列表的内容。这些列表是 ObservableCollection,并且是 OrdersQueueViewModel 的属性。我有一个 ViewModel MainWindowViewModel,它创建一个 ViewModels 集合,以便我可以从 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。对这一切都很陌生,试图弄清楚它,提前感谢您的帮助。

编辑:使用詹姆斯的建议,我最终在我的 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);

I want to update my UI. Should I use BackgroundWorker? Do I put the BackgroundWorker in the MainWindowViewModel and instantiate the repositories again, or do I put it in the OrdersQueueViewModel and do something with the properties?

The UI just displays the contents of lists created by LINQ. The lists are ObservableCollection and are properties of the OrdersQueueViewModel. I have a ViewModel MainWindowViewModel that creates a collection ViewModels, so that I can bind to that collection from the MainWindow.xaml (view).

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>

Example of a property in the OrderQueueViewModel that uses a repository:

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

So I haveLinesToPick bound in the OrdersQueueView, and as the database updates the lists should change in the UI. I'v spent some time reading about BackgroundWorker, but I'm not quite sure what to do to update the lists. I'm hoping because they are ObservableCollections I can just "refresh" them and they will use INotifyPropertyChanged and update the UI automatically. Very new to all this, trying to get my head around it, thanks in advance for any help.

EDIT: Using James's suggestion I have ended up with this In my OrdersQueueViewModel. However I am getting the error "This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread", when the code gets to .Clear() on the 2 lists, which is what I thought the dispatcher was used for. Any suggestions?

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);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

白芷 2024-10-09 17:38:29

您可以通过任一方式执行此操作 - 在 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 将不会更新,直到您通知它包含该集合的属性已更改。保留相同的集合要容易得多。

You can do it either way - in the MainWindowViewModel or one of the child view models. I would choose based on which way produces lower coupling and higher cohesion between components. (Lower coupling - fewer dependencies. Higher cohesion - things go together that belong logically together.)

And BackgroundWorker is a reasonable technique. Just remember to dispatch to the UI thread to update the collection. As for your ObservableCollection code... That needs some work. Don't reinstantiate the ObservableCollection. Do something like this:

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);
    }
}

By keeping the same ObservableCollection that was databound, your UI will automatically pick up changes to the collection. If you replace the collection, you lose the binding to it and your UI won't update until you notify it that the property containing the collection changed. Much easier to just keep the same collection.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文