WPF BackgroundWorker ListView 过滤器问题

发布于 2024-07-26 21:32:39 字数 1059 浏览 5 评论 0原文

我有一个 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的示例吗?

I have a WPF ListView that I am trying to filter within a BackgroundWorker. My code is shown below:

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

This code runs through the filtering however it fails with an error "The calling thread cannot access this object because a different thread owns it." on the following line:

ListView.Filter = New Predicate(Of Object)(AddressOf Me.FindItemsAsync)

What would be the problem here? I can't seem to find any samples with filtering through the BackgroundWorker.

Update: Does anyone know of a sample that filters a WPF ListView using a BackgroundWorker?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

芸娘子的小脾气 2024-08-02 21:32:40

绑定到控件的 ListCollectionView 只能从创建它的线程访问。 所以你只能在UI线程上设置Filter属性...

A ListCollectionView that is bound to a control can only be accessed from the thread that created it. So you can only set the Filter property on the UI thread...

┈┾☆殇 2024-08-02 21:32:40

正如 Thomas 在评论中指出的那样,这种方法对于 WPF 来说完全是废话,它是 WinForms 方法

基于 Thomas 的回答,如果后台线程需要更新 UI,那么它需要首先切换到创建 UI 的线程。

为了简单起见,您可以考虑单个“UI 线程”,然后考虑“后台线程”。 UI 线程负责将内容绘制到屏幕上、处理用户交互等...来自修改 UI 的后台线程的调用可能会导致各种混乱,因此从 .NET 2.0(或可能 1.1)开始默认行为是抛出异常而不是允许潜在危险的调用成功。

通常(至少在 2.0 世界中),您可以通过“调用”需要更新的表单/控件来完成此操作,“调用”在框架中有点含糊,但在 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

一大警告:示例中的“delg”对象还包含一个“Invoke”成员,它不是您的 Invoke 方法正在寻找,你需要“Invoke(delg)”,而不是“delg.Invoke()”——这就是我提到的歧义

As Thomas points out in the comments, this approach is entirely bunk for WPF, it's the WinForms approach

Building on Thomas' answer, if a background thread needs to update the UI then it needs to first switch onto the thread which created the UI.

For the sake of simplicity you can think of a single "UI thread" and then "background threads". The UI thread is in charge of drawing things to the screen, handling user interaction, etc... Calls from the background thread that modify the UI can cause all sorts of messes, so starting in .NET 2.0 (or maybe 1.1) the default behavior is to throw an exception rather than allowing the potentially dangerous call to succeed.

Typically (at least in the 2.0 world) you do this by "Invoke'ing" the Form/Control you need to update, "Invoke" is a bit ambiguous in the framework, but in the context of UI controls it means "return to the UI thread".

In 2.0 the typical pattern used to do this would be along the lines of:

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: the "delg" object in the example also contains an "Invoke" member, which is NOT the Invoke method you're looking for, you need "Invoke(delg)", not "delg.Invoke()"--that's the ambiguity I mentioned

冷…雨湿花 2024-08-02 21:32:39

我猜运行过滤器将需要很长时间,因此您想在后台线程中运行过滤代码 - 这是不可能的。

与 UI 交互的代码(包括设置过滤器和过滤器内的代码)必须在 UI 线程中运行。

您可以做的是,在BackgroundWorker代码中创建一个新列表,其中仅包含应过滤的项目,然后在BackgroundWorker完成并且您返回UI线程后,将新列表设置为ListView的ItemSource 。

I guess running the filter is going to take a long time and so you want to run the filtering code in a background thread - this is just not possible.

Code that talks to the UI (including setting the filter and the code inside the filter) has to run in the UI thread.

What you can do is, inside the BackgroundWorker code, create a new list that includes only the items that should be filtered in and then, after the BackgroundWorker finishes and you are are back in the UI thread, set the new list to the ListView's ItemSource.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文