WPF - Datagrid绑定:INotifyPropertyChanged和BackgroundWorker没有UI更新

时间:2017-03-03 11:08:51

标签: c# wpf multithreading mvvm datagrid

我在我的View中使用DataGrid,它绑定到ViewModel实例的DataTable。

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

我已经尝试在相应的Dispatcher中引发PropertyChange事件,但没有变化。

所以我检查了ThreadId,所有代码都将在正确的线程中执行。我的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}}" />

Button只执行线程工作者。

2 个答案:

答案 0 :(得分:0)

按照@Peter的建议使用ObservableColletion for Data并修改代码

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

希望这有效!!

答案 1 :(得分:0)

将窗口的DataContext属性设置为视图模型的实例:

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

每当您为视图模型的DataGrid属性引发PropertyChanged事件时,都应更新Data