问题描述
我正在编写一个带有允许多选的列表框的应用程序(SelectionMode = Multiple);盒中的物品是食谱的原料.
不幸的是,单击列表框项目会选择此项目,这可能是不希望的.我想要以下情形:
- 用户单击列表框以选择列表框(列表框本身,而不是项目)
- 用户滚动到右边的项目并选择它
我所做的就是设置ListBoxItem的样式,使其包括一个复选框和一个ContentPresenter(例如此博客中).仍然,单击成分名称将其选中.因此,我将MouseDown事件捕获在包含成分名称的文本块上,找到底层的ListBoxItem,在其上调用Focus()并将事件的Handled属性设置为true.
现在,列表框"项目具有焦点,但未选中.使用向上和向下键显示焦点在正确的项目上.我的问题是用户看不到他单击了正确的项目.虚线矩形未显示在此项上.结果如下:
这就是我想要的:
我曾尝试调用私有的WPF方法,例如KeyboardNavigation.ShowFocusVisual,我曾尝试将击键发送到列表框(当由人操作时,按右光标键或Alt键将显示虚线矩形). /p>
有什么主意吗?
SendInput是我发现的唯一超越此方法的方法.通过此链接.
一种简单的使用方法是使用CodePlex中的 InputSimulator .
添加对InputSimulator.dll的引用,我们可以执行以下操作
private bool m_waitingForFocusVisualStyle = false;
private void ListBoxItem_GotFocus(object sender, RoutedEventArgs e)
{
if (m_waitingForFocusVisualStyle == false)
{
m_waitingForFocusVisualStyle = true;
InputSimulator.SimulateKeyDown(VirtualKeyCode.TAB);
InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.SHIFT, VirtualKeyCode.TAB);
}
else
{
m_waitingForFocusVisualStyle = false;
}
}
但是由于许多原因,这可能并不理想(例如,将Shift + Tab转换为ListBoxItem)
一个更好的主意可能是删除ListBoxItem的FocusVisualStyle并像这样在ControlTemplate中添加您自己的. (从Blend复制,并从标准FocusVisualStyle添加了"FocusVisualStyle")
<ListBox ...>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template" Value="{StaticResource ListBoxItemTemplate}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<ControlTemplate x:Key="ListBoxItemTemplate" TargetType="{x:Type ListBoxItem}">
<Grid>
<Rectangle Grid.ZIndex="1"
Name="focusVisualStyle"
StrokeThickness="1"
Stroke="Black"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"
Visibility="Hidden"/>
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="focusVisualStyle" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="Selector.IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
I am writing an application with a listbox allowing multi-selection (SelectionMode=Multiple); the items in the lisbox are ingredients for a recipe.
Unfortunately, clicking on a listbox item selects this item, which may not be desired. I would like the following scenario:
- the user clicks on the listbox in order to select the listbox (the listbox itself, not an item)
- the user scrolls to the right item and selects it
What I did is style the ListBoxItem to include a checkbox and a ContentPresenter (like in this blog).Still, clicking on the ingredient name selects it.So, I trap the MouseDown event on the textblock containing the ingredient name, find the underlying ListBoxItem, call Focus() on it and set the Handled property of the event to true.
Now, the Listbox item has the focus but is not selected. Using the up and down keys shows that the focus was on the right item.My problem is that the user cannot see that he has clicked on the right item. The dotted rectangle is not shown on this item.Here is the result:
And here is what I'd like:
I've tried calling private WPF methods, like KeyboardNavigation.ShowFocusVisual, I've tried sending keystrokes to the listbox (when done by a human, pressing the right cursor key or the Alt key makes the dotted rectangle appear).
Any idea ?
SendInput is the only way I've found which gets past this. From this link.
An easy way to use this is with InputSimulator from CodePlex.
Adding a reference to InputSimulator.dll we can do something like this
private bool m_waitingForFocusVisualStyle = false;
private void ListBoxItem_GotFocus(object sender, RoutedEventArgs e)
{
if (m_waitingForFocusVisualStyle == false)
{
m_waitingForFocusVisualStyle = true;
InputSimulator.SimulateKeyDown(VirtualKeyCode.TAB);
InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.SHIFT, VirtualKeyCode.TAB);
}
else
{
m_waitingForFocusVisualStyle = false;
}
}
But this might not be ideal for a lot of reasons (Shift+Tab to the ListBoxItem for example)
A better idea is probably to remove the FocusVisualStyle for ListBoxItem and add your own in the ControlTemplate like this. (Copied from Blend and added a "FocusVisualStyle" from standard FocusVisualStyle)
<ListBox ...>
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Template" Value="{StaticResource ListBoxItemTemplate}" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<ControlTemplate x:Key="ListBoxItemTemplate" TargetType="{x:Type ListBoxItem}">
<Grid>
<Rectangle Grid.ZIndex="1"
Name="focusVisualStyle"
StrokeThickness="1"
Stroke="Black"
StrokeDashArray="1 2"
SnapsToDevicePixels="true"
Visibility="Hidden"/>
<Border x:Name="Bd"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}"
SnapsToDevicePixels="true">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="focusVisualStyle" Property="Visibility" Value="Visible"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="Selector.IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
这篇关于WPF:如何以编程方式给出键盘焦点在列表框中的视觉反馈?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!