【问题标题】:WPF - Datagrid Binding: INotifyPropertyChanged and BackgroundWorker no UI-UpdateWPF - Datagrid 绑定:INotifyPropertyChanged 和 BackgroundWorker 没有 UI 更新
【发布时间】:2017-03-03 11:08:50
【问题描述】:

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

ViewModel Thread 中 DataTable 的每次更改都会通知给视图,并且视图是最新的。所以这很好用。 但是,如果我使用后台工作者来编辑 DataTable 的数据并在 RunWorkerCompleted 事件中通知,则视图将不会更新。

我已经尝试在相应的 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>

与 DataTable 的绑定:

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

Button 只是简单地执行 thread-worker。

【问题讨论】:

  • 也许问题在于您只是更新“数据”。但是,如果 DataTable 不可观察,您显然不会更新 View mate 中的任何内容。除了数据的绑定...
  • btnExecuteClick 哦,请不要。不。没有匈牙利语。此外,当视图模型实现 INPC 时,您不必 BeginInvoke 更新视图模型——绑定会自动为您将这些更新事件编组到 UI 线程上。这将大大简化您的代码。

标签: c# wpf multithreading mvvm datagrid


【解决方案1】:

按照@Peter 的建议对数据使用 ObservableColletion 并修改代码

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

希望这行得通!

【讨论】:

    【解决方案2】:

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多