从非 UI 线程访问 UI 元素时如何防止编组错误?

How to prevent marshalling errors when accessing UI elements from non-UI threads?

我有这个函数接收数字输出引脚地址 uscita 作为整数和状态高作为布尔值,并更新引脚输出并在 UI 上的类似 LED 的椭圆中填充红色.

    Private Function comandaUscita(ByVal uscita As Integer, ByVal high As Boolean) As Boolean

        If high Then
            Select Case uscita
                Case 1
                    If gpin1 IsNot Nothing Then gpin1.Write(GpioPinValue.High)
                    LED1.Fill = redBrush
                Case 2
                    If gpin1 IsNot Nothing Then gpin2.Write(GpioPinValue.High)
                    LED2.Fill = redBrush
...
                End Select
                Return True
            End If
        End Function

该函数通过定时器每 500 毫秒调用一次。 调试显示该函数只工作一次。 从第二次开始和所有其他时间,函数抛出异常

The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))

如果不使用 f... 调度程序和类似繁琐的东西,我怎么能防止这种情况发生。 此外,如果不存在 .Refresh 方法,又如何在不使用 f... 调度程序的情况下刷新 UI 元素?

旧的 winforms 没有这些问题...啊,旧时代。

我的 UI XAML 看起来像这样:

<StackPanel HorizontalAlignment="Center" 
            VerticalAlignment="Center" 
            Height="60"
            Margin="10,10,10,569" 
            Width="340"> 
    <TextBlock x:Name="DelayText1" 
               Text="Uscita digitale 1"
               Margin="10" 
               TextAlignment="Center"
               FontSize="26.667"
               HorizontalAlignment="Right" /> 
    <Ellipse x:Name="LED1" 
             Fill="LightGray"
             Stroke="White" 
             Width="25"
             Height="25"
             Margin="10,-40,10,0"
             HorizontalAlignment="Left"
             VerticalAlignment="Top"
             RenderTransformOrigin="3.524,-1.209"/>
</StackPanel>

数据绑定!

创建一个 LED ViewModel 对象,将一个对象绑定到每个 LED UI 元素。为 LED ViewModel 提供适当类型的 "Fill" 属性。然后,每 500 毫秒当您的计时器计时时,更新 属性 并触发 PropertyChanged 事件。当UI元素看到PropertyChanged事件,就会刷新"Fill"

这是一个架构变化,但您无需担心使用调度程序。

此网站 http://blogs.msdn.com/b/jerrynixon/archive/2012/10/12/xaml-binding-basics-101.aspx 有一个将字符串绑定到按钮文本的 OK 示例。请参阅 "Binding a property" - 您将需要做类似的事情,但您将绑定到 "Fill"

这个问题:How can I bind a background color in WPF/XAML? 也在做一些与您正在尝试做的事情非常相似的事情。

跟进解决评论中的问题

在您的视图模型中,您需要创建类型为 "Brush" 的 属性,然后在 XAML 中,将其绑定到椭圆的填充 属性喜欢:

//The viewmodel:
public sealed class LedViewModel: INotifyPropertyChanged {
    // Update this property and fire the PropertyChanged
    // event to propagate the change to the UI.
    public Brush LedFill { get; set; } 
. . .

//In the XAML:
<Ellipse x:Name="LED Whatever" 
         Fill="{Binding Path=LedFill}"
. . .

抱歉 - 我刚刚意识到我的示例是 c# 而你正在做 VB - XAML 部分将是相同的 - 你的 ViewModel 的语法将与我的略有不同.

好的,所以我做了什么:

Public NotInheritable Class LedViewModel
    Implements INotifyPropertyChanged

    Private _LEDFill As Brush
    Public Property LEDfill As Brush
        Get
        Return _LEDFill
    End Get
    Set(value As Brush)
        _LEDFill = value
    End Set
End Property

Public Event PropertyChanged As PropertyChangedEventHandler 
  Implements  INotifyPropertyChanged.PropertyChanged
End Class

在XAML

    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Height="60" Margin="10,10,10,569" Width="340">
        <TextBlock x:Name="DelayText1" Text="Uscita digitale 1" Margin="10" TextAlignment="Center" FontSize="26.667" HorizontalAlignment="Right" />
        <Ellipse x:Name="LED1" Fill="{Binding Path=LEDfill}" Stroke="White" Width="25" Height="25" Margin="10,-40,10,0" HorizontalAlignment="Left" VerticalAlignment="Top" RenderTransformOrigin="3.524,-1.209"/>
    </StackPanel>

在代码中? LED1.fill = 什么?