当后台工作人员在 WPF 项目 (MVVM) 中工作时更新 UI

问题描述 投票:0回答:1

在我的 WPF 项目中,我需要将大量 SQL 数据传输到数据网格。自然是等的时间长了。我使用了 MVVM 模式。

为了使 UI 更具响应性,我使用了后台工作者。但传输完成后,屏幕再次冻结,并且 UI 更新。我希望在加载数据时更新 UI。有关于这个主题的主题,我理解这是关于使用

ProgressChanged
事件,但我无法弄清楚。所以我准备了一个简单的项目来询问。

这是我的 XAML 标记:

<Window x:Class="BackRoundWorkerTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BackRoundWorkerTest"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Window.Resources>
        <local:BackroundWorkerVM x:Key="vm"/>
    </Window.Resources>

    <Grid DataContext="{StaticResource vm}">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="40"/>
        </Grid.RowDefinitions>
        <DataGrid ItemsSource="{Binding Persons, UpdateSourceTrigger=PropertyChanged}"
                  AutoGenerateColumns="True">
        </DataGrid>
      
        <Button Grid.Row="1"
                Command="{Binding DoWorkCommand}"/>
    </Grid>
</Window>

这是视图模型:

public class BackgroundWorkerVM : INotifyPropertyChanged
{
     private BackgroundWorker worker;

     // it calls the PopulateList() method.
     public DoWorkCommand DoWorkCommand { get; set; } 

     public BackgroundWorkerVM()
     {
         // it calls the PopulateList() method.
         DoWorkCommand = new DoWorkCommand(this); 
         worker = new BackgroundWorker();
         worker.DoWork += Worker_DoWork;
         worker.RunWorkerCompleted += Worker_RunWorkerCompleted;
         worker.WorkerReportsProgress = true;
     }

     private ObservableCollection<Person> persons = new ObservableCollection<Person>();

     public ObservableCollection<Person> Persons
     {
         get { return persons; }
         set
         {
             persons = value;
             OnPropertyChanged();
         }
     }

     public void PopulateList()
     {
         worker.RunWorkerAsync();
     }

     private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
     {
     }

     private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
     {
     }

     private void Worker_DoWork(object sender, DoWorkEventArgs e)
     {
         App.Current.Dispatcher.Invoke((Action)delegate 
         {
             for (int i = 0; i < 100; i++)
             {
                 Persons.Add(new Person { PersonName = "john", Surname = "Smith", ResultChanged = true });
                 Thread.Sleep(100);
                 Persons.Add(new Person { PersonName = "jack", Surname = "Smith", ResultChanged = false });
             }
         });
     }

     public event PropertyChangedEventHandler PropertyChanged;
     protected void OnPropertyChanged([CallerMemberName] string name = null)
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
     }
 }

这是模型类:

public class Person
{
    public string PersonName { get; set; }
    public string Surname { get; set; }
    public bool ResultChanged { get; set; }
}
c# wpf mvvm
1个回答
0
投票

您仍然在主应用程序线程上进行所有等待

App.Current.Dispatcher.Invoke(...)
。因此,当
Invoke(...)
中调用的方法正在运行时,主应用程序线程无法更新 GUI。

可能的选择之一是在池线程中准备集合,然后替换整个集合:

    public class BackgroundWorkerVM : INotifyPropertyChanged
    {
        public RelayCommand DoWorkCommand { get; }

        public BackgroundWorkerVM()
        {
            DoWorkCommand = new(PopulateList);
        }

        private ObservableCollection<Person> _persons = new ObservableCollection<Person>();

        public ObservableCollection<Person> Persons
        {
            get { return _persons; }
            set
            {
                _persons = value;
                OnPropertyChanged();
            }
        }

        public async void PopulateList()
        {
            var list = await Task.Run(Worker_DoWork);

            Persons = list;
        }


        private ObservableCollection<Person> Worker_DoWork()
        {
            ObservableCollection<Person> list = new ObservableCollection<Person>();

            for (int i = 0; i < 100; i++)
            {
                list.Add(new Person { PersonName = "john", Surname = "Smith", ResultChanged = true });
                Thread.Sleep(100);
                list.Add(new Person { PersonName = "jack", Surname = "Smith", ResultChanged = false });
            }

            return list;
        }

        public event PropertyChangedEventHandler? PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string? name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.