0

I have a simple list view with gridview to display each row.

I added a key binding for delete which is working fine.

 <ListView.InputBindings>
      <KeyBinding Key="Delete" Command="{Binding Path=DeleteKeyCommand}" CommandParameter="{Binding ElementName=DatabasesLstVw, Path=SelectedItem}"/>
 </ListView.InputBindings>

But when I add a Mousebinding for LeftDoubleClick to edit its not firing the command.

 <MouseBinding Gesture="LeftDoubleClick" Command="{Binding Path=LeftDoubleClickCommand}" CommandParameter="{Binding ElementName=DatabasesLstVw, Path=SelectedItem}" />

After spending the last two hours trying to figure it out the only thing I have come up with is that its firing the double click on the entire list view and not the listview item???

How do I get double click edit to work on one row in my list view? I am using MVVM I don't want to break that so I cant use code behind to hack it. There must be a way to map the command back to my view model.

Update more code:

 <ListView x:Name="DatabasesLstVw" ItemsSource="{Binding Path=ClientDetails.Databases}" ItemContainerStyle="{StaticResource alternatingStyle}" AlternationCount="2" Grid.Row="2" Grid.ColumnSpan="4" VerticalAlignment="Top" >                
               <ListView.InputBindings>
                    <KeyBinding Key="Delete" Command="{Binding Path=DeleteKeyCommand}" CommandParameter="{Binding ElementName=DatabasesLstVw, Path=SelectedItem}"/>
                    <MouseBinding Gesture="LeftDoubleClick" Command="{Binding Path=LeftDoubleClickCommand}" CommandParameter="{Binding ElementName=DatabasesLstVw, Path=SelectedItem}" />
                </ListView.InputBindings>
Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449
  • You have added double click on the list view and not list item. In your code behind add it to each item. – Versatile May 02 '16 at 13:37
  • Possible duplicate [stackoverflow](http://stackoverflow.com/questions/2133282/adding-mousebindings-to-items-in-a-databound-wpf-listview) – Pikoh May 02 '16 at 13:37
  • @Versatile I am pretty sure its on the list view not the item. – Linda Lawton - DaImTo May 02 '16 at 13:38
  • @Pikoh I tried that one already it doesn't say what local: is so it doesn't work unfortunately – Linda Lawton - DaImTo May 02 '16 at 13:39
  • Well..local obviously is your project namespace – Pikoh May 02 '16 at 13:40
  • Unfortunately I am very new to WPF so am not exactly sure what that is. I don't have anything called local at the top of my file so it doesn't work. – Linda Lawton - DaImTo May 02 '16 at 13:41
  • In your xaml, you should add something like `xmlns:local="clr-namespace:yourNameSpace` – Pikoh May 02 '16 at 13:43
  • You can also just subscribe to MouseDoubleClick event in ItemContainerStyle of your ListView (using EventSetter in that style), then call your command from that handler. The fact there is code behind does NOT violate mvvm pattern in any way. – Evk May 02 '16 at 13:49
  • @Evk sadly I think this may be the only way pikoh example isn't event adding a namespace it doesn't work because not all the code is there. I would really have thought this would be something easy to do. If you can bind the key command to it why not be able to bind a mouse command. – Linda Lawton - DaImTo May 02 '16 at 13:51
  • Well that is certainly not the only way, just the most straightforward. Pikoh example does work too. Suppose you have application named WpfApplication. Then (by default) all classes you create there would be in WpfApplication namespace. Create AddToInputBinding class in that namespace as described in answer, then use xmlns:local="clr-namespace:WpfApplication" for namespace. I just wanted to mention that code behind by itself does not violate mvvm pattern. – Evk May 02 '16 at 13:54
  • I found the binding part I tried to bind it to my viewmodel but the code in the method is incomplete "InputBinding GetBinding(... // create using propa snippet" – Linda Lawton - DaImTo May 02 '16 at 13:57
  • I agree with @Evk. In this case code behind won't violate MVVM, but I tend to avoid it unless necessary. The example provided in the answer i linked works also DalmTo, and if you are going to code in WPF you should make yourself familiar with defining namespaces in your xaml as sooner than later you would need it – Pikoh May 02 '16 at 13:58
  • Defining the namespace isn't an issue I just don't use local so was unclear on what they where talking about xmlns:Util="clr-namespace:Cloud.Upload.Client.UI.Util" I added the class under util. But the method still isn't complete. he has stuff commented out so it doesn't load. – Linda Lawton - DaImTo May 02 '16 at 14:00
  • I will look at it again in the morning with fresh eyes maybe then I will be able to debug the method. If you both say it works then it should be the solution I am after. – Linda Lawton - DaImTo May 02 '16 at 14:02

1 Answers1

3

As the referenced answer is missing some code, this is how it should be:

    public class AddToInputBinding
    {
        public static System.Windows.Input.InputBinding GetBinding(DependencyObject obj)
        {
            return (System.Windows.Input.InputBinding)obj.GetValue(BindingProp);
        }

        public static void SetBinding(DependencyObject obj, System.Windows.Input.InputBinding value)
        {
            obj.SetValue(BindingProp, value);
        }


        public static readonly DependencyProperty BindingProp = DependencyProperty.RegisterAttached(
          "Binding", typeof(System.Windows.Input.InputBinding), typeof(AddToInputBinding), new PropertyMetadata
          {
              PropertyChangedCallback = (obj, e) =>
              {
                  ((UIElement)obj).InputBindings.Add((System.Windows.Input.InputBinding)e.NewValue);
              }
          });
    }

Then, in your XAML, you would do something like this:

<Window x:Class="WpfApplication.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication"
    Title="Window1" Height="300" Width="300">
<Window.Resources>
    <ResourceDictionary>
        <Style TargetType="ListViewItem">
            <Setter Property="local:AddToInputBinding.Binding">
                <Setter.Value>
                    <MouseBinding Gesture="LeftDoubleClick" Command="{Binding DataContext.ItemDoubleClick,
                                                                                    RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}}"
                                                                                    CommandParameter="{Binding}"/>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>
