当项目被模板化时如何捕捉点击 ListboxItem ? [英] How to catch Click on ListboxItem when the item is templated?

查看:18
本文介绍了当项目被模板化时如何捕捉点击 ListboxItem ?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个设置了 ItemsTemplate 的 ListBox.

I have a ListBox with ItemsTemplate set.

现在我想在 ListBoxItem 上按 Ctrl + 左键单击.

Now I want to catch Ctrl + Left click on a ListBoxItem.

我发现 KeyBoard 类应该给我修饰键.现在如何获取 ListBoxItem 上的点击事件?更好的是,我如何将它绑定到 ICommand.

I found KeyBoard class that should give me modifier keys. Now how do I get the click event on the ListBoxItem? Even better, how do I bind it to ICommand.

我发现了一些零碎的东西,但不知道如何连接它们.看来 InputBinding 似乎可以帮助我或 EventSetter.

I found some bits and pieces but don't know how to connect them. It seems InputBinding seems could help me or EventSetter.

推荐答案

下面是一个使用 ListBoxItem 样式中的 EventSetter 处理 Ctrl + PreviewMouseLeftButtonDown 的简单示例.这可能就是您想要的.

Below is a simple example that handles Ctrl + PreviewMouseLeftButtonDown using an EventSetter in the ListBoxItem's Style. This is probably what you want.

XAML:

<ListBox>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="ListBoxItem_PreviewMouseLeftButtonDown"/>
        </Style>
    </ListBox.ItemContainerStyle>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Button Content="{Binding}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
    <s:String>Item1</s:String>
    <s:String>Item2</s:String>
    <s:String>Item3</s:String>
    <s:String>Item4</s:String>
</ListBox>

代码隐藏:

void ListBoxItem_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    if ((Keyboard.Modifiers & ModifierKeys.Control) > 0)
    {
        Console.WriteLine((sender as ListBoxItem).Content.ToString());
        e.Handled = false;
    }
}

要将其绑定到 ICommand,您可以使用附加行为,例如讨论的 EventToCommand 行为此处.

To bind it to an ICommand, you can use an attached behavior like the EventToCommand behavior discussed here.

为了解决您的评论,对于 ListBoxItem 处理 Click 事件会有点棘手,因为有两个原因:1) ListBoxItem 没有单击事件,以及 2) ListBoxItem 在内部处理一些 MouseEvents.无论如何,我想出了一个模拟的附加 ClickEvent 来使其工作.见下文.希望它有效.

To address your comment, handling the Click-event will be a bit tricky for the ListBoxItem because of two things: 1) The ListBoxItem doesn't have a click event, and 2) The ListBoxItem internally handles some of the MouseEvents. Anyway, I came up with a simulated, attached ClickEvent to make it work. See below. Hope it works.

public class AttachedEvents
{
    private static readonly DependencyProperty IsTriggerEnabledProperty =
        DependencyProperty.RegisterAttached("IsTriggerEnabled", typeof(bool), typeof(FrameworkElement), new FrameworkPropertyMetadata(false));

    public static readonly RoutedEvent ClickEvent;

    static AttachedEvents()
    {
        try
        {
            ClickEvent = EventManager.RegisterRoutedEvent("Click",
                                                        RoutingStrategy.Bubble,
                                                        typeof(RoutedEventHandler),
                                                        typeof(FrameworkElement));
        }
        catch (Exception ex)
        { }
    }


    private static void SetIsTriggerEnabled(FrameworkElement element, bool value)
    {
        if (element != null)
        {
            element.SetValue(IsTriggerEnabledProperty, value);
        }
    }

    private static bool GetIsTriggerEnabled(FrameworkElement element)
    {
        return (element != null) ? (bool)element.GetValue(IsTriggerEnabledProperty) : false;
    }

    public static void AddClickHandler(DependencyObject o, RoutedEventHandler handler)
    {
        FrameworkElement element = (FrameworkElement)o;
        element.AddHandler(ClickEvent, handler);
        element.MouseLeftButtonUp += new System.Windows.Input.MouseButtonEventHandler(SimulatedClick_MouseLeftButtonUp);
        element.PreviewMouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(SimulatedClick_MouseLeftButtonDown);
    }

    public static void RemoveClickHandler(DependencyObject o, RoutedEventHandler handler)
    {
        FrameworkElement element = (FrameworkElement)o;
        element.RemoveHandler(ClickEvent, handler);
        element.MouseLeftButtonUp -= new System.Windows.Input.MouseButtonEventHandler(SimulatedClick_MouseLeftButtonUp);
        element.PreviewMouseLeftButtonDown -= new System.Windows.Input.MouseButtonEventHandler(SimulatedClick_MouseLeftButtonDown);
    }

    static void SimulatedClick_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;
        UpdateIsTriggerSet(element);
        Mouse.Capture(element);
    }

    static void SimulatedClick_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
        FrameworkElement element = (FrameworkElement)sender;

        bool isTriggerSet = (bool)element.GetValue(IsTriggerEnabledProperty);

        // update the trigger set flag
        UpdateIsTriggerSet(element);

        //release the mouse capture
        Mouse.Capture(null);

        // if trigger is set and we are still over the element then we fire the click event
        if (isTriggerSet && IsMouseOver(element))
        {
            element.RaiseEvent(new RoutedEventArgs(ClickEvent, sender));
        }

    }

    private static bool IsMouseOver(FrameworkElement element)
    {
        Point position = Mouse.PrimaryDevice.GetPosition(element);
        if (((position.X >= 0.0) && (position.X <= element.ActualWidth)) && ((position.Y >= 0.0) && (position.Y <= element.ActualHeight)))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private static void UpdateIsTriggerSet(FrameworkElement element)
    {
        Point position = Mouse.PrimaryDevice.GetPosition(element);
        if (((position.X >= 0.0) && (position.X <= element.ActualWidth)) && ((position.Y >= 0.0) && (position.Y <= element.ActualHeight)))
        {
            if (!(bool)element.GetValue(IsTriggerEnabledProperty))
            {
                element.SetValue(IsTriggerEnabledProperty, true);
            }
        }
        else if ((bool)element.GetValue(IsTriggerEnabledProperty))
        {
            element.SetValue(IsTriggerEnabledProperty, false);
        }
    }
}

示例用法如下所示.我似乎无法在 XAML 中设置附加事件(我不确定为什么),所以我不得不在这里做一个解决方法.我所做的是等待直到 ListBoxItem 被加载并在代码隐藏中附加事件处理程序.

Sample usage is shown below. I can't seem to set the attached event in XAML (I'm not sure why) so I had to do a workaround here. What I do is wait 'til the ListBoxItem gets loaded and Attach the event handler in the code-behind.

XAML:

<ListBox>
    <ListBox.ItemContainerStyle>
        <Style TargetType="ListBoxItem">
            <EventSetter Event="Loaded" Handler="OnLoaded"/>
        </Style>
    </ListBox.ItemContainerStyle>
...
</ListBox>

代码隐藏:

void OnLoaded(object sender, RoutedEventArgs e)
{
    AttachedEvents.AddClickHandler((sender as ListBoxItem), HandleClick);
}

void HandleClick(object sender, RoutedEventArgs e) 
{
    if ((Keyboard.Modifiers & ModifierKeys.Control) > 0)
    {
        Console.WriteLine("Ctrl + Clicked!");
    }
}

这篇关于当项目被模板化时如何捕捉点击 ListboxItem ?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