代码之家  ›  专栏  ›  技术社区  ›  Timores

WPF:如何通过编程给出键盘焦点在列表框中的视觉反馈?

  •  3
  • Timores  · 技术社区  · 14 年前

    我正在编写一个应用程序,其中的列表框允许多个选择(SelectionMode=Multiple);列表框中的项是配方的成分。

    不幸的是,单击一个列表框项会选择此项,这可能是不需要的。我想要以下场景:

    • 用户单击列表框以选择列表框(列表框本身,而不是项)
    • 用户滚动到右边的项目并选择它

    我所做的是设置ListBoxItem的样式,使其包含一个复选框和一个ContentPresenter(比如 in this blog ). 不过,点击配料名称也会选择它。 因此,我将MouseDown事件捕获到包含成分名称的文本块上,找到底层ListBoxItem,对其调用Focus()并将事件的Handled属性设置为true。

    现在,Listbox项具有焦点,但未选中。使用向上和向下键显示焦点在正确的项目上。 我的问题是用户看不到他点击了正确的项目。此项上不显示虚线矩形。 结果如下:

    alt text

    以下是我想要的:

    alt text

    我试过调用私有WPF方法,比如KeyboardNavigation.ShowFocusVisual,我试过将击键发送到列表框(当由人完成时,按右光标键或Alt键会显示虚线矩形)。

    知道吗?

    2 回复  |  直到 14 年前
        1
  •  4
  •   Fredrik Hedblad    14 年前

    SendInput是我找到的唯一一个可以通过它的方法。从 this 链接。

    PInvoke发送输入这是 模拟输入的官方方式。它 通过所有 预期的代码路径,并且是 无法与实际输入区分开。

    一个简单的使用方法是 InputSimulator 来自CodePlex。

    添加对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中添加自己的FocusVisualStyle。(从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>
    
        2
  •  0
  •   Aleksei Poliakov    12 年前

    我发现Meleak的答案很有帮助,但是使用GotFocus对我不起作用。相反,我将偶数处理程序绑定到PreviewMouseLeftButtonDown偶数。现在不需要布尔属性来存储状态,代码非常简单:

        void SlideCanvasPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
                InputSimulator.SimulateKeyDown(VirtualKeyCode.TAB);
                InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.SHIFT, VirtualKeyCode.TAB);  
        }
    

    这对我很有好处。

    P.S.I使用 this 样式-它有一些移动虚线矩形的精细动画