Combobox仅通过鼠标或Enter键选择项目

时间:2011-10-11 12:30:39

标签: wpf combobox

我有一个WPF ComboBox
我需要在弹出列表中更改默认行为。

现在,通过按updownSelectedItem会自动更改 我只需按SelectedItem键或点击鼠标即可更改Enter

怎么做?

我已经分组ComboBox

protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
{
    Debug.Write("Pressed " + e.Key+ " ");
    if (e.Key == System.Windows.Input.Key.Up || e.Key == System.Windows.Input.Key.Down)
    {
        // ???
        e.Handled = true;
        return;
    }
    base.OnPreviewKeyDown(e);
}

此代码不起作用 - 未显示弹出窗口,用户无法选择项目。 我写什么,在哪里? :)

感谢。

UPD1:

我需要与ComboBox's弹出窗口相同的功能,用户可以通过鼠标选择项目 每个项目都可以通过鼠标悬停,但不会被选中。只需按下鼠标按钮即可进行选择。我需要同样的东西。 “向上”和“向下”仅突出显示弹出窗口中的项目,但只有按SelectedItem或鼠标单击才能更改Enter

UPD2: 如果我按下鼠标按钮,在ComboCox中打开Popup,我可以用鼠标突出显示Popup中的项目,但只有当我点击项目时,SelectedItem才会改变。

键盘需要相同的功能。如果我在ComboBox中开始输入,Popup会打开。我必须通过键盘UpDown高亮显示项目。 ComboBox中的TextBox在突出显示期间不得更改,且只有在按Enter(或鼠标单击)时,SelectedItem才能更改

UPD3: 链接到演示解决方案:download

6 个答案:

答案 0 :(得分:2)

您应该在组合框中的所有ComboBoxItem上处理此事件。

   <ComboBox.Resources>
        <Style TargetType="{x:Type ComboBoxItem}">
           <EventSetter Event="PreviewKeyDown" Handler="OnPreviewKeyDown" />
        </Style> 
  </ComboBox.Resources>

修改

在代码背后,您可以在InitializeComponent()执行此操作后在MyComboBox的构造函数中添加以下代码...

  var comboBoxItemstyle = new Style(typeof (ComboBoxItem));  
  comboBoxItemstyle.Setters.Add(
        new EventSetter(PreviewKeyDownEvent,
                new KeyEventHandler(OnPreviewKeyDown)));
  this.Resources.Add(typeof (ComboBoxItem), comboBoxItemstyle);

希望这有帮助。

答案 1 :(得分:2)

您拥有的代码似乎工作正常,只需在取消关键事件之前添加一项检查以查看DropDown是否已打开

protected override void OnPreviewKeyDown(KeyEventArgs e)
{
    Debug.Write("Pressed " + e.Key + " ");
    if (!base.IsDropDownOpen && (e.Key == Key.Up || e.Key == Key.Down))
    {
        e.Handled = true;
        return;
    }
    base.OnPreviewKeyDown(e);
}

答案 2 :(得分:0)

在我看来,你应该创建属性 - IsKeyNavigation(如IsMouseOver)

protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e)
{
    Debug.Write("Pressed " + e.Key+ " ");
    if (e.Key == System.Windows.Input.Key.Up || e.Key == System.Windows.Input.Key.Down)
    {
        VisualStateManager.GoToState(this, "KeyNavigation", true);
        e.Handled = true;
        return;
    }
    base.OnPreviewKeyDown(e);
}

如果按下Key.Up或Key.Down,您应该定义导航元素并更改VisualState。

答案 3 :(得分:0)

这是适合我的解决方案 -

public class CustomComboBox : ComboBox
{
    private int _currentItemIndex;
    private string _rowColor = "#E7E7E7";
    private string _selectedRowColor = "#FFFFC6";        

    protected override void OnDropDownOpened(EventArgs e)
    {
        _currentItemIndex = base.SelectedIndex;
        base.OnDropDownOpened(e);
    }

    protected override void OnPreviewKeyDown(KeyEventArgs e)
    {
        if (base.IsDropDownOpen)
        {
            if (e.Key == Key.Up || e.Key == Key.Down)
            {
                ComboBoxItem currentItem;
                var colorConverter = new BrushConverter();

                if (_currentItemIndex > -1 && _currentItemIndex != base.SelectedIndex)
                {
                    currentItem = (ComboBoxItem)base.ItemContainerGenerator.ContainerFromIndex(_currentItemIndex);
                    currentItem.Background = (Brush)colorConverter.ConvertFromString(_rowColor);
                }

                if (e.Key == Key.Up)
                {
                    _currentItemIndex -= 1;
                    if (_currentItemIndex < 0)
                    {
                        _currentItemIndex = 0;
                    }
                }
                else if (e.Key == Key.Down)
                {
                    _currentItemIndex += 1;
                    if (_currentItemIndex > base.Items.Count - 1)
                    {
                        _currentItemIndex = base.Items.Count - 1;
                    }
                }

                currentItem = (ComboBoxItem)base.ItemContainerGenerator.ContainerFromIndex(_currentItemIndex);
                currentItem.Background = (Brush)colorConverter.ConvertFromString(_selectedRowColor);
                currentItem.BringIntoView();

                e.Handled = true;
                return;
            }
            else if (e.Key == Key.Enter)
            {
                base.SelectedItem = base.Items[_currentItemIndex];
            }
        }
        base.OnPreviewKeyDown(e);
    }

    protected override void OnDropDownClosed(EventArgs e)
    {
        if (_currentItemIndex > -1 && base.Items[_currentItemIndex] != base.SelectedItem)
        {
            var colorConverter = new BrushConverter();
            ComboBoxItem currentItem = (ComboBoxItem)base.ItemContainerGenerator.ContainerFromIndex(_currentItemIndex);
            currentItem.Background = (Brush)colorConverter.ConvertFromString(_rowColor);
        }
        base.OnDropDownClosed(e);
    }
}

答案 4 :(得分:0)

最好使用ComboBox。 OnDropDownClosed (EventArgs)方法

https://docs.microsoft.com/de-de/dotnet/api/system.windows.forms.combobox.ondropdownclosed?view=netframework-4.7.2#System_Windows_Forms_ComboBox_OnDropDownClosed_System_EventArgs_

PS:对于Infracistics控件(UltraComboEditor),它是OnAfterCloseUp事件。

答案 5 :(得分:0)

安装nuget软件包System.Windows.Interactivity.WPF,创建一个如下所示的类(注意:左/右箭头也会更改封闭的焦点ComboBox中的选择):

public class ComboBoxCustomBehaviour: Behavior<ComboBox>
{
    private readonly ISet<Key> _dropdownBlockedKeys = new HashSet<Key>{Key.Up, Key.Down, Key.Left, Key.Right};

    protected override void OnAttached()
    {
        AssociatedObject.PreviewKeyDown += AssociatedObject_KeyDown;
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PreviewKeyDown -= AssociatedObject_KeyDown;
    }

    private void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
    {
        if (_dropdownBlockedKeys.Contains(e.Key))
            e.Handled = true;
        // Use following line, when you need to stop selection only on closed ComboBox
        // e.Handled = !((ComboBox)sender).IsDropDownOpen;
    }
}

将此行为类添加到xaml:

<ComboBox>
    <ComboBoxItem>Item 1</ComboBoxItem>
    <ComboBoxItem>Item 2</ComboBoxItem>
    <ComboBoxItem>Item 3</ComboBoxItem>
    <i:Interaction.Behaviors>
        <local:ComboBoxCustomBehaviour />
    </i:Interaction.Behaviors>
</ComboBox>