Shane
Shane

Reputation: 2351

Overriding mouse over behaviour in WPF combo box

When the list is dropped down an the mouse hovers over an item in the drop-down list, the item becomes highlighted but the selected value shown in the text box does not change unless the item is clicked. I am looking for a way to modify the mouse over behavior in a control that inherits from ComboBox. I tried overriding function like OnMouseEnter & OnMouseMove etc.

Upvotes: 1

Views: 1952

Answers (3)

FabioDch
FabioDch

Reputation: 514

This is how I solved the same issue in my code, hopefull that it could be usefull for someone else, or just a steps toward a full xaml solution.

I followed the Quartermeister's solution. But In my opinion, the need subclassing ComboBox is a design weakness (because this is done just for handling the MouseOver event). Because I need just for a different behaviour of the MouseOver event, I implemented just the method which handles MouseOver events in the class attached to XAML file.

First of all, I used the EventSetter class, which subclass the Setter class and it's specific for Events. So EventSetter can be used to decorate FrameworkElements as we usually do with Setter.

<ComboBox>
    <ComboBox.ItemContainerStyle>
        <Style TargetType="{x:Type ComboBoxItem}">
            <EventSetter Event="MouseMove" Handler="_updateModel"/>
        </Style>
    </ComboBox.ItemContainerStyle>
</ComboBox>

In this way, every ComboBoxItem calls _updateModel when the mouse hovers it.

My implementation of _updateModel is quite straight, it's based strongly on the work of Quartermeister:

private void _updateModel(object sender, MouseEventArgs e)
{
    DependencyObject src = e.Source as DependencyObject;
    ComboBoxItem cbi = VisualTreeHelper.GetParent(src) as ComboBoxItem;
    while ((cbi == null) && (src!=null))
    {
        src = VisualTreeHelper.GetParent(src);
        cbi = src as ComboBoxItem;
    }
    if (cbi != null)
    {
        ComboBox cb = ItemsControl.ItemsControlFromItemContainer(cbi) as ComboBox;
        if (cb != null)
        {
            var container = cb.ContainerFromElement((DependencyObject)e.OriginalSource);
            if (container != null)
            {
                cb.SelectedItem = cb.ItemContainerGenerator.ItemFromContainer(container);
            }
        }
    }
}

Other ways to solve the same issues can use blend's behaviors for reasons that aren't worth to explain here, i couldn't use that behaviors.

Upvotes: 1

Quartermeister
Quartermeister

Reputation: 59139

You can do it by overriding OnMouseMove. The OriginalSource property of the MouseEventArgs will give you the element directly under the mouse. You can use ContainerFromElement to get the ComboBoxItem that contains that element and then ItemContainerGenerator.ItemFromContainer to get the item to select:

protected override void OnMouseMove(MouseEventArgs e)
{
    base.OnMouseMove(e);
    var container = ContainerFromElement((DependencyObject)e.OriginalSource);
    if (container != null)
    {
        SelectedItem = ItemContainerGenerator.ItemFromContainer(container);
    }
}

Upvotes: 2

Wallstreet Programmer
Wallstreet Programmer

Reputation: 9677

Instead create your own control using a TextBlock, a ToggleButton with an arrow and a ListBox. Show the Listbox when the ToggleButton is checked. When user do mouse over a listboxitem, change the text in the Textbox and update some property for selected item or fire an event.

Upvotes: 0

Related Questions