【问题标题】:keeping the GUI responsive and interactive in WPF when running methods in other classes在其他类中运行方法时,在 WPF 中保持 GUI 响应和交互
【发布时间】:2014-10-09 07:36:57
【问题描述】:

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

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

到目前为止我的想法:

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

  2. 在 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

【问题讨论】:

  • 我的建议是使用线程或异步。
  • 但是你的后台类没有在后台
  • 是的,抱歉,我的示例不清楚 - 它不是从 GUI 读取,而是自动检查外部数据源以获取新数据。它会持续执行此操作 - 用户无需按下按钮即可实现

标签: wpf vb.net user-interface


【解决方案1】:

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

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

Public Class MyData
End Class

当我们想要更新 UI 时,可以使用 WPF 实现的SynchronisationContext 向 UI 线程发送消息。请注意,RunGetDataFromSomewhere 方法不会阻塞 UI。请注意,该类使用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

【讨论】:

  • 嗨,非常感谢!我正在尝试实现它,“_context.Post(Function(o) RaiseEvent MyDataAdded(DirectCast(o, MyData))”给我带来了麻烦 - 它说 _context 应该有 2 个参数 - 一个 SendingOrPostCallback 和一个状态对象。你能给我解释一下吗?我认为你的 Function(o) 调用有问题,但我不太了解它,无法弄清楚如何解决它。
  • 没关系,想通了 - 冒昧地编辑您的代码来更正它。基本上一些“功能”调用需要是“子”调用。
【解决方案2】:

这是一个实际可行的例子:

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

希望这会有所帮助。

【讨论】:

  • 这不是 WPF 而是 WinForms
  • 我为 windows 窗体编写了代码。按钮和列表框在 winform 和 WPF 中都可用。什么会让你觉得这是 WPF?
  • 问题明确说明WPF,WPF没有Control.Invoke,所以这不是答案
  • 所以你把它改成dispatcher。我的坏
猜你喜欢
  • 1970-01-01
  • 2010-09-14
  • 2023-01-26
  • 2011-05-31
  • 1970-01-01
  • 1970-01-01
  • 2019-07-04
  • 1970-01-01
  • 2021-06-20
相关资源
最近更新 更多