1

I have a MenuItem with ListView inside. What I want is when I click on a ListView item, some command fires. Here is my code:

<MenuItem Header="?">
    <ListView ItemsSource="{Binding CommentTemplateList}" BorderThickness="0" SelectedItem="{Binding SelectedCommentTemplate, UpdateSourceTrigger=PropertyChanged}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectionChanged">
                <i:InvokeCommandAction Command="{Binding PasteTemplate}"
CommandParameter="{Binding SelectedCommentTemplate}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
        <ListView.View>
            <GridView>
                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Caption}" ToolTip="{Binding Description}" HorizontalAlignment="Center"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
   </ListView>
</MenuItem>

Everything is ok, but command PasteTemplate fires only when selection is changed, and I need to it fire every time I click on the item. If I change EventName to one from the list (https://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.selector.aspx), for example MouseDown, the command does not fire at all.

Pyritie
  • 543
  • 4
  • 16
Denisov Jr.
  • 91
  • 3
  • 11

3 Answers3

4

To accomplish this, while respecting the MVVM architecture, the best way is to add the specific behavior to your xaml code as follows;

 <ListView x:Name="ListView"
           ItemsSource="{x:Bind ViewModel.SampleItems, Mode=OneWay}"
           SelectedItem="{x:Bind ViewModel.SelectedItem, Mode=OneWay}"
           IsItemClickEnabled="True">
     <i:Interaction.Behaviors>
         <ic:EventTriggerBehavior EventName="ItemClick">
             <ic:InvokeCommandAction Command="{x:Bind ViewModel.ItemClickCommand}" />
         </ic:EventTriggerBehavior>
     </i:Interaction.Behaviors>
 </ListView>

And in your View Model, after declaring an IComand property as follows,

public ICommand ItemClickCommand
{
    get
    {
        if (_itemClickCommand == null)
        {
            _itemClickCommand = new RelayCommand<ItemClickEventArgs>(OnItemClick);
        }

        return _itemClickCommand;
    }
}

Define the command as if you were handling the event in the code behind as follows;

private void OnItemClick(ItemClickEventArgs args)
{
    ListDataItem item = args?.ClickedItem as ListDataItem; 
    //DO what ever you want with the Item you selected in the click
}

Note: RelayCommand is used to handled commands using the MVVMLight Framework.

Pyritie
  • 543
  • 4
  • 16
Damien Doumer
  • 1,991
  • 1
  • 18
  • 33
0

You could handle the PreviewMouseDown event of the ListViewItem as suggested here:

WPF MVVM Light Multiple ListBoxItems bound to same object

<ListView ...>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <EventSetter Event="PreviewMouseLeftButtonDown" Handler="OnMouseLeftButtonDown"/>
        </Style>
    </ListView.ItemContainerStyle>
    ..
</ListView>

If you don't want to invoke the command of the view model from the code-behind you could wrap the same functionality in an attached behaviour: https://www.codeproject.com/articles/28959/introduction-to-attached-behaviors-in-wpf.

There is more information an example on the link above.

Community
  • 1
  • 1
mm8
  • 163,881
  • 10
  • 57
  • 88
-1

If you wanna use 'SelectionChanged', You can reset the selection after your code. Just add that on your PasteTemplate

if(((ListView)sender).SelectedIndex == -1)return;
//your code
((ListView)sender).SelectedIndex = -1;

So, after your code, ListView has no selected elements. So if you click it again, the selection is changed again and code fires again.

Note: you can use MouseDown for it too, but it's a little tricky. For example, if user clicks none of your items but somewhere else inside your ListView like this, it fires again with your current selection.

GBursali
  • 355
  • 1
  • 10
  • I am using MVVM, so i have binded Listview SelectedIndex property to SelectedTemplateIndex variable. My code: XAML: `SelectedIndex="{Binding SelectedTemplateIndex}" ` ViewModel: `private void OnPasteTemplateExecute() { if (SelectedTemplateIndex == ` `-1) return; LeaveCommentBox = SelectedCommentTemplate.Description;` `SelectedTemplateIndex = -1; }` And i see the same behaviour - command fires only if selection is actually changing. – Denisov Jr. Feb 10 '17 at 07:40
  • `SelectedTemplateIndex=-1` should resets your selection. It selects -1st element (in listview, that means select nothing) and lets you select again. if its still not resets, you can try reset your SelectedItem or check this [link](http://stackoverflow.com/a/18462019/7538242) – GBursali Feb 10 '17 at 07:57