我正在编写VB.Net(.net framework 4.5)WPF软件,它有一个不断通过网络读取数据的类,然后在数据进入时在WPF GUI上填充列表框。用户可以同时点击listboxitem在单独的文本块中查看有关它的更多信息。
我的问题是,如何在后台执行其他内容(在不同的课程中)时保持GUI的响应性和可用性?
到目前为止我的想法:
在应用程序首次运行时同时实例化GUI和后台类(但是它们如何交互?)
在GUI MainWindow中使用线程 - 但是如何让它更新GUI,作为另一个类中的方法?另外,我需要哪种线程代码? (这是我第一次真正尝试这样做而且我之前没有在vb.net中做过任何代码......)
非常感谢任何建议!
以下是一些示例代码:
'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
答案 0 :(得分:1)
免责声明:代码已从C#转换为VB
假设我们有一个包含您要发送到UI的内容的类:
Public Class MyData
End Class
当我们想要更新UI时,我们可以使用WPF实现的SynchronisationContext
向UI线程发送消息。请注意,方法Run
和GetDataFromSomewhere
不会阻止用户界面。请注意,该类使用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
希望这有帮助。