UWP:使用键盘箭头

时间:2018-04-08 11:56:47

标签: c# listview uwp listviewitem

我有一个AutoSuggestBox。当我输入内容时,它会给我一个"建议"的列表。该列表是Popup中的ListView。无论哪种方式,我都希望禁用列表中的某些项目,因此用户无法选择它们。

我做得很好,我的实现如下:

<AutoSuggestBox x:Name="AutoSuggest" ...
                ItemContainerStyle="{StaticResource 
                MyPopUpListViewItemStyle}"
/>


<Style x:Key="MyPopUpListViewItemStyle" TargetType="ListViewItem">
...
        <Setter Property="helpers:SetterValueBindingHelper.PropertyBinding">
            <Setter.Value>
                <helpers:SetterValueBindingHelper
                    Property="IsEnabled"
                    Binding="{Binding Path=Content.IsItemEnabled, RelativeSource={RelativeSource Self}}" />
            </Setter.Value>
        </Setter>
...
</Style>

我在样式中绑定属性时遇到了一些问题。但是现在一切正常,ListViewItems&#39; &#34;的IsEnabled&#34;属性绑定到其内容中的属性。所以现在,用户无法用鼠标选择特定项目。

我的问题是!虽然用户不能用鼠标选择项目,但他仍然可以使用向上↑和向下↓箭头选择它(并且不仅仅选择它们,而实际上选择回车)。我希望用户跳过禁用的项目(仍然可以使用箭头选择常规项目。)

我搜索了很长一段时间,我确实找到了一个很好看的解决方案,可以绑定&#34; Focusable&#34;从ListViewItem属性到我自己的属性,但它只是WPF,因为那里没有&#34;可聚焦&#34;我的ListViewItem的属性。

所有可能的ListViewItem属性,包括:&#34; AllowFocusOnInteraction&#34;,&#34; IsTabStop&#34;,&#34; AllowFocusWhenDisabled&#34;,&#34; IsHitTestVisible&#34;和其他逻辑相关的东西都没有用。

1 个答案:

答案 0 :(得分:0)

经过几个小时的挣扎后,我找到了解决问题的方法。该解决方案与我在问题中发布的方式有所不同。它不会跳过禁用的项目(当遇到带箭头键的禁用项目时跳过第一个启用的项目)。相反,它允许用户像其他任何人一样突出显示禁用的项目,但它不允许他用&#34; Enter&#34;键。无论哪种方式,用户都可以理解该项目已被禁用,首先是因为它是灰色的(因为它的&#34; IsEnabled&#34;设置为false),其次,我将文本的前景设置为内部禁用的ItemListView为红色。

不允许用户选择&#34;输入&#34;只需捕捉&#34;输入&#34;在KeyDown方法中返回&#34;没有做任何事情&#34;。问题是在哪里获得所需的KeyDown方法。

我有自己的AutoSuggestBox样式(主要是原来的Windows&#39; AutoSuggestBox,我不记得有人改变任何事情),如下所示:

<Style TargetType="AutoSuggestBox">
    ...
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="AutoSuggestBox">
                <Grid>
                    ...
                    <TextBox x:Name="TextBox" 
                             ...
                             />
                    <Popup x:Name="SuggestionsPopup">
                        <Border x:Name="SuggestionsContainer">
                            <Border.RenderTransform>
                                <TranslateTransform x:Name="UpwardTransform" />
                            </Border.RenderTransform>
                            <ListView
                                x:Name="SuggestionsList"
                                ...
                                >
                                <ListView.ItemContainerTransitions>
                                    <TransitionCollection />
                                </ListView.ItemContainerTransitions>
                            </ListView>
                        </Border>
                    </Popup>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

可以看出,AutoSuggestBox的想法是带有搜索的TextBox,以及与它相同级别的Popup。 Popup包含一个ListView of&#34; advice&#34;根据TextBox上面的文字吧。他们按名字&#34; TextBox&#34; &安培; &#34; SuggestionsList&#34;

TextBox(原始名称&#34; TextBox&#34;)是您想要捕获&#34; KeyDown&#34;的主要元凶。活动到。我们的想法是,当您使用上下箭头键查看建议列表时,您的焦点始终保留在同一文本框中,而不是列表视图或其他任何内容。

所以我所做的就是向TextBox(上面那个样式中的那个)添加一个Behavior,如下所示:

    <TextBox x:Name="TextBox"
             ... >
        <interactivity:Interaction.Behaviors>
            <TheNamespaceContainingClass:BehaviorClassName />
        </interactivity:Interaction.Behaviors>
    </TextBox>

行为类代码: 我添加了几条评论来进一步解释重要部分

public class BehaviorClassName: DependencyObject, IBehavior
{
    private TextBox _associatedObject;
    private ListView _listView;

    public DependencyObject AssociatedObject
    {
        get
        {
            return _associatedObject;
        }
    }

    public void Attach(DependencyObject associatedObject)
    {
        _associatedObject = associatedObject as TextBox;

        if (_associatedObject != null)
        {
            _associatedObject.KeyDown -= TextBox_OnKeyDown;
            _associatedObject.KeyDown += TextBox_OnKeyDown;
        }
    }

    private void TextBox_OnKeyDown(object sender, KeyRoutedEventArgs e)
    {
        if (_associatedObject != null)
        {
            if (_listView == null)
            {
                // Gets ListView through visual tree. That's a hack of course. Had to put it here since the list initializes only after the textbox itself
                _listView = (ListView)((Border)((Popup)((Grid)_associatedObject.Parent).Children[1]).Child).Child;
            }
            if (e.Key == VirtualKey.Enter && _listView.SelectedItem != null)
            {
                // Here I had to make sure the Enter key doesn't work only on specific (disabled) items, and still works on all the others
                // Reflection I had to insert to overcome the missing reference to the needed ViewModel
                if (!((bool)_listView.SelectedItem.GetType().GetProperty("PropertyByWhichIDisableSpecificItems").GetValue(_listView.SelectedItem, null)))
                    e.Handled = true;
            }
        }
    }

    public void Detach()
    {
        _associatedObject.KeyDown -= TextBox_OnKeyDown;
    }
}

这可能不是最简单的解释和解决方案,但问题也不是很简单。如果遇到这个具体问题,希望你能想出整个想法。如果你不遵循MVVM和/或不关心质量,整个问题可以通过更简单的方式解决,但主要思想保持不变。

此外,我在问题中发布的SetterValueBindingHelper来自this博客。非常感谢其作者SuperJMN。