«Когда я добавляю этот триггер, элемент выбирается, когда фокус находится на дочернем текстовом поле, но первое поведение исчезает. Теперь, когда я щелкаю за пределами списка, элемент отменяется».
На самом деле, я не думаю, что он утратил свое первоначальное поведение. Я подозреваю, что происходит то, что вы щелкаете непосредственно в текстовом поле откуда-то еще, поэтому базовый элемент ListBoxItem никогда не был выбран. Однако, если бы это было так, вы бы увидели, что выбор все равно останется после того, как вы уйдете, как хотите.
Вы можете проверить это, заставив элемент ListBoxItem быть выбранным, щелкнув его непосредственно (примечание: вы всегда должны давать ему фон, даже если он просто «прозрачный», чтобы он мог получать щелчки мыши, чего не будет, если он нулевой ) или даже просто нажав «Shift-Tab», чтобы установить фокус туда, обратно из текстового поля.
Однако это не решает вашу проблему, заключающуюся в том, что TextBox получает фокус, но не позволяет базовому элементу ListBoxItem знать об этом.
Два подхода, которые вы можете использовать для этого, — это триггер события или присоединенное поведение.
Первый — это триггер события IsKeyboardFocusWithinChanged, где вы устанавливаете для IsSelected значение true, если фокус клавиатуры изменился на true. (Примечание: ответ Шеридана делает уведомление об искусственном изменении, но его не следует использовать в случаях, когда вы можете выбрать несколько элементов в списке, потому что все становится выбранным.) Но даже триггер события вызывает проблемы, потому что вы теряете поведение множественного выбора например, переключение или щелчок по диапазону и т. д.
Другой (и мой предпочтительный подход) состоит в том, чтобы написать прикрепленное поведение, которое вы устанавливаете в ListBoxItem, либо напрямую, либо через стиль, если хотите.
Вот прикрепленное поведение. Примечание. Вам снова нужно будет обрабатывать материал с множественным выбором, если вы хотите это реализовать. Также обратите внимание, что хотя я привязываю поведение к ListBoxItem, внутри я привожу к UIElement. Таким образом, вы также можете использовать его в ComboBoxItem, TreeViewItem и т. д. Практически любой ContainerItem в элементе управления на основе селектора.
public class AutoSelectWhenAnyChildGetsFocus
{
public static readonly DependencyProperty EnabledProperty = DependencyProperty.RegisterAttached(
"Enabled",
typeof(bool),
typeof(AutoSelectWhenAnyChildGetsFocus),
new UIPropertyMetadata(false, Enabled_Changed));
public static bool GetEnabled(DependencyObject obj){ return (bool)obj.GetValue(EnabledProperty); }
public static void SetEnabled(DependencyObject obj, bool value){ obj.SetValue(EnabledProperty, value); }
private static void Enabled_Changed(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
var attachEvents = (bool)e.NewValue;
var targetUiElement = (UIElement)sender;
if(attachEvents)
targetUiElement.IsKeyboardFocusWithinChanged += TargetUiElement_IsKeyboardFocusWithinChanged;
else
targetUiElement.IsKeyboardFocusWithinChanged -= TargetUiElement_IsKeyboardFocusWithinChanged;
}
static void TargetUiElement_IsKeyboardFocusWithinChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var targetUiElement = (UIElement)sender;
if(targetUiElement.IsKeyboardFocusWithin)
Selector.SetIsSelected(targetUiElement, true);
}
}
... и вы просто добавляете это как установщик свойств в свой стиль ListBoxItem
<Setter Property="behaviors:AutoSelectWhenAnyChildGetsFocus.Enabled" Value="True" />
Это, конечно, предполагает, что вы импортировали пространство имен XML под названием «behaviors», которое указывает на пространство имен, в котором содержится класс. Вы можете поместить сам класс в общую вспомогательную библиотеку, что мы и делаем. Таким образом, везде, где мы этого хотим, это простое свойство, заданное в XAML, а поведение позаботится обо всем остальном.
person
Mark A. Donohoe
schedule
05.10.2012