如何解决如何在可观察集合的 UI 中立即反映任何添加、删除、字段更改
让我的 Observable 集合的更改(添加、删除、字段更改)立即显示在我的 TableView UI 中时遇到了真正的问题。
我写了一个小程序来测试功能。它可以工作,但不会立即反映更改,它会等到所有添加、删除、更改完成后才显示结果。
我希望它显示发生的每个变化。即,如果我添加一条记录,它会立即显示更改。用户界面应向下滚动屏幕以显示添加。
在我的代码中,我包含了添加、删除和更改之间的睡眠来证明这一点。
我需要做什么才能立即反映所有更改(添加、删除、字段更改)?
附上我的一些代码。
namespace ObservableTest
{
internal static class Common
{
public static ObservableCollection OC = new ObservableCollection();
public static void AddRecords(int HowMany = 100)
{
for(int i = 0; i < HowMany; i++)
{
OC.Add(new TestObservable("StringData " + i.ToString(),i));
Thread.Sleep(1000); // Sleep to see outcome in UI
}
}
public static void RemoveRecords(int HowMany = 5)
{
var data = OC.ToList();
foreach(var field in data)
{
if(field.IntField < HowMany)
{
OC.Remove(field);
Thread.Sleep(1000); // Sleep to see outcome in UI
}
}
}
public static void ChangeRecords(int HowMany = 5)
{
var data = OC.ToList();
foreach(var field in data)
{
field.StringField += " C";
Thread.Sleep(1000); // Sleep to see outcome in UI
}
}
}
public class TestObservable : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{ this.PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propName)); }
private string stringField = "";
private int intField = 0;
public TestObservable(string StringField,int IntField)
{
this.stringField = StringField;
this.intField = IntField;
}
public string StringField
{
get { return stringField; }
set
{
if (this.stringField != value)
{
this.stringField = value;
this.NotifyPropertyChanged("StringField");
}
}
}
public int IntField
{
get { return intField; }
set
{
if (this.intField != value)
{
this.intField = value;
this.NotifyPropertyChanged("IntField");
}
}
}
}
}
解决方法
您应该异步执行阻塞代码。
要将您的示例转换为异步,只需将阻塞 Thread.Sleep
替换为非阻塞 Task.Delay
。
重点是 Thread.Sleep 确实阻塞了 UI 线程。当 UI 线程处于休眠状态时,它无法执行任何其他操作,例如渲染更改。
Thread.Sleep 不谈:当您的阻塞(同步)代码异步执行时,您允许 UI 线程保持响应。 UI 线程将能够在执行异步代码时呈现视图中的更改。
internal static class Common
{
public static ObservableCollection<TestObservable> OC = new ObservableCollection<TestObservable>();
public static async Task AddRecords(int HowMany = 100)
{
for (int i = 0; i < HowMany; i++)
{
OC.Add(new TestObservable("StringData " + i.ToString(),i));
await Task.Delay(1000); // Sleep to see outcome in UI
}
}
public static async Task RemoveRecords(int HowMany = 5)
{
var data = OC.ToList();
foreach (var field in data)
{
if (field.IntField < HowMany)
{
OC.Remove(field);
await Task.Delay(1000); // Sleep to see outcome in UI
}
}
}
public static async Task ChangeRecords(int HowMany = 5)
{
var data = OC.ToList();
foreach (var field in data)
{
field.StringField += " C";
await Task.Delay(1000); // Sleep to see outcome in UI
}
}
}
,
您需要使用异步方法。
所有长时间运行的工作都应该在线程池上执行的任务中进行。
并且只有直接改变WPF View中绑定的集合才应该发生在应用程序的主线程上。
要在主线程上执行操作,首先需要获取它,然后通过它的方法委托将它放入执行队列。
放入队列后,您可以等待它们的执行完成(如我的示例),但您也可以跳过等待并立即继续进一步处理。
这取决于您正在实施的算法以及处理结果的需要。
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Threading;
namespace ObservableTest
{
public static class Common
{
public static ObservableCollection<TestObservable> OC { get; }
= new ObservableCollection<TestObservable>();
public static Dispatcher Dispatcher { get; } = Application.Current.Dispatcher;
private static readonly Action<TestObservable> AddRecord = OC.Add;
private static readonly Func<TestObservable,bool> RemoveRecord = OC.Remove;
private static readonly Action<int,TestObservable> ReplaceRecord = (index,item) => OC[index] = item;
// Synchronous method. It is undesirable to call it from the UI thread.
public static void AddRecords(int howMany = 100)
{
for (int i = 0; i < howMany; i++)
{
TestObservable test = new TestObservable("StringData " + i.ToString(),i);
DispatcherOperation operation = Dispatcher.BeginInvoke(AddRecord,test);
DispatcherOperationStatus status = operation.Wait();
Thread.Sleep(1000); // Sleep to see outcome in UI
}
}
// Asynchronous method. It can be called from the UI thread.
public static async void AddRecordsAsync(int howMany = 100)
=> await Task.Run(() => AddRecords(howMany));
public static void RemoveRecords(int howMany = 5)
{
var data = OC.ToList();
foreach (TestObservable field in data)
{
if (field.IntField < howMany)
{
DispatcherOperation operation = Dispatcher.BeginInvoke(RemoveRecord,field);
DispatcherOperationStatus status = operation.Wait();
Thread.Sleep(1000); // Sleep to see outcome in UI
}
}
}
public static async void RemoveRecordsAsync(int howMany = 5)
=> await Task.Run(() => RemoveRecords(howMany));
public static void ChangeRecords(int howMany = 5)
{
var data = OC.ToList();
foreach (TestObservable field in data)
{
field.StringField += " C";
Thread.Sleep(1000); // Sleep to see outcome in UI
}
}
public static async void ChangeRecordsAsync(int howMany = 5)
=> await Task.Run(() => ChangeRecords(howMany));
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。