gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 04:33:50 27 4
gpt4 key购买 nike

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

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

    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 的示例数据绑定(bind)...

    <TextBlock x:Name="Ambient"  Grid.Row="1" Text="{Binding Path=Ambient}" Style="{StaticResource FieldValueStyle}" />

我正在使用 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()

什么?我不明白这里发生了什么。谁能看出可能是什么问题?

最佳答案

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

看来我对自动编码到 UI 线程的 PropertyChanged 事件做了一个无效的假设。我在有关 WPF 的文章中的一些地方读到了这一点,但正如@Clemens 在评论中指出的那样,这不是我们正在谈论的 WPF,它是通用 Windows 平台,它是 Windows 运行时 (WinRT) 的衍生物。

  • 重点学习:UWP ≠ WPF 中的 XAML在考虑通用 Windows 应用时不能依赖 WPF 文档

然后我找到this question这与我有相似之处,特别是张贴者误以为他正在处理 WPF。接受的答案让我想到了另一个 question regarding the MVVM Light Toolkit's DispatcherHelper class ,它可用于将任何代码编码到调度程序线程。

所以,看来我必须自己做线程编码(我真的很讨厌Windows编程的这方面,我希望微软能做出线程安全的UI技术!)。

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

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

这似乎按预期工作。

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

关于xaml - 为什么从计时器引发 PropertyChanged 事件会导致 COMException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34443048/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com