167

非同期メソッドでViewModelからデータを入力しているDataGridがあります.My 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 クラスのリスト) を取得しています。ここで、上記のエラーが表示されます (タイトルで示したように) 「このタイプの CollectionView は、Dispatcher スレッドとは異なるスレッドからの SourceCollection への変更をサポートしていません」 ここに画像の説明を入力

誰でも私に解決策を提案できますか?さらに、可能であれば、DataGrid を View にバインドする方法を知りたいのですが、より良い方法があれば非同期で更新することもできます。

4

8 に答える 8

266

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);
            });
        }
    }
于 2013-08-20T13:32:07.823 に答える
8

私は同じ問題を一度経験し、AsyncObservableCollection ( http://www.thomaslevesque.com/2009/04/17/wpf-binding-to-an-asynchronous-collection/ ) で問題を解決しました。

于 2014-03-23T12:21:39.447 に答える
2

BackgroundWorker を使用している場合は、UI の同じスレッドでイベントを発生させる必要があります。

たとえば、2 つのビュー A と B があり、A 内の次のコードがイベント WakeUpEvent を発生させる場合

//Code inside codebehind or viewmodel of A
    var worker = new BackgroundWorker();
    worker.DoWork += WorkerDoWork; //<-- Don't raise the event WakeUpEvent inside this method
    worker.RunWorkerCompleted += workerRunWorkerCompleted; // <-- Raise the event WakeUpEvent inside this method instead
    worker.RunWorkerAsync();

//Code inside codebehind or viewmodel of view B
    public ViewB () {
        WakeUpEvent += UpdateUICallBack;
    }
    private void UpdateUICallBack() {
        //Update here UI element
    }

WorkerDoWork メソッドは、UI とは異なるスレッドで実行されます。

于 2016-07-20T10:58:59.047 に答える