在行为之前触发Treeview项目的视觉选择?

时间:2016-11-16 14:37:33

标签: c# .net wpf treeview

我最近开始使用wpf。我有一个简单的TreeView和OnSelectedItemChanged事件:

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

我得到的当前工作流程:

  1. 用户点击TreeView项目。
  2. 代码睡眠。
  3. 以可视方式选择TreeView项目。
  4. 这是非常无响应的工作流程。我需要的是:

    1. 用户点击TreeView项目。
    2. 以可视方式选择TreeView项目。
    3. 代码睡眠。
    4. 我能否以某种方式立即触发视觉点击选择?

1 个答案:

答案 0 :(得分:0)

是的,你可以。
您所要做的就是不阻止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()赢得& #39; t相互干扰。

有许多方法可以确保并发安全性(从只存储在字段或属性中的简单易失性标志开始)但这样做太多了,只能在这一个答案中包含所有内容。
例如,您可以查看Stephen Cleary。他写了一些关于这个主题的非常精彩的文章 或者Stephen Toub与.NET中异步编程的实现密切相关。

作为一般建议,您应尽量在调度程序线程中尽量少做。只做只需要它的操作,比如直接修改UI元素。