我有一个WPF ListView,我试图在BackgroundWorker中过滤。我的代码如下所示:
Dim Worker As New BackgroundWorker
AddHandler Worker.DoWork, AddressOf Me.FilterAsync
Me.TextBoxText = Me.TextBox.Text
Worker.RunWorkerAsync(Me.TextBox)
Private Sub FilterAsync(ByVal sender As Object, ByVal e As DoWorkEventArgs)
'
Dim BackgroundWorker As BackgroundWorker = CType(sender, BackgroundWorker)
Dim Text As String = e.Argument.ToString
'
Dim ListView As ListCollectionView = CType(CollectionViewSource.GetDefaultView(Me.ListView.ItemsSource), ListCollectionView)
If Text <> String.Empty Then
ListView.Filter = New Predicate(Of Object)(AddressOf Me.FindItemsAsync)
Else
ListView.Filter = Nothing
End If
'
End Sub
此代码通过过滤运行但是它失败并显示错误“调用线程无法访问此对象,因为其他线程拥有它。”在以下行:
ListView.Filter = New Predicate(Of Object)(AddressOf Me.FindItemsAsync)
这里会出现什么问题?我似乎找不到任何通过BackgroundWorker过滤的样本。
更新:是否有人知道使用BackgroundWorker过滤WPF ListView的示例?
答案 0 :(得分:1)
我想运行过滤器需要很长时间,所以你想在后台线程中运行过滤代码 - 这是不可能的。
与UI对话的代码(包括设置过滤器和过滤器内的代码)必须在UI线程中运行。
您可以在BackgroundWorker代码中创建一个新列表,其中仅包含应该过滤的项目,然后在BackgroundWorker完成后您又回到UI线程中,将新列表设置为ListView的ItemSource。
答案 1 :(得分:0)
绑定到控件的ListCollectionView
只能从创建它的线程访问。因此,您只能在UI线程上设置Filter
属性...
答案 2 :(得分:0)
正如托马斯在评论中指出的那样,这种方法对于WPF来说完全是上下文,它是WinForms方法
基于Thomas的回答,如果后台线程需要更新UI,那么它需要先切换到创建UI的线程。
为简单起见,您可以想到一个“UI线程”,然后是“后台线程”。 UI线程负责将事物绘制到屏幕上,处理用户交互等等...来自修改UI的后台线程的调用可能导致各种混乱,所以从.NET 2.0(或者1.1)开始默认行为是抛出异常而不是允许潜在危险的调用成功。
通常(至少在2.0世界中)你通过“调用”你需要更新的表单/控件来做到这一点,“调用”在框架中有点模棱两可,但在UI控件的上下文中它意味着“返回UI线程”。
在2.0中,用于执行此操作的典型模式将遵循:
Private DelegateSub UpdateSomeUICaller()
Private Sub UpdateSomeUI()
If Me.InvokeRequired Then
Dim delg as new UpdateSomeUICaller(AddressOf UpdateSomeUI)
Me.Invoke(delg)
Exit Sub
End If
Me.SomeUiControl.Text = "Hello from the UI Thread!"
End Sub
ONE BIG WARNING:示例中的“delg”对象还包含一个“Invoke”成员, NOT 您正在寻找的Invoke方法,您需要“Invoke(delg)” ,而不是“delg.Invoke()” - 这就是我提到的歧义