WPF загружает анимацию в отдельный stream пользовательского интерфейса? (С #)

Хорошо, у меня есть анимация загрузки, которая работает, пока большой DataTable заполняется, чтобы сообщить пользователю, что программа не замерзала. У меня анимация работает нормально, но она зависает, а DataTable также обновляет. Есть ли способ иметь несколько streamов пользовательского интерфейса, чтобы анимация продолжала работать, пока DataTable загружает информацию?

EDIT: Текущий код ниже.

private void CreateFileTable() { file_data = new DataSet(); data_table = new DataTable(); file_data.Tables.Add(data_table); DataColumn tempCol = new DataColumn("File Name", typeof(string)); data_table.Columns.Add(tempCol); tempCol = new DataColumn("Ext", typeof(string)); data_table.Columns.Add(tempCol); tempCol = new DataColumn("Size", typeof(string)); data_table.Columns.Add(tempCol); tempCol = new DataColumn("Created", typeof(Label)); data_table.Columns.Add(tempCol); tempCol = new DataColumn("Modified", typeof(Label)); data_table.Columns.Add(tempCol); tempCol = new DataColumn("Accessed", typeof(Label)); data_table.Columns.Add(tempCol); tempCol = new DataColumn("Location", typeof(string)); data_table.Columns.Add(tempCol); File_List.ItemsSource = file_data.Tables[0].DefaultView; } private void PopulateDirectories(string[] directories) { for (int i = 0; i < directories.Length; i++) { DirectoryInfo tempDirInfo = new DirectoryInfo(directories[i]); bool isSystem = ((tempDirInfo.Attributes & FileAttributes.System) == FileAttributes.System); if (!isSystem) { DataRow tempRow = data_table.NewRow(); tempRow["File Name"] = tempDirInfo.Name; tempRow["Ext"] = ""; tempRow["Size"] = ""; tempLabel = new Label(); tempLabel.Padding = new Thickness(2, 0, 2, 0); tempLabel.Content = tempDirInfo.CreationTime.ToLongDateString() + ", " + tempDirInfo.CreationTime.ToLongTimeString(); tempRow["Created"] = tempLabel; tempLabel = new Label(); tempLabel.Padding = new Thickness(2, 0, 2, 0); tempLabel.Content = tempDirInfo.LastWriteTime.ToLongDateString() + ", " + tempDirInfo.LastWriteTime.ToLongTimeString(); tempRow["Modified"] = tempLabel; tempLabel = new Label(); tempLabel.Padding = new Thickness(2, 0, 2, 0); tempLabel.Content = tempDirInfo.LastAccessTime.ToLongDateString() + ", " + tempDirInfo.LastAccessTime.ToLongTimeString(); tempRow["Accessed"] = tempLabel; tempRow["Location"] = tempDirInfo.FullName; data_table.Rows.Add(tempRow); } } } private void PopulateFiles(string[] files) { for (int i = 0; i  1048576) { tempRow["Size"] = "" + fileSize / 1048576 + " MB"; } else if (fileSize > 1024) { tempRow["Size"] = "" + fileSize / 1024 + " KB"; } else { tempRow["Size"] = "" + fileSize + " B"; } tempLabel = new Label(); tempLabel.Padding = new Thickness(2, 0, 2, 0); tempLabel.Content = tempFileInfo.CreationTime.ToLongDateString() + ", " + tempFileInfo.CreationTime.ToLongTimeString(); tempRow["Created"] = tempLabel; tempLabel = new Label(); tempLabel.Padding = new Thickness(2, 0, 2, 0); tempLabel.Content = tempFileInfo.LastWriteTime.ToLongDateString() + ", " + tempFileInfo.LastWriteTime.ToLongTimeString(); tempRow["Modified"] = tempLabel; tempLabel = new Label(); tempLabel.Padding = new Thickness(2, 0, 2, 0); tempLabel.Content = tempFileInfo.LastAccessTime.ToLongDateString() + ", " + tempFileInfo.LastAccessTime.ToLongTimeString(); tempRow["Accessed"] = tempLabel; tempRow["Location"] = tempFileInfo.DirectoryName; data_table.Rows.Add(tempRow); } } } private string GetSelectedPath(TreeViewItem selectedNode) { return selectedNode.Tag as string; } private void PopulateFileList() { PopulateDirectories(Directory.GetDirectories(GetSelectedPath((TreeViewItem)Dir_Tree.SelectedItem))); PopulateFiles(Directory.GetFiles(GetSelectedPath((TreeViewItem)Dir_Tree.SelectedItem))); } private void UpdateFileList() { LoadingWheel.Visibility = System.Windows.Visibility.Visible; CreateFileTable(); PopulateFileList(); TxtFoundCount.Text = "Files/Folders Found: " + File_List.Items.Count; LoadingWheel.Visibility = System.Windows.Visibility.Hidden; } 

Я попытался использовать BackgroundWorker и вызвать метод UpdateFileList () внутри него, но мне не повезло.

