2013-07-12 3 views
0

У нас есть TreeView в нашем приложении со следующими требованиями:Как выполнять последовательные вызовы BringIntoView в WPF?

Когда элемент добавляется:

  1. Вновь добавленный элемент прокручивается в поле зрения
  2. Родитель вновь добавленного элемента является также прокручивается в поле зрения.
  3. Если они слишком далеко, чтобы оба были замечены одновременно, элемент имеет приоритет.

Это кажется простым, просто сначала прокрутите родительский элемент, а затем прокрутите его.

Проблема заключается в том, когда вы называете это так:

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

... только второй один, кажется, никакого эффекта. Первый в основном игнорируется.

Затем я попытался обертыванием второго вызова в BeginInvoke() вызова, как это:

parent.BringIntoView(); 

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

Который делает работу, но теперь вы можете наглядно увидеть TreeView свиток дважды; один раз для родителя, затем через мгновение, для ребенка, который выглядит просто плохо.

Так как я могу позвонить BringIntoView назад, но без проблемы с повторным обновлением использования диспетчера?

ответ

0

Попробуйте использовать событие Loaded вместо диспетчера. По словам this article, он идеально подходит для ситуаций, как это:

... мы сначала реализовали Loaded событие, так что он будет стрелять только после того, как окно было вынесено, но перед любым входом был обработан. Мы полагали, что если он был достаточно готов для ввода, то был готов к инициализации времени загрузки. Но затем мы начали триггерные анимации с события Loaded и увидели проблему; для секунд вы увидите рендеринг содержимого без анимации, затем вы увидите начало анимации. Возможно, вы не всегда это заметили, но это было особенно заметно при удаленном запуске приложения.

Итак, мы переместили Загружено так, что теперь он запускается после компоновки и привязки данных, имеет шанс на запуск, но перед первым рендерингом. (И заметьте, что если вы сделать что-нибудь в вашем Loaded обработчика событий, лишает законной силы расположение, может быть необходимо повторно запустить его перед визуализацией.)

Другими словами, на Loaded вы имеете самую датируйте информацию о физическом макете элемента, но он пока не отобразился, поэтому вы должны быть в безопасности от любых «мерцаний экрана».

EDIT: Для того, чтобы ответить на ваш вопрос в комментариях, вы можете подключить до события «локального» в текущий метод, используя замыкание, например:

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

Определяя обработчик внутри метода, вы можете получить доступ к локальным переменным метода (child) изнутри. Очень похоже на звонок Dispatcher.

Я не уверен, что, полагаясь на LayoutUpdated, это хорошая идея. Это случается довольно часто, поэтому может закончиться стрельбой раньше, чем вам нужно. Это случается дважды для отдельных настроек Width и Height, например. Еще один, который нужно посмотреть, - ScrollViewer.ScrollChanged. Или вы можете вообще избежать BringIntoView и попробовать вручную изучить размеры элементов, чтобы рассчитать, где их можно прокрутить.

+0

Код, который я пробовал, фактически * в * загруженном событии для узла, но это не проблема. Опять же, проблема заключается в обратном вызове BringIntoView, где первый из них в основном узурпирован вторым и оказывается неэффективным. – MarqueIV

+0

Тем не менее, я считаю, что ваше решение отложить второй вызов имеет смысл. Проблема в том, что он слишком долго задерживается, и это происходит после рендеринга (вызывая видимость двойного обновления). Если Loaded уже произошло, попробуйте [LayoutUpdated] (http://msdn.microsoft.com/en-us/library/system.windows.uielement.layoutupdated.aspx). – nmclean

+0

Но это его собственное событие. Помните ... это действие запускается пользователем. Можете ли вы показать мне, как бы вы подключили это, чтобы вы могли ответить пользователю, а затем ответить на системное событие как часть той же транзакции. – MarqueIV

Смежные вопросы