2009-07-08 21 views
0

BackgroundWorkerでフィルタリングしようとしているWPF ListViewがあります。私のコードは次のようになります。WPF BackgroundWorker 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をフィルタリングするサンプルを知っている人はいますか?

+0

より完全なサンプルを提供できますか?提供されたスニペットでは、私はエラーを再現することができず、別の結果につながることをあまり想定したくありません。 – STW

+0

ありがとう!できるだけ早くより完全なサンプルを取得しようとします。Stackoverflowが質問に大量のコードをダンプするのではなく、ファイルの添付ファイルを受け入れるといいでしょう。 WPF ListViewをフィルタリングするためのBackgroundWorkerのサンプルコードはありますか? – Luke

+0

具体的には、それはクロススレッドの問題であり、より完全なサンプルは、それを修正する方法を教えてくれます。 – STW

答えて

1

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

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

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

0

コントロールにバインドされたListCollectionViewは、コントロールを作成したスレッドからのみアクセスできます。だから、あなたが唯一のトーマスはコメントで指摘するように、このアプローチは完全にWPFのための二段れる... UIスレッド上で

+0

ありがとう!さて、UIスレッドにフィルタを設定するように設定すると、UIスレッドでも述語が実行されず、BackgroundWorkerスレッド内では実行されませんか? – Luke

+0

フィルタを割り当てると、各項目の述語の評価がトリガーされるため、UIスレッドで実行されます。実際には、バックグラウンドスレッドでフィルタリングを行うことが可能かどうかはわかりません...少なくとも簡単にはありません。 –

0

Filterプロパティを設定することができ、それは、WinFormsのはトーマスの答えに

ビルに近づきますバックグラウンドスレッドがUIを更新する必要がある場合は、最初にUIを作成したスレッドに切り替える必要があります。

簡単にするために、1つの「UIスレッド」と「バックグラウンドスレッド」を考えることができます。 UIスレッドは、画面への描画、ユーザー操作の処理などを担当しています... UIを変更するバックグラウンドスレッドからの呼び出しは、あらゆる種類の混乱の原因となる可能性があります。そのため、.NET 2.0(または多分1.1)潜在的に危険な呼び出しを成功させるのではなく、例外をスローすることです。

一般的に(少なくとも2.0の世界では)更新する必要のあるフォーム/コントロールを「Invoke」することによってこれを行います。「Invoke」はフレームワークで少し曖昧ですが、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メソッドは、 "delg.Invoke()"ではなく、 "delg.Invoke()"を呼び出す必要があります - これは私が言及したあいまいさです

+1

Me.InvokeとMe.InvokeRequiredは、WPFではなくWindowsフォーム用です。WPFでは、Dispatcherプロパティを使用してUIスレッドでメソッドを呼び出します。 –

+0

@トーマスは真剣に知っておいてよかったですが、WPFのために私の足元にたどり着いたことは分かりませんでした(本当にもっとXAMLを始めたようです)... – STW