jps*_*res 6 wpf listbox listboxitem
我有一个为我定义的样式ListBoxItems
,触发器设置IsSelected
为True 时的背景颜色:
<Style x:Key="StepItemStyle" TargetType="{x:Type ListBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border" Padding="0" SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#40a0f5ff"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Run Code Online (Sandbox Code Playgroud)
这种风格即使在ListBox
和ListBoxItem
失去焦点时也能保持所选项目,在我的情况下绝对是必须的.问题是我还希望ListBoxItem
在其中一个TextBox
孩子得到关注时被选中.为了达到这个目的,我添加了一个触发器,IsSelected
当IsKeyboardFocusWithin
为true 时设置为true:
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter Property="IsSelected" Value="True" />
</Trigger>
Run Code Online (Sandbox Code Playgroud)
当我添加此触发器时,焦点在子节点上时会选择Item TextBox
,但第一个行为会消失.现在当我点击外面时ListBox
,该项目被取消选中.
我怎样才能保持这两种行为?
当您的列表框失去焦点时,它会因您的触发器将所选项设置为null.您可以使用一些代码来选择焦点,这些代码在您失去焦点时不会取消选择.
XAML:
<Window x:Class="SelectedTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<StackPanel>
<TextBox Text="Loose focus here" />
<ListBox Name="_listBox" ItemsSource="{Binding Path=Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" GotFocus="OnChildGotFocus">
<TextBox Text="{Binding .}" Margin="10" />
<TextBox Text="{Binding .}" Margin="10" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border Name="Border" SnapsToDevicePixels="true" Background="Transparent">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</StackPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
代码背后:
private void OnChildGotFocus(object sender, RoutedEventArgs e)
{
_listBox.SelectedItem = (sender as StackPanel).DataContext;
}
Run Code Online (Sandbox Code Playgroud)
"当我添加此触发器时,焦点位于子TextBox上时会选择Item,但第一个行为消失.现在,当我在ListBox外部单击时,该项目将被取消选中."
实际上,我认为它没有失去原有的行为.我怀疑发生的是你从其他地方直接点击文本框,这样底层的ListBoxItem实际上从未被选中.但是,如果确实如此,您会看到在您离开后仍然保留选择.
您可以通过直接单击它来强制选择ListBoxItem来测试它(侧注:你应该总是给它一个背景,即使只是'透明'所以它可以接收鼠标点击,如果它是null,它就不会或者甚至只是点击"Shift-Tab"将焦点设置在那里,从文本框返回.
但是,这并不能解决您的问题,即TextBox获得焦点但不会让底层ListBoxItem知道它.
您可以使用的两种方法是事件触发器或附加行为.
第一个是IsKeyboardFocusWithinChanged事件的事件触发器,如果键盘焦点更改为true,则将"IsSelected"设置为true.(注意:Sheridan的答案会进行虚假更改通知,但不应该用于您可以在列表中进行多选的情况,因为所有内容都会被选中.)但即使是事件触发器也会导致问题,因为您丢失了多选行为例如切换或范围点击等
另一个(以及我的首选方法)是编写一个您在ListBoxItem上直接设置的附加行为,或者如果您愿意,可以通过样式编写.
这是附加的行为.注意:如果要实现,则需要再次处理多选项.另请注意,虽然我将行为附加到ListBoxItem,但我在内部转换为UIElement.这样你也可以在ComboBoxItem,TreeViewItem等中使用它.基本上是基于Selector的控件中的任何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);
}
}
Run Code Online (Sandbox Code Playgroud)
...而你只需在ListBoxItem的样式中将其添加为属性设置器
<Setter Property="behaviors:AutoSelectWhenAnyChildGetsFocus.Enabled" Value="True" />
Run Code Online (Sandbox Code Playgroud)
当然,这假设您已导入名为"behavior"的XML命名空间,该命名空间指向包含该类的命名空间.您可以将类本身放在共享的"Helper"库中,这就是我们所做的.这样,在我们想要它的任何地方,它都是在XAML中设置的简单属性,并且行为会处理其他所有事情.
归档时间: |
|
查看次数: |
7666 次 |
最近记录: |