VirtualTreeView: правильная обработка изменений выбора

Этот вопрос покажется очевидным тем, кто сам не сталкивался с проблемой.

Мне нужно обработать изменения выбора в VTV. У меня есть плоский список узлов. Мне нужно делать что-то со всеми выбранными в данный момент узлами всякий раз, когда

  1. Пользователь щелкает узел;
  2. Пользователь, удерживая нажатой клавишу Shift / Ctrl, щелкает узел;
  3. Пользователь использует клавиши со стрелками для перемещения по списку;
  4. Пользователь создает выбор, перетаскивание мышью
  5. Пользователь снимает выделение, щелкнув пустое место или щелкнув с нажатой клавишей Ctrl только выбранный узел

и т. д. Это наиболее распространенное и ожидаемое поведение, как и в проводнике Windows: когда вы выбираете файлы с помощью мыши и / или клавиатуры, на информационной панели отображаются их свойства. Больше мне ничего не нужно. И здесь я застрял.

Ниже приводятся некоторые из моих исследований.


Сначала я использовал OnChange. Казалось, что это работает хорошо, но я заметил какое-то странное мерцание и обнаружил, что в наиболее распространенном сценарии (выбран один узел, пользователь щелкает другой) OnChange запускается дважды:

  1. Когда старый узел не выбран. На данный момент выбор пуст. Я обновляю свой графический интерфейс, чтобы вместо всех свойств отображалась метка «ничего не выбрано».
  2. Когда выбран новый узел. Я снова обновляю свой графический интерфейс, чтобы показать свойства нового узла. Отсюда и мерцание.

Эта проблема была доступна в Google, поэтому я обнаружил, что люди используют OnFocusChange и OnFocusChanging вместо OnChange. Но этот способ работает только для одиночного выбора. С множественным выбором, перетаскиванием и клавишами навигации это не работает. В некоторых случаях события Focus даже не срабатывают (например, когда выбор снимается щелчком по пустому пространству).

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

C   OnChange
FC  OnFocusChange
FCg OnFocusChanging
-   nil parameter
*   non-nil parameter
!   valid selection


Nodes     User action                   Handlers fired (in order)
selected                
0     Click node                    FCg-*   C*!     
1     Click same                    FCg**           
1     Click another                 C-  FCg**   C*! FC*
1     Ctlr + Click  same            FCg**   C*!     
1     Ctrl + Click another          FCg**   C*! FC* 
1     Shift + Click same            FCg**   C*!     
1     Shift + Click another         FCg**   C-! FC* 
N     Click focused selected        C-! FCg**       
N     Click unfocused selected      C-! FCg**   FC* 
N     Click unselected              C-  FCg**   C*! FC*
N     Ctrl + Click unselected       FCg**   C*! FC* 
N     Ctrl + Click focused          FCg**   C*!         
N     Shift + Click unselected      FCg**   C-! FC* 
N     Shift + Click focused         FCg**   C-!         
1     Arrow                         FCg**   FC* C-  C*!
1     Shift + Arrow                 FCg**   FC* C*! 
N     Arrow                         FCg**   FC* C-  C*!
N     Shift + Arrow (less)          C*! FCg**   FC* 
N     Shift + Arrow (more)          FCg**   FC* C*! 
Any   Ctrl/Shift + Drag (more)      C*! C-!     
0     Click empty                   -           
1/N   Click Empty                   C-!         
N     Ctrl/Shift + Drag (less)      C-!         
1     Ctrl/Shift + Drag (less)      C-!         
0     Arrow                         FCg**   FC* C*!

Это довольно сложно читать. В двух словах говорится, что в зависимости от конкретного действия пользователя три обработчика (OnChange, OnFocusChange и OnFocusChanging) вызываются в случайном порядке со случайными параметрами. FC и FCg иногда никогда не вызываются, когда мне все еще нужно обработать событие, поэтому очевидно, что я должен использовать OnChange.

Но следующая задача: внутри OnChange я не могу знать, следует ли мне использовать этот вызов или ждать следующего. Иногда набор выбранных узлов является промежуточным и бесполезным, и его обработка вызывает мерцание графического интерфейса пользователя и / или нежелательные тяжелые вычисления.

Мне нужны только те вызовы, которые отмечены знаком "!" в таблице выше. Но отличить их изнутри нет возможности. Например: если я нахожусь в "C-" (OnChange, Node = nil, SelectedCount = 0), это может означать, что пользователь удалил выделение (тогда мне нужно обработать его) или что они щелкнули другой узел (тогда мне нужно подождать следующий вызов OnChange при формировании новой выборки).


В любом случае, я надеюсь, что в моем исследовании не было необходимости.Я надеюсь, что я упускаю что-то, что сделало бы решение простым и понятным, и что вы, ребята, собираетесь указать мне на это. Решение этой головоломки с использованием того, что у меня есть до сих пор, привело бы к ужасно ненадежной и сложной логике.

Заранее спасибо!

11
задан 13x666 3 November 2011 в 13:32
поделиться