3

Is there a way I can implement Click on a ListBoxItem? There is MouseLeftButtonUp but its not really the same, I can mouse down elsewhere and drag into another ListBoxItem and it still works, minor problem tho, it maybe weird for users tho

Jiew Meng
  • 84,767
  • 185
  • 495
  • 805

2 Answers2

4

I deleted this answer because I realized that this is way to much for this simple task, but then I thought I'll post it anyway in case someone wants to know how to subclass ListBoxItem for whatever reason.

To really get a Click event from a ListBoxItem you'll have to do the following. First subclass ListBoxItem and check MouseEnter, MouseLeave, MouseUp, MouseDown to know when to fire it.

public class ClickableListBoxItem : ListBoxItem
{
    // Register the routed event
    public static readonly RoutedEvent ClickEvent = 
        EventManager.RegisterRoutedEvent( "Click", RoutingStrategy.Bubble, 
        typeof(RoutedEventHandler), typeof(ClickableListBoxItem));

    // .NET wrapper
    public event RoutedEventHandler Click
    {
        add
        {
            AddHandler(ClickEvent, value);
        } 
        remove
        {
            RemoveHandler(ClickEvent, value);
        }
    }

    protected void OnClick()
    {
        RaiseEvent(new RoutedEventArgs(ClickEvent));
    }

    private bool m_isClickable = false;
    private bool m_click = false;
    protected override void OnMouseEnter(System.Windows.Input.MouseEventArgs e)
    {
        m_isClickable = true;
        base.OnMouseEnter(e);
    }
    protected override void OnMouseLeave(System.Windows.Input.MouseEventArgs e)
    {
        m_isClickable = false;
        base.OnMouseLeave(e);
    }
    protected override void OnPreviewMouseLeftButtonUp(System.Windows.Input.MouseButtonEventArgs e)
    {
        if (m_click == true)
        {
            OnClick();
        }
        base.OnPreviewMouseLeftButtonUp(e);
    }
    protected override void OnPreviewMouseLeftButtonDown(System.Windows.Input.MouseButtonEventArgs e)
    {
        if (m_isClickable == true)
        {
            m_click = true;
        }
        base.OnPreviewMouseLeftButtonDown(e);
    }
}

To get the ListBox to use ClickableListBoxItem instead of ListBoxItem we must also subclass ListBox and override GetContainerForItemOverride.

public class ClickableListBox : ListBox
{
    protected override DependencyObject GetContainerForItemOverride() 
    {
        //Use our own ListBoxItem 
        return new ClickableListBoxItem(); 
    }
}

Then we can use this ClickableListBox in Xaml and get the Click event like this. This will work no mather what you put in the ItemTemplate, Buttons, TextBoxes, TextBlocks etc.

<local:ClickableListBox x:Name="c_listBox">
    <local:ClickableListBox.ItemContainerStyle>
        <Style TargetType="{x:Type local:ClickableListBoxItem}">
            <EventSetter Event="Click" Handler="ListBoxItem_Click"/>
        </Style>
    </local:ClickableListBox.ItemContainerStyle>
</local:ClickableListBox>

An easier solution would be to just subclass the Parent container in the ItemTemplate for the ListBoxItem and use the same Mouse routines.

Fredrik Hedblad
  • 83,499
  • 23
  • 264
  • 266
2

You could make a new ControlTemplate for the ListBoxItem with something clickable as the root-element (like a Button), handle the click-event on that and place the ContentPresenter inside the 'clickable'?

Goblin
  • 7,970
  • 3
  • 36
  • 40
  • I guess that's 1 solution, I'll just wait to see if there are other solutions, else this will be marked as answer – Jiew Meng Nov 11 '10 at 07:48