如何在WPF中执行顺序BringIntoView调用?

时间:2013-07-12 22:26:26

标签: c# wpf scroll

我们的应用程序中有TreeView符合以下要求:

添加项目时:

  1. 新添加的项目滚动到视图
  2. 新添加项目的父级也会滚动到视图中。
  3. 如果它们距离太远而无法同时看到,则该项目优先。
  4. 这看起来很简单,只需先将父级滚动到视图中,然后滚动子级。

    问题在于你这样称呼它:

    parent.BringIntoView();
    child.BringIntoView();
    

    ......只有第二个似乎有任何影响。第一个基本上被忽略了。

    然后我尝试在BeginInvoke()这样的电话中打包第二个电话:

    parent.BringIntoView();
    
    Dispatcher.BeginInvoke((Action)(() => {
        child.BringIntoView();
    }));
    

    哪个确实有效,但现在你可以看到TreeView两次滚动;一次为父母,一会儿之后,对于那个看起来很糟糕的孩子。

    那么我如何能够背靠背调用BringIntoView但没有使用调度程序的双重刷新问题?

1 个答案:

答案 0 :(得分:0)

尝试使用Loaded事件而不是调度程序。根据{{​​3}},它非常适合这样的情况:

  

...我们最初实现了Loaded事件   它会在窗口渲染之后,但在任何输入之前触发   被处理了。我们认为,如果它足够准备输入,它   已准备好足以进行加载时初始化。但后来我们开始了   触发Loaded事件的动画,并看到问题;为一个   然后,拆分秒,你会看到没有动画的内容渲染   你会看到动画开始。你可能并不总是注意到它,但它   当您远程运行应用程序时,这一点尤为明显。

     

所以我们感动了   加载,以便它现在在布局和数据绑定之后触发了   有机会跑,但就在第一次渲染之前。 (并注意如果   你在Loaded事件处理程序中做任何使布局无效的事情,   在渲染之前可能需要重新运行它。)

换句话说,在Loaded上你有关于元素物理布局的最新信息,但它实际上还没有渲染,所以你应该避免任何“屏幕闪烁”问题。

编辑:要在评论中回答您的问题,您可以使用闭包将事件“local”连接到当前方法,如下所示:

EventHandler handler = null;
handler = (sender, e) => {
    this.LayoutUpdated -= handler;  // only run once
    child.BringIntoView();
};
this.LayoutUpdated += handler;

通过在方法内定义处理程序,您可以从内部访问方法的局部变量(child)。与Dispatcher电话非常相似。

实际上,我不确定依靠LayoutUpdated是否是一个好主意。它经常发生,所以它可能会比你需要的更快地射击。例如,对于单个WidthHeight设置,它会发生两次。另一个要研究的是this article。或者您可以完全避免BringIntoView并尝试手动检查元素大小以计算滚动到的位置。