如何解决WPF MVVM 从线程池更新 ObservableCollection
我读到我从后台工作线程(使用 Task.Run())更新可观察集合的实现可能不是线程安全的。
在我的应用程序中,我有一个 ListView 绑定到一个 observable 集合,所选项目也双向绑定到我的视图模型。当应用程序空闲时,我让这个 ListView 每 60 秒更新一次它的值。此更新可以手动触发,因此我将其设计为异步函数,因为它从数据库请求值。当我的控件加载并处于空闲状态时,在 Task.Run() 下运行一个循环函数。
public ObservableCollection<WorkFlowTask> WorkFlowTasks { get; set; }
private WorkFlowTask _SelectedTask;
public WorkFlowTask SelectedTask
{
get
{
return _SelectedTask;
}
set
{
_SelectedTask = value;
OnPropertyChanged("SelectedTask");
}
}
private void SynchTaskList()
{
TokenSourceTaskList = new CancellationTokenSource();
CancelTokenTaskList = TokenSourceTaskList.Token;
Task.Run(() => UpdateTaskList());
}
UpdateTaskList 定义如下:
private async void UpdateTaskList ()
{
while (!CancelTokenTaskList.IsCancellationRequested)
{
List<WorkFlowTask> tasks = await Connector.GetWorkFlowTasksByEmpID(Employee.EmployeeID);
if(SelectedTask != null)
{
//Preserve currently selected item through collection update
SelectedTask = tasks.Where(x => x.TransWorkFlowDetailID == SelectedTask.TransWorkFlowDetailID).FirstOrDefault();
}
var newWorkFlowTasks = new ObservableCollection<WorkFlowTask>(tasks.OrderBy(x => x.DueDate));
if (!WorkFlowTasks.SequenceEqual(newWorkFlowTasks))
{
WorkFlowTasks = newWorkFlowTasks;
}
OnPropertyChanged("WorkFlowTasks");
await Task.Delay(60000);
}
}
在功能上,这按我的预期工作,但我担心这可能不是线程安全的。这是否只是因为我用新对象替换集合而不是修改它?是否需要调用对集合的更新?我是否也应该在 SelectedItem 属性更改周围加锁?
任何见解或建议将不胜感激。
解决方法
首先,您不需要调用对 SelectedTask
和 WorkflowTasks
的更改,因为您通过数据绑定使用它们,数据绑定本身是异步的。通常访问该集合就可以了。
由于您编写了可以手动调用 WorkflowTasks 的更新机制,因此将它们包装在 lock 语句中可能是个好主意。否则,当两个并行任务同时修改 SelectedTask
时,您可能会遇到问题。
我会在获取任务列表后立即放置锁。这样,多个任务可以同时获取列表(我认为这是一项耗时的任务),但会按顺序将结果写入您的属性。
private async void UpdateTaskList()
{
while (!CancelTokenTaskList.IsCancellationRequested)
{
List<WorkFlowTask> tasks = await Connector.GetWorkFlowTasksByEmpID(Employee.EmployeeID);
lock (this.taskListLock)
{
if (SelectedTask != null)
{
//Preserve currently selected item through collection update
SelectedTask = tasks.Where(x => x.TransWorkFlowDetailID == SelectedTask.TransWorkFlowDetailID).FirstOrDefault();
}
var newWorkFlowTasks = new ObservableCollection<WorkFlowTask>(tasks.OrderBy(x => x.DueDate));
if (!WorkFlowTasks.SequenceEqual(newWorkFlowTasks))
{
WorkFlowTasks = newWorkFlowTasks;
}
OnPropertyChanged("WorkFlowTasks");
}
await Task.Delay(60000);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。