c# - 当项目模板化时,如何捕获 ListboxItem 上的单击?

标签 c# wpf xaml

我有一个设置了 ItemsTemplate 的列表框。

现在我想捕获 Ctrl + 左键单击 ListBoxItem。

我发现 KeyBoard 类应该为我提供修饰键。现在如何获取 ListBoxItem 上的单击事件?更好的是,如何将它绑定(bind)到 ICommand。

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

最佳答案

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

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;
    }
}

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

编辑:

为了解决您的评论,处理 ListBoxItem 的 Click 事件会有点棘手,因为有两件事:1) ListBoxItem 没有单击事件,2) ListBoxItem 在内部处理一些 MouseEvents。不管怎样,我想出了一个模拟的、附加的 ClickEvent 来让它工作。见下文。希望它有效。

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 加载并在代码隐藏中附加事件处理程序。

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!");
    }
}

关于c# - 当项目模板化时,如何捕获 ListboxItem 上的单击?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3981857/

相关文章:

c# - 在 C# 中以编程方式调整 wpf 窗口的大小

c# - XAML:基于实际宽度的可见性在网格中表现得很奇怪

c# - C#中删除JavaScript创建的本地存储的方法

C# Visual Studio 2010 嵌入 exe 图标

c# - 使用 C# 从 ASP.Net MVC 访问 Active Directory

wpf - 需要能够退出 Alt 键下划线模式,可能使用 ESC 键

xaml - 如何在 Windows Phone 8.1 Silverlight 应用程序中将颜色代码分组到一个文件中

c# - 使用 LINQ 获取特定子类型的列表条目

c# - 我可以通过剪贴板将 [Serializable] 对象传递到 Excel 加载项吗?

c# - 按名称杀死线程