2017-03-03 18 views
0

ViewModelインスタンスのDataTableにバインドされている、ビューでDataGridを使用しています。WPF - Datagridバインディング:InotifyPropertyChangedおよびBackgroundWorker UI更新なし

ViewModelスレッド内のDataTableの各変更は、ビューに通知され、ビューは最新です。だからこれはうまく動作します。 しかし、私がDataTableのデータを編集するために背景作業者を使用し、RunWorkerCompletedイベント内に通知すると、ビューは更新されません。

対応するDispatcher内でPropertyChangeイベントを発生させようとしましたが、変更はありませんでした。

私はスレッドIDをチェックし、すべてのコードが正しいスレッドで実行されます。私のViewModel:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows; 
using System.Windows.Input; 
using System.Windows.Threading; 

namespace BackgroundWorker_vs_INotifyPropertyChange 
{ 
    class ViewModel : INotifyPropertyChanged 
    { 
     public event PropertyChangedEventHandler PropertyChanged; 



    BackgroundWorker worker; 

    #region Properties 
    private DataTable data = new DataTable(); 
    public DataTable Data 
    { 
     get 
     { 
      return data; 
     } 
    } 
    #endregion 

    #region Commands 
    ButtonCommand btnCommand; 
    public ICommand btnExecuteClick 
    { 
     get 
     { 
      return btnCommand; 
     } 
    } 
    #endregion 

    public ViewModel() 
    { 
     Debug.WriteLine("ViewModel_" + Thread.CurrentThread.ManagedThreadId); 
     // Default data for datatable 
     data.Columns.Add("Firstname"); 
     data.Columns.Add("Lastname"); 
     // -- Sample data 
     data.Rows.Add("Andreas", "Anderson"); 

     // Commands 
     btnCommand = new ButtonCommand(worker_Start); 

     // BackgroundWorker 
     worker = new BackgroundWorker(); 
     worker.WorkerReportsProgress = true; 
     worker.WorkerSupportsCancellation = true; 

     worker.DoWork += new DoWorkEventHandler(worker_DoWork); 
     worker.ProgressChanged += 
        new ProgressChangedEventHandler(worker_ProgressChanged); 
     worker.RunWorkerCompleted += 
        new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted); 
    } 

    private void worker_Start() 
    { 
     worker.RunWorkerAsync(); 
    } 


    private void worker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     Debug.WriteLine("worker_" + Thread.CurrentThread.ManagedThreadId); 
     // Process some work like filling the aDataTable with new data 
     // ... 
     int percentFinished = 0; 
     while (!worker.CancellationPending && percentFinished < 100) 
     { 
      percentFinished++; 
      worker.ReportProgress(percentFinished); 
      System.Threading.Thread.Sleep(50); 
      data.Rows.Add(percentFinished.ToString(), percentFinished.ToString()); 
     } 
     e.Result = percentFinished; 
    } 

    void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) 
    { 
    } 

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
    {// Worker finished 

     // Notify the PropertyChanged Listener the change of ProgressStateOfWork Property 
     Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
        new Action(() => 
        { 
         this.RaisePropertyChanged("Data"); 
         Debug.WriteLine("Dispatcher_" + Thread.CurrentThread.ManagedThreadId); 
         //PropertyChanged(this, new PropertyChangedEventArgs("Data")); 
        } 
        )); 
     MessageBox.Show("Completed"); 
    } 

    protected void RaisePropertyChanged(string s) 
    { 
     Debug.WriteLine("RaisePropertyChanged_" + Thread.CurrentThread.ManagedThreadId); 
     var temp = PropertyChanged; 
     if (temp != null) 
     { 
      temp(this, new PropertyChangedEventArgs(s)); 
     } 
    } 
} 

}

マイビューのリソース

<Window.Resources> 
    <local:ViewModel x:Key="aViewModel"></local:ViewModel> 
</Window.Resources> 

のDataTableへの結合:

<DataGrid x:Name="dataGrid" 
      ItemsSource="{Binding Data,Source={StaticResource aViewModel}}" /> 

は、ボタンは単にスレッドのワーカーを実行します。

+0

おそらく問題は、単に「データ」を更新することです。しかし、DataTableが観測できない場合は、ViewMateで何も更新しないことは明らかです。データのバインドを除いて... – Peter

+0

'btnExecuteClick'ああいいえください。しないでください。ハンガリー人なし。また、INPCを実装するときに、ビューモデルへの 'BeginInvoke'更新を行う必要はありません.Bindingsは自動的にこれらの更新イベントをUIスレッドにマーシャリングします。それはあなたのコードを大幅に簡素化します。 – Will

答えて

0

データのObservableColletion使用、@Peterによって提案されたと

 Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, 
       new Action(() => 
       { 
        Data.Rows.Add(percentFinished.ToString(), percentFinished.ToString()); 
       } 
       )); 

はこの作品を願って、コードを変更して!!あなたのビューモデルのインスタンスへのあなたのウィンドウのDataContextプロパティを設定

0

:あなたはビューモデルのDataプロパティのPropertyChangedイベントを発生させるたび

<Window.DataContext> 
    <local:ViewModel /> 
</Window.DataContext> 
... 
<DataGrid x:Name="dataGrid" ItemsSource="{Binding Data}" /> 

はその後DataGridを更新する必要があります。

関連する問題