EDIT: Ниже мой код для BackgroundWorker.

 private BackgroundWorker bgWorker1; private void InitializeBackgroundWorker() { bgWorker1 = new BackgroundWorker(); bgWorker1.DoWork += new DoWorkEventHandler(bgWorker1_DoWork); bgWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker1_RunWorkerCompleted); } private void bgWorker1_DoWork(object sender, DoWorkEventArgs e) { if (Dispatcher.CheckAccess()) { PopulateFileList(); } else { Dispatcher.Invoke(new Action(() => PopulateFileList())); } } private void bgWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { TxtFoundCount.Text = "Files/Folders Found: " + File_List.Items.Count; LoadingWheel.Visibility = System.Windows.Visibility.Hidden; } private void UpdateFileList() { LoadingWheel.Visibility = System.Windows.Visibility.Visible; CreateFileTable(); bgWorker1.RunWorkerAsync(); } 

У меня есть событие SelectionChanged в TreeView, которое вызывает InitializeBackgroundWorker () и UpdateFileList (). Список загружается по-прежнему, и я не получаю никаких ошибок, но анимация загрузки никогда не становится видимой.

Любая помощь будет принята с благодарностью.

Благодарю.

Существует только один stream пользовательского интерфейса. Что вам нужно сделать, так это загрузить данные в DataTable в другой stream.

Если вы хотите показать прогресс загрузки DataTable по пути (прямо или через ProgressBar или какой-либо другой механизм), BackgroundWorker – довольно простой способ сделать это.

ОБНОВЛЕНИЕ: Очень простой пример рабочего стола
Вот довольно простой пример. Он добавляет 100 случайных чисел в коллекцию, приостанавливая stream в течение короткого промежутка времени между каждым, чтобы имитировать длительный процесс загрузки. Вы можете просто вырезать и вставить его в собственный тестовый проект, чтобы увидеть, как он работает.

Дело в том, что тяжелая работа (материал, который занимает некоторое время) выполняется в DoWork, в то время как все обновления пользовательского интерфейса выполняются в ProgressChanged и RunWorkerCompleted. Фактически в обработчике DoWork создается отдельный список (числа), поскольку глобальная коллекция mNumbers находится в streamе пользовательского интерфейса и не может взаимодействовать в обработчике DoWork.

XAML

  

C # Code-Behind

 BackgroundWorker bgWorker = new BackgroundWorker(); ObservableCollection mNumbers = new ObservableCollection(); public Window1() { InitializeComponent(); bgWorker.DoWork += new DoWorkEventHandler(bgWorker_DoWork); bgWorker.ProgressChanged += new ProgressChangedEventHandler(bgWorker_ProgressChanged); bgWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted); bgWorker.WorkerReportsProgress = true; btnGenerateNumbers.Click += (s, e) => UpdateNumbers(); this.DataContext = this; } void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) { progress.Visibility = Visibility.Collapsed; lstItems.Opacity = 1d; btnGenerateNumbers.IsEnabled = true; } void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e) { List numbers = (List)e.UserState; foreach (int number in numbers) { mNumbers.Add(number); } progress.Value = e.ProgressPercentage; } void bgWorker_DoWork(object sender, DoWorkEventArgs e) { Random rnd = new Random(); List numbers = new List(10); for (int i = 1; i <= 100; i++) { // Add a random number numbers.Add(rnd.Next()); // Sleep from 1/8 of a second to 1 second Thread.Sleep(rnd.Next(125, 1000)); // Every 10 iterations, report progress if ((i % 10) == 0) { bgWorker.ReportProgress(i, numbers.ToList()); numbers.Clear(); } } } public ObservableCollection NumberItems { get { return mNumbers; } } private void UpdateNumbers() { btnGenerateNumbers.IsEnabled = false; mNumbers.Clear(); progress.Value = 0; progress.Visibility = Visibility.Visible; lstItems.Opacity = 0.5; bgWorker.RunWorkerAsync(); } 

Я написал небольшую тестовую программу, которая показывает использование classа Dispatcher. Это просто требует WPF-Window и ListBox с именем «listBox». Должно быть легко применить это решение к вашей проблеме.

  public void Populate() { // for comparison, freezing the ui thread for (int i = 0; i < 1000000; i++) { listBox.Items.Add(i); } } private delegate void AddItemDelegate(int item); public void PopulateAsync() { // create a new thread which is iterating the elements new System.Threading.Thread(new System.Threading.ThreadStart(delegate() { // inside the new thread: iterate the elements for (int i = 0; i < 1000000; i++) { // use the dispatcher to "queue" the insertion of elements into the UI-Thread // DispatcherPriority.Background ensures Animations have a higher Priority and the UI does not freeze // possible enhancement: group the "jobs" to small units to enhance the performance listBox.Dispatcher.Invoke(new AddItemDelegate(delegate(int item) { listBox.Items.Add(item); }), System.Windows.Threading.DispatcherPriority.Background, i); } })).Start(); } 
  • Как сделать блокировку с несколькими чтениями / одиночной записью из более простых примитивов синхронизации?
  • оператор присваивания '=' атомный?
  • Какие операции являются атомарными в C #?
  • Нужно ли блокировать или маркировать как изменчивые при доступе к простому булевому флагом в C #?
  • Может ли num ++ быть атомарным для 'int num'?
  • Почему объект блокировки должен быть статическим?
  • Записи чтения / записи в C ++
  • Насколько дорого стоит инструкция блокировки?
  • Давайте будем гением компьютера.