ListView MouseDoubleClickEvent создать в коде позади - PullRequest
0 голосов
/ 18 марта 2012

Когда у меня есть:

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

это событие возникает, когда я дважды щелкаю любую часть списка, а не только элемент списка. Также я ожидаю, что отправитель будет ListViewItem, и это не так. отправитель фактически является списком. Вещи, которые я пробовал:

1) Поскольку отправителем является просмотр списка, я попытался создать событие как:

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

Я получаю ту же ошибку, что отправитель является списком

2) Вместо выполнения:

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

Я делаю:

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

проблема в том, что если пользователь дважды щелкнет что-либо в списке, кроме строки, он вернет текущий выбранный элемент

почему мой код не работает? что я делаю не так?

Ответы [ 4 ]

2 голосов
/ 19 марта 2012

Прикрепленный шаблон поведения


Я думаю, что вы должны использовать прикрепленное поведение, потому что

  1. MVVM ♥ Прикрепленное поведение
  2. Его можно использовать повторно: после создания прикрепленного поведения и команд для двойного щелчка вы можете прикрепить его к любому другому типу элемента управления (чтобы вы могли использовать тот же код для двойного щелчка по изображению и т. Д.)
  3. Абстрагирует грязную реализацию, чтобы xaml и модель представления были намного более разборчивыми
  4. То, как они работают, потрясающе, и я люблю использовать умный код.

Вот что вы делаете:

enter image description here


Создание ListViewItemDoubleClickCommandBehavior

Как видно из приведенной выше диаграммы, этот класс CommandBehavior связывает команду с элементом управления.

  • В приведенном выше случае для базы кнопок, но мы собираемся сделать ListViewItem один

  • Для этого вам понадобится призма, так как CommandBehaviorBase, от которой она наследуется, является частью этой библиотеки. Вы можете получить все это здесь (но для этого примера вам нужен только 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

В этом классе будут размещены все команды двойного щелчка.

  • Его называют двойным щелчком, потому что он представляет фактический акт двойного щелчка. Каждый другой вид действия (скажем, вам нужна команда для нажатия кнопки в текстовом поле) будет иметь свой собственный класс со своей командой, параметром команды и поведением, к которому мы можем затем обратиться.

  • Команды являются свойствами зависимостей типа ICommand (я предполагаю, что вы реализовали этот интерфейс, потому что он вам как-то нужен для MVVM)

  • Одно свойство зависимости для самой команды и одно для параметров, в которых она нуждается (в этом случае вы, вероятно, будете использовать выбранный элемент в качестве параметра)

  • Этот класс имеет экземпляр ListViewItemDoubleClickCommandBehavior в качестве свойства зависимости. Так создается связь между командой, которую вы привязываете к своему элементу управления, и событием двойного щелчка в ListViewItemDoubleClickCommandBehaviour. Мы используем некоторые магические методы CommandBehaviorBase, чтобы создать поведение и передать ему команду для выполнения.

  • Обратные вызовы OnSetCommand и OnSetCommandParameter используются для привязки поведения к команде. Каждый раз, когда команда изменяется, мы устанавливаем ее как новую команду для запуска поведения. Эти обратные вызовы регистрируются в свойствах DependencyProperties в части PropertyMetadata конструктора. Они запускаются всякий раз, когда изменяется свойство зависимости.

Вот код этого класса:

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

Примечание:

Я знаю, что это выглядит как много сложного кода, но это простой шаблон, если вы используете его достаточно часто, и он абстрагирует всю сложность от вашей модели представления, так что привязка команды к элементу управления выглядит удивительно простой .


Создайте команду в своей модели представления и привяжите ее в 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

0 голосов
/ 15 апреля 2012

Разберись !!Я уверен, что это должно быть то же самое с двойным щелчком мыши ...

В 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 # позади:1006 *

    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
}
0 голосов
/ 19 марта 2012

Не понимаю, почему вы делаете это в коде, если вы не хотите именованного контента в вашем UserControl, поэтому вы меняете его на пользовательский элемент управления. Попробуйте повторить свой код xaml в коде позади, т.е. создайте стиль для ListViewItem и установите его как ItemContainerStyle для вашего списка.

0 голосов
/ 18 марта 2012

В xaml вы присоединяете обработчик событий к ListViewItem, в то время как в коде позади вы присоединяете его к самому ListView.Вот почему вы получаете другое поведение.Если вы хотите сделать то же самое в коде позади, вам придется зациклить все элементы в вашей коллекции элементов и связать событие DoubleClick каждого из них с вашим обработчиком.

Если в коде нет реальной причины делать это, я бы выбрал подход xaml, который лучше соответствует шаблону MVVM, когда вы пытаетесь сохранить как можно меньше кода в коде позади.

...