【问题标题】:WPF MVVM updating ObservableCollection from ThreadpoolWPF MVVM 从线程池更新 ObservableCollection
【发布时间】:2023-04-06 17:54:01
【问题描述】:

我读到我从后台工作线程(使用 Task.Run())更新可观察集合的实现可能不是线程安全的。

在我的应用程序中,我有一个 ListView 绑定到一个可观察集合,所选项目也双向绑定到我的视图模型。当应用程序空闲时,我让这个 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 属性更改?

任何见解或建议将不胜感激。

【问题讨论】:

    标签: c# wpf mvvm observablecollection


    【解决方案1】:

    首先,您不需要调用对SelectedTaskWorkflowTasks 的更改,因为您通过数据绑定来使用它们,这本身就是异步的。通常访问该集合就可以了。

    由于您编写了可以手动调用 WorkflowTask 的更新机制,因此将它们包装在 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);
            }
        }
    

    【讨论】:

    • 感谢您为我解决这个问题。也许在我的阅读中,我在 WPF 与代码背后与 MVVM 之间进行了交叉。我认为你是对的,我应该引入锁以避免重叠 fetch 调用的可能性。
    猜你喜欢
    • 1970-01-01
    • 2011-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-06-03
    • 2021-08-31
    • 2014-01-15
    相关资源
    最近更新 更多