UWP将UI控件添加到非uit线程

时间:2017-07-11 16:52:33

标签: vb.net multithreading binding navigation uwp

因此,随着我学习越来越多的UWP和XAML,我遇到了两个问题,一个是(我认为)"导航"相关的,第二个是线程问题。我想要实现的目标很简单。我有两页,一页" home"和一个"设置"。在主页上,我将连接的客户端显示为Custom_Buttons。在“设置”页面上,我可以更改有关应用和已连接客户端的一些设置

导航问题 在我的MainPage上设置我需要的所有声明和对象类。当我导航到一个页面时,我将me(即MainPage)传递到我正在加载的页面,这样我就可以使用我在MainPage上声明的属性和对象。然后,当我加载页面时,我使用页面事件OnNavigatedTo来处理传递的MainPage并使用它执行本地stuf。当我经常在页面之间切换应用程序崩溃并打开页面app.g.i.vb并指向以下代码:

#If Debug AndAlso Not DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION Then
    AddHandler Me.UnhandledException,
        Sub(sender As Global.System.Object, unhandledExceptionArgs As Global.Windows.UI.Xaml.UnhandledExceptionEventArgs)
            If Global.System.Diagnostics.Debugger.IsAttached Then
             **Here--->>>**   Global.System.Diagnostics.Debugger.Break()
            End If
        End Sub
#End If

导航代码:

Private Sub ListBox_SelectionChanged(sender As Object, e As SelectionChangedEventArgs)

    If Home.IsSelected AndAlso Not ScenarioFrame.CurrentSourcePageType Is GetType(Home) Then
        BackButton.Visibility = Visibility.Collapsed
        ScenarioFrame.Navigate(GetType(Home), Me)
    ElseIf Settings.IsSelected AndAlso Not ScenarioFrame.CurrentSourcePageType Is GetType(Settings) Then
        BackButton.Visibility = Visibility.Visible
        ScenarioFrame.Navigate(GetType(Settings), Me)
    End If
End Sub

线程问题 在MainPage上,我声明了一个名为TCP_Server的类。此类有一个StreamSocketListener,它使用事件ConnectionReceived接受新的传入客户端。然后,我只需创建一个表示客户端UI形式的新Object,并将其传递给sub new中Event Args中的StreamSocket。通过这种方式,每个对象都可以直接从StreamSocket处理它自己的读写。然后我将这个新对象添加到TCP_Server类中保存的ObservableCollection(Of Object)。此列表绑定到我在HomePage上使用的Canvas的ItemsSource,而不是我的MainPage。

Protected Overrides Sub OnNavigatedTo(e As NavigationEventArgs)
    MyBase.OnNavigatedTo(e)

    If ButtonsList.ItemsSource = Nothing Then ButtonsList.ItemsSource = DirectCast(e.Parameter, MainPage).TCP_Server.Clients
End Sub

当我在ConnectionReceived中创建此新对象时,我收到错误System.Exception: 'The application has called an interface that has been marshalled for another thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)) '。它仅在我使用Dispatcher.RunAsync

时有效
Private Async Sub TCP_Listener_ConnectionReceived(sender As StreamSocketListener, args As StreamSocketListenerConnectionReceivedEventArgs) Handles TCP_Listener.ConnectionReceived

    'Check if the client already excists or not.
    Dim client As Client_Button = Clients.FirstOrDefault(Function(x) x.IPaddr = args.Socket.Information.RemoteAddress.ToString)

    rootPage.NotifyUser("New Client connected! : [" & args.Socket.Information.RemoteAddress.ToString & "] Total Connected clients = " & Clients.Count, NotifyType.Message)

    If client Is Nothing Then
        Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()
                                                                                                         'Create New object
                                                                                                         Dim x As New Client_Button(args.Socket)

                                                                                                         'Create new task that runs Async to process incomming data
                                                                                                         Dim tsk As Task = Task.Run(Sub() x.ProcessClientAsync())

                                                                                                         'Add to the task list so we can stop it later on
                                                                                                         ClientTasks.Add(tsk)

                                                                                                         'Add it to the Clients List so we can work with the objects
                                                                                                         Clients.Add(x)
                                                                                                         Return True
                                                                                                     End Function)
    Else
        Await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, Function()
                                                                                                         client = Nothing
                                                                                                         Clients.Remove(client)

                                                                                                         'Create New object
                                                                                                         Dim x As New Client_Button(args.Socket)

                                                                                                         'Create new task that runs Async to process incomming data
                                                                                                         Dim tsk As Task = Task.Run(Sub() x.ProcessClientAsync())

                                                                                                         'Add to the task list so we can stop it later on
                                                                                                         ClientTasks.Add(tsk)

                                                                                                         'Add it to the Clients List so we can work with the objects
                                                                                                         Clients.Add(x)
                                                                                                         Return True
                                                                                                     End Function)
    End If
End Sub

1 个答案:

答案 0 :(得分:1)

对于您在此处描述的“导航问题”,页面之间多次导航会崩溃,请尝试将页面的NavigationCacheMode设置为RequiredEnabled,如下所示:

Public Sub New()
    Me.InitializeComponent()
    Me.NavigationCacheMode = NavigationCacheMode.Required
End Sub

详情请参阅Page课程的评论。如果您仍有问题,请提供有关“UnhandledException”的详细信息。

对于“线程问题”,使用Core​Dispatcher是正确的方法,这是设计的。 ConnectionReceived在非UI线程中触发,但您在此事件句柄中调用了UI线程,因此您需要Dispatcher.RunAsync。更多细节,您可以参考this similar thread