【问题标题】:Double Click a ListBox item to open a browser双击 ListBox 项以打开浏览器
【发布时间】:2010-10-23 17:19:44
【问题描述】:

我的 wpf 窗口中有一个ListBox,它绑定到一个ObervableCollection。如果有人单击ListBox 的元素(就像链接一样),我想打开浏览器。有人可以告诉我该怎么做吗?我发现了一些带有 listboxviews 的东西,它只能以这种方式工作还是仅使用 ListBox 就可以了?

你的

塞巴斯蒂安

【问题讨论】:

    标签: wpf binding listbox listboxitem


    【解决方案1】:

    您可以在ListBox.ItemContainerStyle 中添加样式,并在此处添加EventSetter

    <ListBox>
        ....
        <ListBox.ItemContainerStyle>
            <Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
                <EventSetter Event="MouseDoubleClick" Handler="ListBoxItem_MouseDoubleClick"/>
            </Style>
        </ListBox.ItemContainerStyle>
    </ListBox>
    

    ListBoxItem_MouseDoubleClick 是您代码中的一个方法,其签名正确为 MouseDoubleClick

    【讨论】:

    • 谢谢。这也解决了我的问题。一个跟进:这在正在运行的应用程序中效果很好,但它会让视觉工作室设计师感到厌烦(不是阻碍,而是令人恼火)。我没有在应用程序资源中明确定义 ListBoxItem 样式,因此 BasedOn 将在设计时失败。但是,我有一个在运行时定义此资源的主题库 (WPFTheme)。如果我确实定义了一个静态资源,它就会消除动态的主题资源。有什么想法可以让两者一起玩得很好吗?
    • 经过更多的实验,我想通了...我只是在合并的资源属性中引用了主题的 xaml: ResourceDictionary.MergedDictionaries>
    • 这很酷,但是如果您已经在 ResourceDictionary 中定义了 ItemContainerStyle 怎么办?
    • 只需在
    • @Bob +1 为缺少双击的简单解决方案。
    【解决方案2】:

    我想解决这个问题,而不需要在代码隐藏中处理 listBoxItem 双击事件,并且我不想重写 listBoxItem 样式(或首先定义要重写的样式)。我只想在双击 listBox 时触发一个命令。

    我像这样创建了一个附加属性(代码很具体,但你可以根据需要概括它):

    public class ControlItemDoubleClick : DependencyObject {
    public ControlItemDoubleClick()
    {
    
    }
    
    public static readonly DependencyProperty ItemsDoubleClickProperty =
        DependencyProperty.RegisterAttached("ItemsDoubleClick",
        typeof(bool), typeof(Binding));
    
    public static void SetItemsDoubleClick(ItemsControl element, bool value)
    {
        element.SetValue(ItemsDoubleClickProperty, value);
    
        if (value)
        {
            element.PreviewMouseDoubleClick += new MouseButtonEventHandler(element_PreviewMouseDoubleClick);
        }
    }
    
    static void element_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        ItemsControl control = sender as ItemsControl;
    
        foreach (InputBinding b in control.InputBindings)
        {
            if (!(b is MouseBinding))
            {
                continue;
            }
    
            if (b.Gesture != null
                && b.Gesture is MouseGesture
                && ((MouseGesture)b.Gesture).MouseAction == MouseAction.LeftDoubleClick
                && b.Command.CanExecute(null))
            {
                b.Command.Execute(null);
                e.Handled = true;
            }
        }
    }
    
    public static bool GetItemsDoubleClick(ItemsControl element)
    {
        return (bool)element.GetValue(ItemsDoubleClickProperty);
    }
    

    }

    然后我用附加的属性和我的目标命令声明我的 ListBox:

    <ListBox ItemsSource="{Binding SomeItems}"
         myStuff:ControlItemDoubleClick.ItemsDoubleClick="true">
    <ListBox.InputBindings>
        <MouseBinding MouseAction="LeftDoubleClick" Command="MyCommand"/>
    </ListBox.InputBindings>
    </ListBox>
    

    希望这会有所帮助。

    【讨论】:

    • 但是如果他们双击滚动条不会触发吗?或者 ListBoxItems 之间的任何填充?
    • 是的,如果您双击列表框中的任意位置,它将触发。对我来说,它仍然是一个很好的解决方案,我喜欢它不需要代码。将 b.Command.CanExecute(null) 和 Execute(null) 的命令参数从 null 更改为 b.CommandParameter。
    【解决方案3】:

    我已经更新了 AndrewS 解决方案,以解决双击列表框中任意位置时触发执行命令的问题:

    public class ControlDoubleClick : DependencyObject
    {
        public static readonly DependencyProperty CommandProperty =
            DependencyProperty.RegisterAttached("Command", typeof(ICommand), typeof(ControlDoubleClick), new PropertyMetadata(OnChangedCommand));
    
        public static ICommand GetCommand(Control target)
        {
            return (ICommand)target.GetValue(CommandProperty);
        }
    
        public static void SetCommand(Control target, ICommand value)
        {
            target.SetValue(CommandProperty, value);
        }
    
        private static void OnChangedCommand(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            Control control = d as Control;
            control.PreviewMouseDoubleClick += new MouseButtonEventHandler(Element_PreviewMouseDoubleClick);
        }
    
        private static void Element_PreviewMouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            Control control = sender as Control;
            ICommand command = GetCommand(control);
    
            if (command.CanExecute(null))
            {
                command.Execute(null);
                e.Handled = true;
            }
        }
    }
    

    在 XAML 中,ListBox 的声明是:

    <ListBox ItemsSource="{Binding MyItemsSource, Mode=OneWay}">                    
          <ListBox.ItemContainerStyle>
                        <Style>                            
                            <Setter Property="behaviours:ControlDoubleClick.Command" Value="{Binding DataContext.MyCommand,
                                        RelativeSource={RelativeSource FindAncestor, 
                                        AncestorType={x:Type UserControl}}}"/>
                         </Style>  
         </ListBox.ItemContainerStyle>
    </ListBox>
    

    【讨论】:

    • 最佳答案在这里!
    • 这是我在尝试了几个选项后独立选择的解决方案,但我稍微更改了绑定:我给了 UserControl 一个 Name,删除了 RelativeSource 搜索,并添加了一个ElementName 用我赋予控制权的名称代替。结果是一样的,但它可能会为那些对控件有很多引用的人节省一些空间/运行时间。
    【解决方案4】:

    我使用了 Expression SDK 4.0

    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    
    <i:Interaction.Triggers>
      <i:EventTrigger EventName="MouseDoubleClick" SourceName="CaravanasListBox">
         <i:InvokeCommandAction Command="{Binding AccionesToolbarCommand}" CommandParameter="{x:Static local:OpcionesBarra.MostrarDetalle}" />
       </i:EventTrigger>
    </i:Interaction.Triggers>
    

    贾米尔·G.

    【讨论】:

    • 如果它被附加到列表框,那么如果你双击列表框的任何部分,它就会触发,包括滚动条,这对于长列表来说非常烦人。而且 listboxitem 似乎没有 MouseDoubleClick 事件。
    【解决方案5】:

    这是一个在ListBoxListView 上都完成的行为。这是基于 Andrew S. 和 Vadim Tofan 的回答,他们做得很好!

    public class ItemDoubleClickBehavior : Behavior<ListBox>
    {
        #region Properties
        MouseButtonEventHandler Handler;
        #endregion
    
        #region Methods
    
        protected override void OnAttached()
        {
            base.OnAttached();
    
            AssociatedObject.PreviewMouseDoubleClick += Handler = (s, e) =>
            {
                e.Handled = true;
                if (!(e.OriginalSource is DependencyObject source)) return;
    
                ListBoxItem sourceItem = source is ListBoxItem ? (ListBoxItem)source : 
                    source.FindParent<ListBoxItem>();
    
                if (sourceItem == null) return;
    
                foreach (var binding in AssociatedObject.InputBindings.OfType<MouseBinding>())
                {
                    if (binding.MouseAction != MouseAction.LeftDoubleClick) continue;
    
                    ICommand command = binding.Command;
                    object parameter = binding.CommandParameter;
    
                    if (command.CanExecute(parameter))
                        command.Execute(parameter);
                }
            };
        }
    
        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.PreviewMouseDoubleClick -= Handler;
        }
    
        #endregion
    }
    

    这是用于查找父级的扩展类。

    public static class UIHelper
    {
        public static T FindParent<T>(this DependencyObject child, bool debug = false) where T : DependencyObject
        {
            DependencyObject parentObject = VisualTreeHelper.GetParent(child);
    
            //we've reached the end of the tree
            if (parentObject == null) return null;
    
            //check if the parent matches the type we're looking for
            if (parentObject is T parent)
                return parent;
            else
                return FindParent<T>(parentObject);
        }
    }
    

    用法:

    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    xmlns:coreBehaviors="{{Your Behavior Namespace}}"
    
    
    <ListView AllowDrop="True" ItemsSource="{Binding Data}">
        <i:Interaction.Behaviors>
           <coreBehaviors:ItemDoubleClickBehavior/>
        </i:Interaction.Behaviors>
    
        <ListBox.InputBindings>
           <MouseBinding MouseAction="LeftDoubleClick" Command="{Binding YourCommand}"/>
        </ListBox.InputBindings>
    </ListView>
    

    【讨论】:

      猜你喜欢
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      • 2017-09-17
      • 2018-10-04
      • 2011-01-23
      • 2014-03-08
      • 1970-01-01
      相关资源
      最近更新 更多