0

I'm trying to raise an event from a UWP class library background task, but I need to marshal it on the main UI thread in the UWP app I plan to use the class library with. I'm looking for a way to marshal it from the background task though. I've looked through a couple of articles including this one: Raise Events in .NET on the main UI thread but its not making sense to me. Can anyone help me with the below code?

    Private ReceiveTask As New Task(Sub()    
                                    Dim InStream As Stream = CSocket.InputStream.AsStreamForRead    
                                    While killswitch = False    
                                        Try    
                                            Dim Reader As StreamReader = New StreamReader(InStream)    
                                            Dim DataText As String = ""    
                                            While Reader.Peek <> -1    
                                                DataText &= Convert.ToChar(Reader.Read)    
                                            End While    
                                            RaiseEvent DataReceived(DataText)    
                                        Catch ex As Exception    
                                            RaiseEvent SocketError("Receiving", ex.Message)    
                                        End Try    
                                    End While    
                                End Sub)    

Thanks to jmcilhinney, the below code works!

    Private ReceiveTask As New Task(Sub()
                                    Dim InStream As Stream = CSocket.InputStream.AsStreamForRead
                                    While killswitch = False
                                        Try
                                            Dim Reader As StreamReader = New StreamReader(InStream)
                                            If Reader.Peek <> -1 Then
                                                DataText = ""
                                                While Reader.Peek <> -1
                                                    DataText &= Convert.ToChar(Reader.Read)
                                                End While
                                                uiContext.Post(AddressOf RaiseDataToUI, Nothing)
                                            End If
                                        Catch ex As Exception
                                            ReceiveError = ex.Message
                                            uiContext.Post(AddressOf RaiseErrorToUI, Nothing)
                                        End Try
                                    End While
                                End Sub)
Community
  • 1
  • 1
Kevin
  • 23
  • 5

1 Answers1

0

I've not done any UWP development myself but I believe the correct way to do as you want is to use the SynchronizationContext class, as in WPF. The principle is that the SynchronizationContext.Current property will yield a thread-specific instance of the class, so you can get the value of that property on the UI thread and then use that object elsewhere to marshal a call to the owning thread. The property value is usually retrieved in the constructor of an object that is itself created on the UI thread, e.g.

Imports System.Threading

Public Class SomeClass

    'Get the context for the thread on which the current instance is created.
    Private uiContext As SynchronizationContext = SynchronizationContext.Current

    Private Sub ThisMethodIsCalledOnASecondaryThread()
        uiContext.Post(AddressOf ThisMethodIsCalledOnTheUIThread, Nothing)
    End Sub

    Private Sub ThisMethodIsCalledOnTheUIThread(data As Object)
        'Execute UI thread logic here, e.g. raise an event.
    End Sub

End Class
jmcilhinney
  • 50,448
  • 5
  • 26
  • 46
  • This works in the sense that I'm now able to raise the event to the UI. But I've tested my test client with test server software, and it seems like uiContext.post can't send the info to the UI fast enough. I'm missing a bunch of information coming through the socket. Task.Delay doesn't seem to help at all. Any ideas? – Kevin Jan 30 '17 at 13:33
  • Nevermind, it works. Was clearing the buffer before the event had time to fire. Will post correct code for others. – Kevin Jan 30 '17 at 13:45
  • In my example above, I have passed `Nothing` to the second parameter of the `Post` method. I see that you have done the same in your final code, which suggests that you must be reading data in the `RaiseErrorToUI` method. It may be better for you to read that data before calling `Post` and pass it to that parameter. You'll then receive it as an argument top the method you invoke. That means that it doesn't matter what happens to the original source of that data in the meantime. – jmcilhinney Jan 30 '17 at 21:52
  • Good idea, I've implemented that, thanks for the tip! :) – Kevin Feb 17 '17 at 16:17