</Window.Resources>
<Grid>
    <ListView ItemsSource="{Binding Patients}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Test" />
            </GridView>

        </ListView.View>
    </ListView>

</Grid>

In your viewModel, the command definition would be like this:

    RelayCommand<string> _ItemDoubleClick;
    public ICommand ItemDoubleClick
    {
        get
        {
            if (_ItemDoubleClick == null)
            {
                _ItemDoubleClick = new RelayCommand<string>(this.ItemDoubleClickExecuted,
                    param => this.ItemDoubleClickCanExecute());

            }
            return _ItemDoubleClick;
        }
    }

    private bool ItemDoubleClickCanExecute()
    {
        return true;
    }

    private void ItemDoubleClickExecuted(string item)
    {
        //In item you've got the text of double clicked ListViewItem
    }

Note that in this sample, the ListView binded ObservableCollection is of type string. If this was other type, you should change the types in the ICommand definitions. Don't forget also to set the Window DataContext to your ViewModel. Hope this is clearer now.

Community
  • 1
  • 1
Pikoh
  • 7,582
  • 28
  • 53
  • I will test it out if it works I will give you a bounty for helping a nub :) – Linda Lawton - DaImTo May 02 '16 at 14:44
  • I hope it works. If it doesn't, just tell my and i will try it myself. And the bounty isn't necessary, don't worry :) – Pikoh May 02 '16 at 15:58
  • Check that question the second answer the one with Interactivity works. I am having some huge debugging issues with yours. Type 'AddToInputBinding' initialization failed: The type initializer for 'MouseDoubleClickListviewItem.Util.AddToInputBinding' threw an exception. So what is the difference does it matter if I use the other one? – Linda Lawton - DaImTo May 03 '16 at 08:03
  • No, it really doesn't matter. If the second one works to you, don't look back, both are o.k. :) – Pikoh May 03 '16 at 08:10
  • I may keep trying with this just because I want to understand how DependencyProperty works. – Linda Lawton - DaImTo May 03 '16 at 08:15
  • @DaImTo Ok, i've tried the code I gave you and it wasn't working. See my edit now, it should work as expected. Note that the `AddToInputBinding` is different now. – Pikoh May 03 '16 at 09:06