如何在数据库更改时更新 WPF UI

use*_*520 2 c# wpf datagrid multithreading mvvm

我首先在 C#/WPF/Entity Framework DB 中编写一个应用程序,它与一个专有的工业硬件进行通信,该硬件测量来自冷却剂管线的流量和温度等值。这些值经常通过在后台运行的线程在我的 SQL Server 数据库中更新,然后显示在我的 UI 中。

我目前关心的是如何更新我的 UI 以反映这些变化。这是我如何更新数据网格的示例:

我将我的数据上下文设置为我的视图模型,并实例化一个每秒运行的线程:

    _DataContext = new ViewModels.SummaryTable_ViewModel();
    this.DataContext = _DataContext;
    UIUpdateThread = new Thread(UIUpdaterThread);
    UIUpdateThread.IsBackground = true;
    UIUpdateThread.Start();       
Run Code Online (Sandbox Code Playgroud)

我的网格所基于的模型是一个 IList<>,如下所示:

    private IList<channel> _channel;
    public IList<channel> Channels
    {
        get
        {
            return _channel;
        }
        set
        {
            _channel = value;
            //NotifyPropertyChanged();
            OnPropertyChanged("Channels");
        }
    }
Run Code Online (Sandbox Code Playgroud)

然后每秒我的 UIUpdateThread 调用我的 FillChannels() 方法,如下所示,然后网格根据 propertychanged 通知更新:

using (var DTE = new myEntities())
            {
                if (DTE.channels.Any())
                {
                    var q = (from a in DTE.channels
                             where a.setup.CurrentSetup == true
                             orderby a.ChannelNumber
                             select a).ToList();

                    this.Channels = q;
                }
            }
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:有没有更好、更优雅的方法来做到这一点?由于缺乏更好的术语,这感觉“错误”。它有不好的副作用,比如每次线程运行时重置我的数据网格上的用户设置排序。我也认为它打破了 MVVM 模式,尽管我不确定。

例如,我在想,如果与我的硬件对话的线程每次轮询硬件以获取数据时都会更新一个共享的 Channel 对象,并且我只是将我的 UI 绑定到它,这样我就不必运行这个线程(或我的其他 UI 上执行相同操作的其他线程),只需根据 PropertyChanged 通知进行更新。或者还有其他一些我完全不知道的方法吗?在寻找答案时,我看到提到了我不熟悉的工作单元模式,这是一个相关的概念吗?

正如您所看到的,我不太确定从哪里开始,并且真的可以使用一些帮助。对不起,文字墙,我只是想尽可能彻底。任何帮助将不胜感激。谢谢。

ror*_*.ap 6

我认为您的模型应该是在有新数据时通知您的视图模型的模型。您应该将完成此操作的任何机制(例如我假设您正在使用的计时器)放入模型中。

基本上,您的模型通知您的视图模型,您的视图模型通知视图有数据更改。如果您正确设置您的视图——并且使用 XAML 而不是代码隐藏,它应该通过视图和视图模型之间的数据绑定自动组合在一起。

关于排序:这应该是视图模型的一个单独属性,它绑定到视图网格上的排序属性。您的模型应该维护用户设置的排序,并在数据更改时通知视图模型之前将其适当地应用于更新的数据。

我不确定工作单​​元是否适用于此处,因为您不是在谈论将相关数据行持久保存到多个表并将其作为一个事务执行——您只是在读取数据。不过,我可能是错的,因为我还没有研究那么多工作单元。


要在评论中解决您的问题:

让我们退后一步。您的视图模型应该关心与关联视图的表示相关的逻辑。它不应该有任何数据访问代码或执行任何业务逻辑或域相关任务的代码;该代码包含在统称为“模型”的内容中(如果您已经拥有此代码,请原谅我,但很难准确说出您在问题中提供的代码所在的位置)。

该模型可以由多个类组成,这些类执行不同的业务逻辑任务或代表您的域/实体 POCO(例如您的实体框架生成的类)。

我有点不清楚您的Channel对象是什么以及它如何与您的实体类/POCO(即 EF 生成的模型)分开。但同样,您与 EF 的交互以及与您的实体相关的维护和逻辑应该发生在模型中。

所以是的,这个想法是您使用任何您想要的机制在模型中查找数据更改 - 例如计时器(顺便说一句,有同步运行的计时器,所以不要将“计时器”的概念与“线程”混为一谈") 或直接绑定到您的实体集合上的“集合更改”事件。当检测到更改时,您只需执行模型中该更改所需的任何业务逻辑(如应用转换、排序、日志记录等),然后通知视图模型已发生更改。