当前位置:  开发笔记 > 编程语言 > 正文

为什么从计时器引发PropertyChanged事件会导致COMException?

如何解决《为什么从计时器引发PropertyChanged事件会导致COMException?》经验,为你挑选了1个好方法。

我正在使用在Raspberry Pi下运行的XAML开发通用Windows平台应用程序Windows 10 IoT Core.该应用程序驱动I2C总线上的温度传感器.传感器类是MLX90614Thermometer.传感器使用a DispatcherTimer每100毫秒(大约)获取读数并更新移动平均值.当移动平均值变化超过指定阈值时,传感器会引发ValueChanged事件并在事件args中提供新值.

在我的ViewModel类中TemperatureSensorViewModel,我订阅了传感器的ValueChanged事件并使用它来更新命名的绑定属性Ambient,Channel1Channel2.这些属性绑定到XAML UI中的文本块.这是事件处理程序:

    void HandleSensorValueChanged(object sender, SensorValueChangedEventArgs e)
    {
        switch (e.Channel)
        {
            case 0:
                Ambient = e.Value;
                break;
            case 1:
                Channel1 = e.Value;
                break;
            case 2:
                Channel2 = e.Value;
                break;
        }
    }

...这里是一个示例数据绑定Ambient...

    

我正在使用MVVM Light Toolkit,因此我的属性就像这样实现(仅Ambient显示,但除了名称之外其他都是相同的):

    public double Ambient
    {
        get { return ambientTemperature; }
        private set { Set(nameof(Ambient), ref ambientTemperature, value); }
    }

MVVM Light Toolkit提供了该Set()方法,该方法自动引发PropertyChanged所设置属性的通知.

如果我从传感器读取单个样品以响应按下按钮,则此操作正常.一旦我启用了自动采样模式(基于计时器),它就会开始投掷COMExceptions.所以这必定是与计时器有关的某种线程问题.

现在,如果我理解正确,运行时应该PropertyChanged自动将通知编组到UI线程上; 从堆栈跟踪看起来似乎就是这种情况.但是,我最终得到了一个COMException.啊.

System.Runtime.InteropServices.COMException (0x8001010E): The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
   at System.Runtime.InteropServices.WindowsRuntime.PropertyChangedEventArgsMarshaler.ConvertToNative(PropertyChangedEventArgs managedArgs)
   at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
   at GalaSoft.MvvmLight.ObservableObject.RaisePropertyChanged(String propertyName)
   at GalaSoft.MvvmLight.ViewModelBase.RaisePropertyChanged[T](String propertyName, T oldValue, T newValue, Boolean broadcast)
   at GalaSoft.MvvmLight.ViewModelBase.Set[T](String propertyName, T& field, T newValue, Boolean broadcast)
   at TA.UWP.Devices.Samples.ViewModel.TemperatureSensorViewModel.set_Channel1(Double value)
   at TA.UWP.Devices.Samples.ViewModel.TemperatureSensorViewModel.HandleSensorValueChanged(Object sender, SensorValueChangedEventArgs e)
   at TA.UWP.Devices.MLX90614Thermometer.RaiseValueChanged(UInt32 channel, Double value)
   at TA.UWP.Devices.MLX90614Thermometer.SampleAllChannels()
   at TA.UWP.Devices.MLX90614Thermometer.b__37_0()
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at TA.UWP.Devices.MLX90614Thermometer.d__37.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at TA.UWP.Devices.MLX90614Thermometer.d__38.MoveNext()

WAT?我不明白这里发生了什么.任何人都可以看到问题可能是什么?



1> Tim Long..:

经过进一步的研究,我想我可以回答我自己的问题......

似乎我对自动编组到UI线程的PropertyChanged事件做了一个无效的假设.我在一些关于WPF的文章中读过这篇文章,但正如@Clemens在评论中指出的那样,这不是我们所说的WPF,它是通用Windows平台,它是Windows运行时(WinRT)的衍生物.

密钥学习:UWP中的XAML≠WPF.在考虑通用Windows应用程序时,您不能依赖WPF文档.

然后我发现这个问题与我有相似之处,特别是海报错误地假设他正在处理WPF.接受的答案让我想到了关于MVVM Light Toolkit DispatcherHelper类的另一个问题,它可以用来将任何代码编组到调度程序线程上.

所以,似乎我必须自己进行线程编组(我真的很讨厌Windows编程的这个方面,我希望微软能够制作一个线程安全的UI技术!).

所以我更新了我的属性以使用这种模式:

    public double Ambient
    {
        get { return ambientTemperature; }
        private set
        {
            ambientTemperature = value;
            DispatcherHelper.CheckBeginInvokeOnUI(() => RaisePropertyChanged());
        }
    }

现在似乎按预期工作.

我想很多人都会陷入这个泥潭,所以我在这里留下这个答案,希望人们在需要时能找到它.

推荐阅读
k78283381
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有