Listview MouseDoubleClickEvent在后面的代码中创建

时间:2012-03-18 07:53:41

标签: c# wpf listview code-behind

当我有:

<UserControl.Resources>

    <Style x:Key="itemstyle" TargetType="{x:Type ListViewItem}">
        <EventSetter Event="MouseDoubleClick" Handler="HandleDoubleClick" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
    </Style>
</UserControl.Resources>
<Grid>
    <ListView  ItemContainerStyle="itemstyle"  Name="listView1" >
        <ListView.View>
             <GridView>
                  ... etc

背后的代码

    protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
    {
        T item = (T)(((ListViewItem)sender).Content);   
        // item is the row item that was double clicked on                    
    }

一切都很好。


现在我需要在代码背后做同样的事情。这就是我的成果:

 public Constructor(){

    listview.AddHandler(
        ListViewItem.MouseDoubleClickEvent, 
        new MouseButtonEventHandler(HandleDoubleClick)
    );
 }


 protected void HandleDoubleClick(object sender, MouseButtonEventArgs e)
 {
        T item = (T)(((ListViewItem)sender).Content);       
        // error cause the sender is the listview                           
 }

当我双击listview的任何部分而不仅仅是listviewItem时,该事件将触发。此外,我希望发件人是ListViewItem,它不是。发件人实际上是列表视图。我尝试过的事情:

  

1)因为发件人是列表视图,所以我尝试将事件创建为:

         listview.AddHandler(
            // I use PreviewMouseDoubleClickEvent instead of MouseDoubleClickEvent because of the way the events bubles
            ListViewItem.PreviewMouseDoubleClickEvent,   
            new MouseButtonEventHandler(HandleDoubleClick)
         );

我收到的错误是发件人是listview

  

2)而不是:

  T item = (T)((ListViewItem)sender).Content;

我做:

  T item = (T)(listview.selectedItem);

这个问题是,如果用户双击列表视图中不是行的任何内容,它将返回当前所选项目

为什么我的代码不起作用?我做错了什么?

4 个答案:

答案 0 :(得分:2)

Attached Behavior Pattern


