2017-03-03 100 views
0

我在我的视图中使用DataGrid,它绑定到ViewModel实例的DataTable。WPF - Datagrid绑定:INotifyPropertyChanged和BackgroundWorker没有UI更新

ViewModel线程中DataTable的每次更改都会通知到视图,并且视图是最新的。所以这工作正常。 但是,如果我使用backgroundworker编辑DataTable的数据并在RunWorkerCompleted Event中通知,那么视图将不会更新。

我尝试过在相应的Dispatcher中引发PropertyChange事件,但没有更改。

所以我检查了ThreadId,所有的代码都会在正确的线程中执行。我的视图模型:

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> 

绑定到数据表:

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

的按钮即可执行线程的工人。

+0

也许问题是,你只需更新“数据”。但是,如果DataTable不可观察,你显然不会更新View mate中的任何内容。除了数据绑定... – Peter

+0

'btnExecuteClick'哦请不要。别。没有匈牙利人。另外,当你实现INPC时,你不需要对你的视图模型进行“BeginInvoke”更新 - 绑定会自动将这些更新事件编组到你的UI线程中。这将大大简化您的代码。 – Will

回答

0

使用ObservableColletion的数据,如@Peter建议和修改代码

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

希望这个作品!

0

设置你的窗口DataContext财产到您的视图模型的实例:

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

然后,每当你提高PropertyChanged事件视图模型的Data财产DataGrid应该更新。