Getting CurrentItem within a nested ItemsControl - wpf

I have an itemscontrol, with a item template. Inside this item template another itemscontrol exists. The latter ItemsControl has a button in its template, the command bound to this template needs to get the "parent" itemscontrol current item.
The structure looks something like this:
<ItemsControl x:Name="outerItemsControl" ItemsSource={Binding MyCollection}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ItemsControl ItemsSource={Binding MySecondCollection}>
<ItemTemplate>
<DataTemplate>
<Button Command="{Binding MyFantasticCommand}"
CommandParameter="{Binding ????}"/>
</DataTemplate>
</ItemTemplate>
</ItemsControl>
</DataTemplate>
<ItemControl.ItemTemplate>
</ItemsControl>
What should I replace the {Binding ????} with to get hold of the current item in MyCollection?
I've tried with both:
Binding ., ElementName=outerItemsControl
and
Binding Path="." RelativeSource="{RelativeSource AncestorType={x:Type ItemsControl}, AncestorLevel=2}
EDIT
Usually when we need to access the "current item" in an items control we do the following:
<ItemsControl x:Name="outerItemsControl" ItemsSource={Binding MyCollection}>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding MyCommand}" CommandParameter="{Binding .}"/>
</DataTemplate>
<ItemControl.ItemTemplate>
</ItemsControl>
I want to do the same as this example, but access the parent's "current" item from the child itemscontrol.

It seems you want to access the object with the MySecondCollection property from the inner DataTemplate.
This should work:
CommandParameter="{Binding DataContext,
RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=2}}"

Related

MahApps.Metro: WindowCommands ItemsSource binding

I am trying to bind a collection of items to the windowcommands of metrowindow. Below is the xaml snippet.
<metro:MetroWindow.WindowCommands>
<metro:WindowCommands ItemsSource="{Binding WindowCommands}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding DisplayName}"
Command="{Binding Callback}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</metro:WindowCommands>
</metro:MetroWindow.WindowCommands>
But it does not display the DisplayName property, but the type name of the bounded datatype. How can I achive the intended behaviour?
Works if you add the template as a resource to the MetroWindow. For this to work you will need to create a WindowCommandViewModel that has Label and Callback properties.
<metro:MetroWindow.Resources>
<DataTemplate DataType="{x:Type viewModels:WindowCommandViewModel}">
<Button Content="{Binding DisplayName}"
Command="{Binding Callback}"/>
</DataTemplate>
</metro:MetroWindow.Resources>

ItemTemplate: how to refer to the item itself

I have a ListBox displaying items with a template something like this:
<ListBox
x:Name="CustomerResultList"
ItemsSource="{Binding Customers}">
<ListBox.ItemTemplate>
<DataTemplate>
<controlsToolkit:DockPanel>
<Button
x:Name="CustomerButton"
Command="{Binding MyCommand}"
CommandParameter="{Binding WhatGoesHere?}"
controlsToolkit:DockPanel.Dock="Left"
Content="ButtonText" />
<TextBlock
Text="{Binding Path=Name}"
controlsToolkit:DockPanel.Dock="Right" />
</controlsToolkit:DockPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The button in the template should invoke a command that gets passed the customer as a parameter.
I can't figure out how to refer to the customer in the buttons CommandParameter binding.
Is there a special Elementname or Path I can use to refer to the Custome itself and not some of its properties?
Simply:
CommandParameter="{Binding}"
If you specify Binding without Path, you bind to the DataContext itself.

WPF + Binding Command and Header of a Context Menu Item using MVVM