我认为你应该使用附加行为,因为

  1. MVVM♥附加行为
  2. 可以重复使用:一旦创建了附加行为和双击命令,就可以将它附加到任何其他控件类型(这样你就可以使用相同的代码来双击图像等)。
  3. 抽象脏实现,使xaml和视图模型更加清晰
  4. 他们的工作方式很棒,我喜欢使用聪明的代码。
  5. 你做的是什么:

    enter image description here


    创建ListViewItemDoubleClickCommandBehavior

    从上图中可以看出,此CommandBehavior类将命令链接到控件。

    • 在上面的情况下,它是一个按钮库,但是我们要创建一个ListViewItem

    • 你将需要prism这个,因为它继承自的CommandBehaviorBase是该库的一部分。你可以得到它here(但是对于这个例子你只需要Prism.Commands dll)

    • 命名约定表示您应该以

      格式命名此CommandBehavior
       [X][Y]CommandBehavior
      

      X - 我们绑定命令的控件的名称(在本例中为ListViewItem)
      Y - 用户执行的将导致命令发生的操作(在本例中为DoubleClick)

    下面是代码:

        public class ListViewItemDoubleClickCommandBehaviour : CommandBehaviorBase<ListViewItem>
        {
            public ListViewItemDoubleClickCommandBehaviour(ListViewItem controlToWhomWeBind)
            : base(controlToWhomWeBind)
            {
                controlToWhomWeBind.MouseDoubleClick += OnDoubleClick;
            }
    
            private void OnDoubleClick(object sender, System.Windows.RoutedEventArgs e)
            {
    
                ExecuteCommand();
    
            }
        }
    

    创建DoubleClick Static类

    这个类将包含所有双击命令。

    • 它被称为doubleclick,因为它代表双击的实际行为。其他类型的操作(比如你想要一个文本框中按钮的命令)将拥有自己的类及其命令,命令参数和行为,然后我们就可以访问了。

    • 这些命令是ICommand类型的依赖项属性(我假设你已经实现了这个接口,因为你需要它用于MVVM)

    • 命令本身的一个依赖属性,一个用于命令所需的参数(在这种情况下,您可能会将所选项目用作参数)

    • 此类具有ListViewItemDoubleClickCommandBehavior的实例作为依赖项属性。这是在绑定到控件的命令和ListViewItemDoubleClickCommandBehaviour中的双击事件之间创建链接的方式。我们使用一些CommandBehaviorBase的魔术方法来创建行为并将命令传递给它。

    • OnSetCommand和OnSetCommandParameter回调用于将Behavior连接到命令。每次命令更改时,我们都会将其设置为要运行的行为的新命令。这些回调被注册到构造函数的PropertyMetadata部分中的DependencyProperties。每当依赖项属性发生更改时,都会触发它们。

    这是该类的代码:

    public static class DoubleClick
    {
    
        public static readonly DependencyProperty CommandProperty =
                              DependencyProperty.RegisterAttached(
                                      "Command",
                                      typeof(ICommand),
                                      typeof(DoubleClick),
                                      new PropertyMetadata(OnSetCommandCallback));
    
        public static readonly DependencyProperty CommandParameterProperty =
                                DependencyProperty.RegisterAttached(
                                        "CommandParameter",
                                        typeof(object),
                                        typeof(DoubleClick),
                                        new PropertyMetadata(OnSetCommandParameterCallback));
    
    
    
        private static readonly DependencyProperty DoubleClickCommandBehaviorProperty =
                                      DependencyProperty.RegisterAttached(
                                              "DoubleClickCommandBehavior",
                                              typeof(ListViewItemDoubleClickCommandBehaviour),
                                              typeof(DoubleClick),
                                              null);
    
    
        public static void SetCommand(ListViewItem controlToWhomWeBind, ICommand value)
        {
            controlToWhomWeBind.SetValue(CommandProperty, value);
        }
    
        public static ICommand GetCommand(ListViewItem controlToWhomWeBind)
        {
             return (ICommand)controlToWhomWeBind.GetValue(CommandProperty);
        }
    
        public static void SetCommandParameter(ListViewItem controlToWhomWeBind, ICommand value)
        {
            controlToWhomWeBind.SetValue(CommandParameterProperty, value);
        }
    
        public static ICommand GetCommandParameter(ListViewItem controlToWhomWeBind)
        {
            return (ICommand)controlToWhomWeBind.GetValue(CommandParameterProperty);
        }
    
    
    
        private static void OnSetCommandCallback(DependencyObject dependencyObject,
    DependencyPropertyChangedEventArgs e)
        {
            ListViewItem controlToWhomWeBind= dependencyObject as ListViewItem;
            if (controlToWhomWeBind!= null)
            {
                ListViewItemDoubleClickCommandBehaviour behavior = GetOrCreateBehavior(controlToWhomWeBind);
                behavior.Command = e.NewValue as ICommand;
            }
        }
    
        private static void OnSetCommandParameterCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
        {
            ListViewItem controlToWhomWeBind= dependencyObject as ListViewItem;
            if (controlToWhomWeBind!= null)
            {
                ListViewItemDoubleClickCommandBehaviour behavior = GetOrCreateBehavior(controlToWhomWeBind);
                behavior.CommandParameter = e.NewValue;
            }
        }
    
        private static ListViewItemDoubleClickCommandBehaviour GetOrCreateBehavior(
                                                                   ListViewItem controlToWhomWeBind)
        {
            ListViewItemDoubleClickCommandBehaviour behavior =
                controlToWhomWeBind.GetValue(DoubleClickCommandBehaviorProperty) as
                     ListViewItemDoubleClickCommandBehaviour;
            if (behavior == null)
            {
                behavior = new ListViewItemDoubleClickCommandBehaviour (controlToWhomWeBind);
                controlToWhomWeBind.SetValue(DoubleClickCommandBehaviorProperty, behavior);
            }
    
            return behavior;
        }
    }
    

    注意:

    我知道这看起来很像复杂的代码,但是一旦你经常使用它就会变成一个简单的模式,并且它会从视图模型中抽象出所有复杂性,因此命令与控件的绑定看起来非常简单


    在viewmodel中创建命令并在xaml

    中绑定它

    既然咕噜咕噜的工作结束了,我们就可以轻松完成。

    创建命令

    我假设你熟悉命令,你可以像往常一样创建命令:

        public ICommand DisplaySelectedItemCmd { get; protected set; }
    
        //This method goes in your constructor
        private void InitializeCommands()
        {
            //Initializes the command
            this.DisplaySelectedItemCmd = new RelayCommand(
                (param) =>
                {
                    this.DisplaySelectedItem((object)param);
                },
                (param) => { return this.CanDisplaySelectedItem; }
            );
        }      
        //The parameter should be your listview's selected item. I have no idea what type it is so I made it an object
        public void DisplaySelectedPolicy(object selectedListViewItem)
        {
            //Code to perform when item is double clicked
        }
    
        private bool CanDisplaySelectedPolicy
        {
            get
            {
                return true; //Change this bool if you have any reason to disable the double clicking, as this bool basically is linked to the double click command firing.
            }
        }
    

    在xaml中创建绑定

    现在是美丽的一部分。 首先添加xml命名空间:

     xmlns:commands="clr-namespace:CommandHandling" 
    

    然后绑定到ListViewItem

     <Style TargetType="{x:Type ListViewItem}" x:Key="{x:Type ListViewItem}" >
           <Setter Property="commands:DoubleClick.Command" Value="{Binding Path=bleh}"/>
     </Style>
    

    并完成。

    如果这不起作用,请告诉我。 (如果你愿意的话,任何读这篇文章的人都可以请你帮忙)

    u_u

