在处理大量数据时,INotifyPropertyChanged陷入困境

Wob*_*les 1 c# wpf inotifypropertychanged

我有一个HID设备,我在200hz-600hz左右与之通信,并将数据解释为代表HID设备属性的类对象.该类在其属性上实现了INotifyPropertyChanged,并且由于通信速度,我认为处理队列陷入困境,因为控件似乎变得滞后并且在几分钟后变得"框架".

是否有.net中的方法可能有助于此类事件,可能是事件处理程序池或某种类型的队列?

不幸的是,如果没有我的HID设备,我不确定我的代码是否对任何人都有用,但是生病包括一些相关的代码段只是为了显示我的实现:

public enum DataEvents { onNone = 0, onStatus = 1, onInput = 2, onOutput = 4, onReport = 8};
public class Controller: INotifyPropertyChanged, IDisposable, INotifyDisposed
{
    public event PropertyChangedEventHandler PropertyChanged;
    public event EventHandler Disposing;
    public event EventHandler Disposed;
    public event EventHandler ReportReceived;

    internal void callPropertyChanged(string PropertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
    }

    internal void callReportReceived()
    {
        ReportReceived?.Invoke(this, EventArgs.Empty);
    }

    public bool Touch1
    {
        get { return _Touch1; }
        private set { if (value != _Touch1) { _Touch1 = value; if (RaiseUpdateEvents.HasFlag(DataEvents.onInput)) callPropertyChanged("Touch1"); } }
    }
    private bool _Touch1 = false;

    //There are many more properties but all of them follow this pattern, and have several different types
}
Run Code Online (Sandbox Code Playgroud)

我的对象是从System.Threading.Thread循环中填充,轮询HID设备以获取报告.HID设备读取方法是阻塞调用,因此循环不是死循环,并且仅限于设备的数据速率,如通常所述200hz- 600Hz的.

编辑:值得注意的是,我对WPF绑定特别感兴趣.

Ber*_*sch 8

在处理WPF中的近实时系统时(我花了6年的时间研究它们),你有几个选择.首先,我会列出一些值得思考的食物:

  • 要通过一个事件使所有WPF绑定更新string.Empty,请使用您的属性名称.
  • 您的问题可能不完全是由于事件造成的.WPF有很多影响内存管理的问题.

所以你要问的问题是用户需要经常看到任何类型的变化?人类视觉持久性是1/10秒,或100ms.任何比这更频繁的更新都会被浪费,但更多时候,即使这种情况太频繁.

每秒一个事件?

在我的场景中,我们确定我们只需要每秒更新屏幕上的所有内容.即使我们每秒收到12次数据(每个样本83毫秒),我们收集并平均数据以使其平滑.它为我们的用户提供了更好的了解.

  • 我们构建了我们的视图模型,Update()使用主计时器每秒调用一次方法.
  • 实现的模型是INotifyPropertyChanged为了避免绑定内存泄漏,但只引发了一个属性更改事件,string.Empty导致UI刷新

最小化对象创建

在垃圾收集中花费的每毫秒是用户无法与您的应用程序交互的明显时间.每次举起活动时,都必须创建要发送的活动对象.虽然从技术上讲,您可以创建一次事件对象并引发相同的实例,但WPF会为您创建对象实例.这些是你需要关注的事情:

  • DataTemplate实质上为您想要模板的每个对象创建一个新模板.尽可能尝试使用虚拟化,并尽量减少使用虚拟化.
  • ResourceDictionary每次在控件中声明资源字典时,都要创建新实例.拥有所有合并的资源字典App.xaml比在不同的用户控件中包含相同的字典更好.特别是如果你有一个用户控件DataTemplate
  • ContentPresenter 不是你的朋友.

为了进一步解释,ContentPresenter将获取您的对象,在控件ResourceDictionary中查找它的类型以找到DataTemplate实例化您的数据.当您需要将窗口的特定部分换成另一个控件时,这可能很方便,但是它确实需要付出很大的代价.尽可能减少它的使用.

在后台保持硬件/通信

我们专门设置线程来处理通信和处理需求.这使得UI可以保持响应,同时我们可以对数据进行一些DSP /统计减少.

使用Memory Profiler

每当您需要在显示器上进行近实时更新时,您必须特别注意内存使用.这是我们不得不面对的头号问题.

  • 您的应用程序开始正常,但一两分钟后它开始降级
  • 确保您没有持有您不期望的对象实例
  • 查找垃圾收集事件中存在的对象