I created a WPF application and am following MVVM Pattern. I have a context menu in my xaml and I need to bind the command and Header text. Using the following code I can bind the Header of the context menu with the "MenuItemName" which is a property in BOList which is an observable collection. My issue is that command is not getting fired? I changes the Item source of the Context Menu to datacontext
(DataContext="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}")
Command is working fine but my header is getting blank. Is there a way to bind my header and command of a menu item? Here the command MenuClick is a Icommand property in the VM and MenuItemName is a property inside BOList which is an observable collection binded to my ListBox.
<Grid>
<StackPanel Orientation="Vertical">
<Button x:Name="btnClickMe" Command="{Binding ButtonCommand}" Content="Click Me" />
<ListBox ItemsSource="{Binding BOList}" x:Name="lstDemo" SelectedItem="{Binding BussinessObj,Mode=OneWayToSource}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel x:Name="stkStyleRender" Orientation="Horizontal" Background="Cyan" Width="525" Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}" >
<TextBlock x:Name="txtId" Text="{Binding FirstName}"></TextBlock>
<TextBlock x:Name="txtName" Text="{Binding LastName}"></TextBlock>
<StackPanel.ContextMenu>
<ContextMenu x:Name="cntMnuTest" ItemsSource ="{Binding Path=PlacementTarget.Tag, RelativeSource={RelativeSource Self}}" >
<MenuItem Header="{Binding MenuItemName}" Command="{Binding MenuClick}" CommandParameter="Icon"></MenuItem>
</ContextMenu>
</StackPanel.ContextMenu>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
Hi Identified the issue.
If we set Item Source of the context menu to BOList (observable collection ) command wont get fired because the ICommand definition is in Window data context (vm).
We need to handle the code like wise.
Since debugging is not possible for binding , I was beating around the bush :-)
This link helped me a lot WPF Tutorial - Debug Databinding Issues in WPF
In context menu use DataContext instead of using Items source
then bind your menu item
try this:
<MenuItem Header="{Binding Path=PlacementTarget.MenuItemName, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}" Command="{Binding Path=PlacementTarget.MenuClick, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ContextMenu}}" />

TreeView ContextMenu MVVM Binding

I currently have a UserControl that uses the MVVM model.
In that control there is a TreeView, which displays some items. I have added a HierarchicalDataTemplate for this TreeView and in that template is a ContextMenu for the Items.
In the ViewModel, which is DataContext of the control (named RestoresTreeViewControl) is a command I want to bind one of the menu items to. However what I have done doesn't seem to be working. I am getting the usual can't find source for binding reference.
Here is the bit of code for the datatemplate that tried to bind the EditDatabaseCommand to one of the menu items.
<HierarchicalDataTemplate DataType="{x:Type model:Database}" >
<StackPanel>
<TextBlock Text="{Binding Name}" >
<TextBlock.ContextMenu>
<ContextMenu>
<MenuItem Header="Edit" Command="{Binding ElementName=RestoresTreeViewControl, Path=DataContext.EditDatabaseCommand}" />
<MenuItem Header="Delete"/>
<Separator/>
<MenuItem Header="Test Connection"/>
</ContextMenu>
</TextBlock.ContextMenu>
</TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
Here is a section of the ViewModel where the command is.
public ICommand EditDatabaseCommand { get; private set; }
Unfortunately the ContextMenu is not in the VisualTree, so it's not going to see your DataContext. What you can do is something like this (copied from here: MVVM binding command to contextmenu item)
<Button Height="40" Margin="0,2,0,0" CommandParameter="{Binding Name}"
Tag="{Binding RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type UserControl}}}" Command = "{Binding
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}},
Path=DataContext.ConnectCommand}">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Remove"
CommandParameter="{Binding Name}"
Command="{Binding Path=PlacementTarget.Tag.DataContext.RemoveCommand,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ContextMenu}}"/>
</ContextMenu>
</Button.ContextMenu>
So simply use PlacementTarget.Tag to find your ViewModel.
You can try tracing the binding:
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
...
{binding ... diag:PresentationTraceSources.TraceLevel="High"}
However requiring the users (even if it is just yourself) of your control to name each instance of "RestoresTreeViewControl" rather burdensome.
Try:
{Binding Path=... RelativeSource={ FindAncestor, AncestorType={x:TheRestoresTreeViewControlType}} }
That probably has to do with the inheritance context.
See: Binding WPF ContextMenu MenuItem to UserControl Property vs ViewModel Property

Bind to ItemsControl's DataContext from inside an ItemTemplate

I have an ItemsControl whose for the ItemTemplate DataTemplate contains a Button. I want the Command on the button to bind to a Command on the DataContext of the ItemsControl, not the ItemTemplate. I think the solution has to do with using RelativeSource, but my attempts so far have failed:
<ItemsControl ItemsSource="{Binding Games}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Command="{Binding Path=GameSelectedCommand, Source={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
CommandParameter="{Binding}"
Style="{StaticResource MenuButtonStyle}"
Content="{Binding Name}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
How can I get the Button to bind to the GameSelectedCommand of the ItemsControl's DataContext object?
You're setting the source of the binding to the ItemsControl itself. Therefore, you'll need to dereference the DataContext of the ItemsControl:
Command="{Binding DataContext.GameSelectedCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ItemsControl}}}"
How would you have known this? Take a look at your debug output window when running the app. You'll see a message along the lines of "Cannot resolve property 'GameSelectedCommand' on type 'ItemsControl'".

Resources