答案 1 :(得分:0)

在xaml中,您将事件处理程序附加到ListViewItem,而在后面的代码中将它附加到ListView本身。这就是为什么你会有不同的行为。如果您想在后面的代码中执行相同操作,则必须在项集合中循环al项,并将每个项的DoubleClick事件绑定到您的处理程序。

如果没有真正的理由在代码中执行此操作,我会选择适合MVVM模式的xaml方法,以便在后面的代码中尽可能少地保留代码。

答案 2 :(得分:0)

除非您想要在UserControl中使用命名内容,否则不要理解为什么要在代码中执行此操作,以便将其更改为自定义控件。尝试在后面的代码中重复你的xaml代码,即为ListViewItem创建一个样式并将其设置为listview的ItemContainerStyle。

答案 3 :(得分:0)

搞清楚!!我确信它应该与双击一样......

在xaml中我有:

<ListView IsSynchronizedWithCurrentItem="True" Name="listView" Margin="32,158,66,0" VerticalAlignment="Top">
        <ListView.ItemContainerStyle>                 
             <Style TargetType="ListViewItem">
                <EventSetter Event="PreviewMouseUp" Handler="itemClicked"></EventSetter>
            </Style>                 
        </ListView.ItemContainerStyle>            
        <ListView.View>
        ... etc

我可以用c#在后面的代码上创建相同的东西:

    EventSetter ev = new EventSetter();
    ev.Event = ListViewItem.PreviewMouseUpEvent;
    ev.Handler = new MouseButtonEventHandler(itemClicked);

    Style myStyle = new Style();
    myStyle.TargetType = typeof(ListViewItem);

    myStyle.Setters.Add(ev);


    listView.ItemContainerStyle = myStyle;

...

void itemClicked(object sender, MouseButtonEventArgs e)
{
     // item was licked in listview implement behavior in here
}