ОБНОВЛЕНИЕ: Итак, у меня есть решение моей непосредственной проблемы.Мне не удалось создать "свой" класс TreeView
.Но причина, по которой я хотел это сделать, заключалась в том, что элементы управления, основанные на ButtonBase
, не работают в Popup
из TreeView
, и с помощью @MarkFeldman я нашел решение, которое приходит к нему отдругой угол.
Проблема состоит в том, что события MouseDown
и MouseUp
всплывают, и это переплетение пересекает границу логического дерева между Popup
и его владельцем.Итак, когда вы нажимаете на что-то, размещенное внутри Popup
, TreeViewItem
и TreeView
, которые в конечном итоге владеют Popup
, узнают об этом.Затем он запускает код внутри TreeView
, который проверяет «Есть ли у меня фокус?», А если нет, услужливо возвращает себе фокус - но, будучи отдельным логическим деревом, Popup
имеетего собственный контекст фокуса, и поэтому он эффективно крадет фокус у элемента управления Button
, когда он находится в середине обработки щелчка.Button
реагирует на это, игнорируя щелчок.
Эта ошибочная обработка в TreeView
происходит только при достижении событий MouseDown
и MouseUp
.Что если бы был какой-то способ помешать ему увидеть эти события?Что ж, если вы перехватываете события PreviewMouseDown
и PreviewMouseUp
и помечаете их Handled
, то фреймворк не генерирует события MouseDown
и MouseUp
для начала.
Глядя на справочный источник, похоже, что обработка кликов ButtonBase
связана с парой protected
методов:
https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,414 https://referencesource.microsoft.com/#PresentationFramework/src/Framework/System/Windows/Controls/Primitives/ButtonBase.cs,478
Это означает, что вы можете вызывать их из ваших собственных подклассов!Таким образом, вместо создания «своего» * 1045 *, где все элементы управления работают должным образом, вместо этого я могу создать «свой» CheckBox
, который работает правильно в Popup
из TreeView
.Поскольку вся фактическая обработка кликов доступна напрямую, и события, которые она обычно отвечает на использование того же типа EventArgs
, что и события Preview
, и поверх нее обработка по умолчанию заботится о маркировкесобытия Handled
, вся реализация сводится к следующему:
public class CheckBoxThatWorks : CheckBox
{
protected override void OnPreviewMouseLeftButtonDown(MouseButtonEventArgs e) => base.OnMouseLeftButtonDown(e);
protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) => base.OnMouseLeftButtonUp(e);
}
Отлично!
ОРИГИНАЛЬНЫЙ ВОПРОС:
Мне нужно сделать клонкласса TreeView
WPF - копия элемента управления, который работает из моего собственного кода.(В элементе управления есть ошибка, и Microsoft, похоже, не считает ее достаточно высоким приоритетом для исправления, и она делает невозможным размещение кнопок (включая флажки и переключатели) во всплывающих окнах, показанных в TreeViewItem
s. link )
Я столкнулся с серьезными трудностями из-за количества internal
махинаций, которые Microsoft предприняла при реализации базовых элементов управления WPF.Несколько проблем, с которыми я столкнулся:
Элементы управления имеют свойство HandlesScrolling
, которое позволяет им перенять базовую обработку прокрутки с ScrollViewer
.Но он помечен internal
, что делает для меня невозможным иметь собственный элемент управления, который самостоятельно обрабатывает прокрутку с клавиатуры.Я собирался сделать так, чтобы моя TreeView
управляла прокруткой клавиатуры в OnPreviewKeyDown
вместо OnKeyDown
, чтобы он мог предотвратить возникновение событий KeyDown
для клавиш, которые он перехватывает.Я не дошел до того, чтобы знать, какие предостережения могут быть по этому поводу.
Система визуальных состояний позволяет вам объявлять, какие стили следует применять при входе в разные состояния, но на самом делевходящие состояния, кажется, связаны виртуальным методом ChangeVisualState
типа Control
.Все элементы управления, которые хотят переключаться между визуальными состояниями, могут переопределять этот метод и проверять свое состояние, чтобы определить, какое визуальное состояние должно отображаться.Ой, подожди.Они не могут, потому что метод internal
!Очевидно, только Microsoft может создавать элементы управления, которые устанавливают свои собственные визуальные состояния ??
Есть ли какие-либо стратегии, которые я могу использовать, чтобы обойти эти ограничения, или мне просто не повезло?