1. ホーム
  2. c#

[解決済み] このタイプのCollectionViewは、Dispatcherスレッドとは異なるスレッドからそのSourceCollectionへの変更をサポートしません[重複]。

2022-04-24 11:20:21

質問

私は、非同期メソッドによってViewModelからデータを取り込むDataGridを持っています。

<DataGrid ItemsSource="{Binding MatchObsCollection}"  x:Name="dataGridParent" 
                      Style="{StaticResource EfesDataGridStyle}" 
                      HorizontalGridLinesBrush="#DADADA" VerticalGridLinesBrush="#DADADA" Cursor="Hand" AutoGenerateColumns="False" 
                      RowDetailsVisibilityMode="Visible"  >

を使っています。 http://www.amazedsaint.com/2010/10/asynchronous-delegate-command-for-your.html を使用して、私のビューモデルに非同期方法を実装します。

以下は、私のビューモデルのコードです。

public class MainWindowViewModel:WorkspaceViewModel,INotifyCollectionChanged
    {        

        MatchBLL matchBLL = new MatchBLL();
        EfesBetServiceReference.EfesBetClient proxy = new EfesBetClient();

        public ICommand DoSomethingCommand { get; set; }
        public MainWindowViewModel()
        {
            DoSomethingCommand = new AsyncDelegateCommand(
                () => Load(), null, null,
                (ex) => Debug.WriteLine(ex.Message));           
            _matchObsCollection = new ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC>();                

        }       

        List<EfesBet.DataContract.GetMatchDetailsDC> matchList;
        ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> _matchObsCollection;

        public ObservableCollection<EfesBet.DataContract.GetMatchDetailsDC> MatchObsCollection
        {
            get { return _matchObsCollection; }
            set
            {
                _matchObsCollection = value;
                OnPropertyChanged("MatchObsCollection");
            }
        }        
        //
        public void Load()
        {            
            matchList = new List<GetMatchDetailsDC>();
            matchList = proxy.GetMatch().ToList();

            foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList)
            {
                _matchObsCollection.Add(match);
            }

        }

ViewModelのLoad()メソッドでわかるように、まずServiceからmatchList(DataContractクラスのリスト)を取得し、foreachループでmatchListのアイテムを_matchObsCollection(DataContractクラスのObservableCollection))に挿入しています。ここで上記のエラー(タイトルに示したように) "This type of CollectionView does not support to its SourceCollection from a thread different than Dispatcher thread" が発生します。

また、可能であれば、ビューでDataGridをバインドする方法と、より良い方法があれば非同期でそれを更新する方法を知りたいのですが、どなたか解決方法を教えていただけませんか?

解決方法は?

ObservableCollectionはUIスレッドで作成されているので、UIスレッドからのみ変更可能で、他のスレッドからは変更できません。これは、次のように呼ばれています。 スレッドアフィニティ .

UIスレッドで作成されたオブジェクトを別のスレッドから更新する必要がある場合、単純に put the delegate on UI Dispatcher というように、UIスレッドに委譲してくれます。これは動作します。

    public void Load()
    {
        matchList = new List<GetMatchDetailsDC>();
        matchList = proxy.GetMatch().ToList();

        foreach (EfesBet.DataContract.GetMatchDetailsDC match in matchList)
        {
            App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE
            {
                _matchObsCollection.Add(match);
            });
        }
    }