在其他类中运行方法时,在WPF中保持GUI响应和交互

时间:2014-08-15 14:46:58

标签: wpf vb.net user-interface

我正在编写VB.Net(.net framework 4.5)WPF软件,它有一个不断通过网络读取数据的类,然后在数据进入时在WPF GUI上填充列表框。用户可以同时点击listboxitem在单独的文本块中查看有关它的更多信息。

我的问题是,如何在后台执行其他内容(在不同的课程中)时保持GUI的响应性和可用性?

到目前为止我的想法:

  1. 在应用程序首次运行时同时实例化GUI和后台类(但是它们如何交互?)

  2. 在GUI MainWindow中使用线程 - 但是如何让它更新GUI,作为另一个类中的方法?另外,我需要哪种线程代码? (这是我第一次真正尝试这样做而且我之前没有在vb.net中做过任何代码......)

  3. 非常感谢任何建议!

    以下是一些示例代码:

    'GUI Class
    Private Sub MainWindow_Loaded(sender As Object, e As RoutedEventArgs)
        ShowLoginScreen()
        'run background thread somehow?
    End Sub
    Private Sub MainWindow_Closing(sender As Object, e As ComponentModel.CancelEventArgs)
        'nicely stop the background thread
    End Sub
    
    'background class
    Private stopRunningFlag As Boolean = False
    Private dataList As List(Of DataType)
    Sub StartRunning()
        Do Until stopRunningFlag.Equals(True)
            For Each data As DataTypeIn dataList
                'read and process data
                'update GUI
            Next
            'read more data in
        Loop
    End Sub
    

2 个答案:

答案 0 :(得分:1)

免责声明:代码已从C#转换为VB

假设我们有一个包含您要发送到UI的内容的类:

Public Class MyData
End Class

当我们想要更新UI时,我们可以使用WPF实现的SynchronisationContext向UI线程发送消息。请注意,方法RunGetDataFromSomewhere不会阻止用户界面。请注意,该类使用CancellationToken将消息发送到后台线程,它应该在我们关闭应用程序时停止它的操作。 BackgroundStuff有一个可以订阅的事件,以便在有新数据时收到通知。

Public Class BackgroundStuff
    Private ReadOnly _context As SynchronizationContext
    Private _cts As New CancellationTokenSource()
    Public Sub New()
        'this constructor has to be called on the UI thread so
        'this class knows how to send a message to the UI thread.
        _context = SynchronizationContext.Current
        Task.Factory.StartNew(Function() Run(_cts.Token))
    End Sub

    Public Sub Run(token As CancellationToken)
        While Not token.IsCancellationRequested
            Dim data As MyData = GetMyDataFromSomewhere()
            SendData(data)
        End While
    End Sub

    Private Function GetMyDataFromSomewhere() As MyData
        Thread.Sleep(500)
        Return New MyData()
    End Function

    Public Event MyDataAdded As Action(Of MyData)

    Private Sub SendData(data As MyData)
        _context.Post(Function(o) 
        RaiseEvent MyDataAdded(DirectCast(o, MyData))

End Function, data)
    End Sub

    Public Sub [End]()
        _cts.Cancel()
    End Sub
End Class

最后,MainWindow中的一些代码(我添加了一个简单的列表框来添加MyData元素)。

Public Partial Class MainWindow
    Inherits Window
    Private ReadOnly _backgroundStuff As BackgroundStuff
    Public Sub New()
        InitializeComponent()
        _backgroundStuff = New BackgroundStuff()
        AddHandler _backgroundStuff.MyDataAdded, AddressOf _backgroundStuff_MyDataAdded
        AddHandler Me.Closing, AddressOf MainWindow_Closing
    End Sub

    Private Sub _backgroundStuff_MyDataAdded(obj As MyData)
        MyListBox.Items.Add(obj)
    End Sub

    Private Sub MainWindow_Closing(sender As Object, e As System.ComponentModel.CancelEventArgs)
        _backgroundStuff.[End]()
    End Sub
End Class

答案 1 :(得分:0)

这是一个有效的实际例子:

Private Sub Whatever()
    Dispatcher.Invoke(New Action(Function() ListBox1.Items.Add("Hello")))

End Sub

Private Sub Button_Click(sender As Object, e As RoutedEventArgs)
    System.Threading.ThreadPool.QueueUserWorkItem(AddressOf Whatever)
End Sub

希望这有帮助。