-2

I've got this function that receives a digital output pin address uscita as Integer and status high as boolean, and updates the pin-out and fills color red in a LED-like Ellipse on the UI.

    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

The function is called every 500ms via a timer. Debugging shows that the function is working only once. From the second time and for all other times, the function throws an exception

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

How can I prevent that without using the f... dispatchers and similar cumbersome stuff. Additionally, how to refresh the UIelements, given that no .Refresh method exists, again without using the f... dispatchers?

The old winforms didn't have these issues... ah, the old times.

My UI XAML looks something like this:

<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>
4
  • 1
    The old winforms did have these issues, and you solve the problem in exactly the same way - by running the setter on the UI thread. You just need to use the WPF dispatcher instead of the BeginInvoke method on the main form. You're either going to have to do that, or use WPF data binding. Updating the ViewModel and triggering the "Property Changed" event will cause the control to refresh its bindings. Commented Aug 26, 2015 at 21:18
  • I don't want to use dispatchers. And begininvoke is not a member or method of dispatcher in UWP. Commented Aug 26, 2015 at 21:33
  • Yes, I was not being clear: Dispatcher goes with WPF just like BeginInvoke goes with Winforms Commented Aug 26, 2015 at 21:37
  • Using threads in winforms was an option. In UWP is not an option. Commented Aug 26, 2015 at 21:44

2 Answers 2

2

Data Binding!

Create an LED ViewModel object, bind one to each LED UI element. Give the LED ViewModel a "Fill" property of the appropriate type. Then, every 500 ms when your timer ticks, update the property and fire off the PropertyChanged event. When the UI element sees the PropertyChanged event, it will refresh "Fill"

It's a bit of an architecture change, but you won't need to worry about using the dispatcher.

This website http://blogs.msdn.com/b/jerrynixon/archive/2012/10/12/xaml-binding-basics-101.aspx has an OK example of binding a string to a button's text. See "Binding a property" - you're going to need to do something similar, but you'll be binding to "Fill"

This question: How can I bind a background color in WPF/XAML? is also doing something pretty similar to what you're trying to do.

Followup to address questions in comments

In your viewmodel, you would need to create a property of type "Brush" and then in the XAML, bind it to the Fill property of the ellipse like:

//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}"
. . .

Sorry - I just realized that my example is c# and you're doing VB - the XAML part will be the same - The syntax for your ViewModel will be a little different from mine.

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, although I'm pretty naive to bindings. So I have this stackpanel <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>`
What do I have to bind to what? Like this? <Ellipse Content="{Binding Path=LEDfill}" /> and instantiate a new class public class myLED? And what do I put inside? A UIElement get/set
Thanks, dude, wtf... I need to change a color of a circle on a form.
0

Ok, so what I did:

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

in the 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>

And in the code? LED1.fill = whatever?

1 Comment

Just to let you know that the binding thing is not working as suggested and expected. I had to resource to a dispatcher.timer event. Thanks anyway for your time and effort. This was very helpful and motivating.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.