为了说明这个选中的问题,先创建了一个界面
<Window.Resources>
<Style x:Key="editableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="LightGray" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Plum" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox
Grid.Column="0"
Name="lbNation"
Margin="2, 2, 4, 2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Path=Nations}"
SelectedItem="{Binding Path=SelectedNation}"
ItemContainerStyle="{StaticResource editableListBoxItemStyle}">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border
BorderThickness="1"
BorderBrush="Black"
Background="White">
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Margin="1">
<ItemsPresenter Margin="10"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<TextBox
Margin="4"
Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
<ListBox
Grid.Column="1"
Name="lbPerson"
Margin="2, 2, 4, 2"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Path=SelectedNation.Members}"
SelectedItem="{Binding Path=SelectedPerson}"
ItemContainerStyle="{StaticResource editableListBoxItemStyle}">
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border
BorderThickness="1"
BorderBrush="Black"
Background="White">
<ScrollViewer
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
Margin="1">
<ItemsPresenter Margin="10"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<TextBox
Margin="4"
Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
</Grid>
左边的Listbox中包含一个TextBox,选中左边ListBoxItem某项后右边会出现姓名列表
我想要实现选中TextBox后,同时能选中ListBoxItem这个对象,但是事与愿违,TextBox 具有焦点,但未选择 ListBoxItem。效果如下:
开始行动:
实验一: 在 ListBoxItem 的 Style.Triggers 中添加IsKeyboardFocusWithin
<Window.Resources>
<Style x:Key="editableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<!--追加-->
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="LightGray" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Plum" />
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
会这种方法可以实现ListBoxItem 与 TexBox 的焦点一起被选中。右侧的成员列表也已更新。
但是当焦点转移到另一个控件时,ListBox 的 SelectedItem 绑定变为空。回顾第一次操作检查。在实现 IsKeyboardFocusWithin 触发器之前,即使焦点丢失,选择信息也会保留。在这种情况下,使用 IsKeyboardFocusWithin 设置标志似乎是不够的。
实验2:Behaviors方法
在stackoverflow上也搜到了类似的问题,发现一个采用Behaviors实现的方法,似乎可以通用所有控件,先创建一个类,代码如下:
using System.Windows;
using System.Windows.Controls.Primitives;
namespace Sample.Behaviors
{
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 的样式更改如下:
<Style x:Key="editableListBoxItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--追加-->
<Setter Property="bh:AutoSelectWhenAnyChildGetsFocus.Enabled" Value="True"></Setter>
<Style.Triggers>
<!--废弃-->
<!--<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True"/>
</Trigger>-->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="LightBlue" />
</Trigger>
<Trigger Property="IsMouseOver" Value="False">
<Setter Property="Background" Value="LightGray" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="Plum" />
</Trigger>
</Style.Triggers>
</Style>
现在运行。ListBoxItem 是与TextBox 的焦点一起选择的。
失去焦点后
完美解决问题!!