0

BackgroundWorker 内でフィルタリングしようとしている WPF ListView があります。私のコードを以下に示します。

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 をフィルター処理するサンプルを知っている人はいますか?

4

3 に答える 3

1

フィルターの実行には時間がかかると思いますので、フィルタリング コードをバックグラウンド スレッドで実行する必要がありますが、これは不可能です。

UI と対話するコード (フィルターの設定とフィルター内のコードを含む) は、UI スレッドで実行する必要があります。

できることは、BackgroundWorker コード内で、フィルター処理する必要がある項目のみを含む新しいリストを作成し、BackgroundWorker が終了して UI スレッドに戻った後、新しいリストを ListView の ItemSource に設定することです。 .

于 2009-10-28T12:12:11.020 に答える
0

Thomas がコメントで指摘しているように、このアプローチは 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

1 つの大きな警告: この例の「delg」オブジェクトには「Invoke」メンバーも含まれていますが、これは探している Invoke メソッドではありません。「delg.Invoke()」ではなく「Invoke(delg)」が必要です。 -それは私が言及した曖昧さです

于 2009-07-08T15:32:23.570 に答える
0

コントロールにバインドされているListCollectionViewは、それを作成したスレッドからのみアクセスできます。Filterしたがって、UIスレッドでのみプロパティを設定できます...

于 2009-07-08T15:16:32.213 に答える