1

I am using the Model View ViewModel pattern in my WPF application. The DataContext of my view is set to the ViewModel.

I have a ListView in my view, which has a ContextMenu and one of the MenuItems there needs to bind to a Command and the CommandParameter is the ListView itself.

Now my problem is, that I don't know how to reference the ListView. Maybe a code-snippet makes it easier to understand:

<ListView 
            Name="lvTestList"
            ItemsSource="{Binding Path=TestList.Items}">

            <!-- Context Menu of the selected test -->
            <ListView.ContextMenu>
                <ContextMenu>
                    <MenuItem
                        Header="Remove from List"
                        IsEnabled="{Binding IsATestSelected}" 
                        Command="{Binding RemoveTestFromTestListCommand}" 
                        CommandParameter="{Binding ElementName=lvTestList}"/>
                </ContextMenu>
            </ListView.ContextMenu>

            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding TestName}"/>
                    <GridViewColumn Header="Package" DisplayMemberBinding="{Binding PackageName}"/>
                    <GridViewColumn Header="Expected Duration" DisplayMemberBinding="{Binding ExpectedDuration}"/>
                </GridView>
            </ListView.View>
        </ListView>

The problematic line is the one saying:

CommandParameter="{Binding ElementName=lvTestList}"/>

Normally, this would be working. However, if the DataContext of the whole class changes, it just passes null as parameter.

Does anyone know how to keep a reference to the current xaml document? or how to "talk" to the ListView "lvTestList" directly?

Best wishes and Thanks for help, Christian

Christian
  • 4,345
  • 5
  • 42
  • 71

2 Answers2

1

You can obtain a reference to your ListView via a reltivesource FindAncestor binding:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}

It seems a bit odd that you want to pass a ListView as a parameter to a command, perhaps you should use:

{Binding Path=DataContext.Something, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListView}}

With the path set to the DataContext you are then able to bind the parent view model.

Hope that helps, Colin E.

ColinE
  • 68,894
  • 15
  • 164
  • 232
  • Thanks for the quick response. I know its not the neat way of doing it, you're right. However, using your Binding gives the following binding error: System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ListView', AncestorLevel='1''. BindingExpression:(no path); DataItem=null; target element is 'MenuItem' (Name=''); target property is 'CommandParameter' (type 'Object') – Christian Dec 17 '10 at 12:32
  • Ah .. looks like it is because you are in a context menu ... see the following for a solution: http://stackoverflow.com/questions/504533/commandparameters-in-contextmenu-in-wpf – ColinE Dec 17 '10 at 12:34
  • Hmm, tried what they suggested, however still getting "null" and Binding errors – Christian Dec 17 '10 at 12:42
1

Use Self Binding:

CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}, Path=Parent.PlacementTarget.Name}"

Will set CommandParameter's value to "lvTestList".

You can also use Ancestor Binding:

CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ContextMenu}, Path=PlacementTarget.Name}"

In these examples, PlacementTarget will be a control on which a ContextMenu was opened. In your case, it will be ListView.

decyclone
  • 30,394
  • 6
  • 63
  • 80
  • This only sets the command parameter to a string with content "lvTestList", so what it passes in reality is just a string and not a ListView object. :/ – Christian Dec 17 '10 at 12:41
  • Ahh no my fault. did not turn on my brain when reading your code, sorry. Now it works!! {Binding RelativeSource={RelativeSource Mode=Self}, Path=Parent.PlacementTarget} – Christian Dec 17 '10 at 12:43