在行为之前触发树视图项目的视觉选择

本文关键字:项目 视图 视觉 选择 | 更新日期: 2023-09-27 18:18:08

我最近开始使用wpf。我有一个简单的树视图与OnSelectedItemChanged事件:

private void Treeview1_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
       Thread.Sleep(1000);
    }

我得到的当前工作流:

  1. 用户点击树视图项。
  2. 代码睡觉。
  3. 树视图项被直观地选中。

这是一个非常无响应的工作流程。我需要的是:

  1. 用户点击树视图项。
  2. 树视图项被直观地选中。
  3. 代码睡觉。

我能以某种方式触发视觉点击选择吗?

在行为之前触发树视图项目的视觉选择

可以。
您所要做的就是不要阻塞UI线程,以便Dispatcher可以选择TreeViewItem

最好的方法可能是在事件处理程序中使用async/await。如果您不使用MVVM,并且需要直接操作您的UI元素,您可以这样做:

private async void Treeview1_OnSelectedItemChanged(object sender,
    RoutedPropertyChangedEventArgs<object> e)
{
    // TreeViewItem gets selected immediately.
    // Now let's do some background work, for example getting some data.
    await Task.Run(() => DoSomeBackgroundWork());
    // And fill the DataGrid with the results.
    // Thanks to async/await we're already in the dispatcher thread again.
    dataGrid.Items.Add(...);
}
private void DoSomeBackgroundWork()
{
    // Simulate some blocking synchronous work.
    Thread.Sleep(1000);
}

如果您使用带有数据绑定的MVVM(我强烈推荐),那么您可能不需要在调度程序线程中填充ViewModel的内容。
相反,您可以在async上下文中执行此操作,然后从上面告诉await,之后不需要切换到调度程序线程的上下文:

await Task.Run(() => DoSomeBackgroundWork())
    .ConfigureAwait(continueOnCapturedContext: false);
myViewModel.Items.Add(...);

但是请注意,您很可能还需要应用某种形式的并发安全性,因为如果用户快速单击多个TreeViewItems,则无法保证多个Task.Run()不会相互干扰。

有许多方法可以确保并发安全性(从存储在字段或属性中的简单volatile标志开始),但是要在这一个答案中包含所有内容,那就太多了。
例如,你可以看看斯蒂芬·克利里。关于这个主题,他写了一些非常棒的文章。
或者Stephen Toub,他与。net中异步编程的实现密切相关。

作为一般建议,您应该尝试在分派器线程中尽可能少地执行操作。只做绝对需要的操作,比如直接修改UI元素。