WPF binding child controls DataContext to HierarchicalDataTemplate ItemsSource item - wpf

I have a collection of Barcodes that contains a collection of Positions. How do I set the DataContext of a custom control to a Position item in the collection?
<TreeView ItemsSource="{Binding SelectedPlate.Barcodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Positions}"
DataType="{x:Type ControlViewModels:BarcodeViewModel}">
<TextBox Text="{Binding Code}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<!--The Custom Control that needs to bind to the Position item-->
<ControlViews:PositionControl DataContext="{Binding}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

The root element in the ItemTemplate inherits the DataContext so you can remove DataContext="{Binding}".
<TreeView ItemsSource="{Binding SelectedPlate.Barcodes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Positions}"
DataType="{x:Type ControlViewModels:BarcodeViewModel}">
<TextBox Text="{Binding Code}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<ControlViews:PositionControl />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
In the PositionControl you can then bind directly to a public property of a Position object assuming you don't explicitly set the DataContext of the control somewhere.

Related

why my Listbox data binding using DataContext is not working?

I am new to WPF and data binding,
here I have a Listbox which works just fine:
<ListBox
x:Name="listBox" ItemsSource="{Binding Path=AllFriends}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Now I want to try DataContext so I use:
<UserControl.Resources>
<CollectionViewSource
x:Key="FriendsGroups"
Source="{Binding Path=AllFriends}"
>
</CollectionViewSource>
</UserControl.Resources>
<ListBox
x:Name="listBox"
DataContext="{StaticResource FriendsGroups}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
But this one is not working.
I would appreciate if you could tell me why?
Even when you use a CollectionViewSource, you still have to set the ItemsSource property, not the DataContext:
<ListBox ItemsSource="{Binding Source={StaticResource FriendsGroups}}">

How to find datacontext of parent's parent for dynamic control

We have following xaml code to display context menu and fire command when delete menu is clicked.
For the context menu item, I would like to bind command which is present in DataContext of ItemsControl. We tried with RelativeSource={RelativeSource TemplatedParent} but as the tree is created dynamically (using dataContext) it is not able to find DeleteCommand.
<Grid x:Name="MyGrid" >
<ItemsControl ItemsSource="{Binding Path=TreeRoot.Children}">
<ItemsControl.ItemTemplate>
<HierarchicalDataTemplate>
<StackPanel>
<Label Background="Black" Content="{Binding Path=DisplayText}"/>
<TreeView ItemsSource="{Binding Converter={StaticResource myCompositeNodeConverter}}" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:CompositeNode}" ItemsSource="{Binding Path=Children}" >
<TextBlock Text="{Binding Path=DisplayText}" Foreground="Black"></TextBlock>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:LeafNode}" ItemsSource="{Binding Path=Children}">
<TextBlock Text="{Binding Path=DisplayText}"></TextBlock>
</HierarchicalDataTemplate>
</TreeView.Resources>
<TreeView.ContextMenu>
<ContextMenu >
<MenuItem Header="Delete" Command="{Binding DeleteCommand}" />
</ContextMenu>
</TreeView.ContextMenu>
</TreeView>
</StackPanel>
</HierarchicalDataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
How do we bind DeleteCommand for context menu item to DataContext of ItemsControl?

Binding to ViewModel instance from View

I have program which initializes PersonsViewModel in MainWindowViewModel's constructor.
public MainWindowViewModel()
{
PersonsViewModel viewModel = new PersonsViewModel();
}
In MainWindow.xaml, PersonsViewModel and PersonsView are connected.
<Window.Resources>
<DataTemplate DataType="{x:Type vm:PersonsViewModel}">
<vw:PersonsView />
</DataTemplate>
</Window.Resources>
I use viewModel as ItemsControl ItemsSource.
<ItemsControl ItemsSource="{Binding viewModel}" Margin="4" />
Now my program opens UserControl and I need to set instance of PersonsViewModel to UserControl.DataContext.
<UserControl.DataContext>
<vm:PersonsViewModel />
</UserControl.DataContext>
Am I creating a new instance of PersonsViewModel. If I am doing so, then how I can bind it to PersonsViewModel instance? Because I have following code in UserControl. I have PersonsList bound to ItemsSource and I need to bind Command to PersonsViewModel instance.
<ItemsControl ItemsSource="{Binding PersonsList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBox Width="50" Text="{Binding Name}" />
<Button Content="Ok" Width="20" Margin="3" Command="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type UserControl}}, Path=DataContext.Command}" CommandParameter="{Binding Name}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can remove the UserControl.DataContext and Add ItemsControl.ItemTemplate. Since each ItemsControl is bound to List of person viewmodel. Each item will get the viewmodel as its datacontext. Refer the below code.
<ItemsControl ItemsSource="{Binding ViewModels}" Margin="4">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type vm:PersonsViewModel}">
<vw:PersonsView />
</DataTemplate>
</ItemsControl.ItemTemplate>

HierarchicalDataTemplate issue

I need some help with HierarchicalDataTemplate...
I am trying to build a TreeView to display some hierarchical data
like this:
RuleSet <- (root)
-RuleA
RuleB
RuleC
RuleA
.....
RuleD
RuleA, ... are derived from the same RuleBase that has a
Type
RuleBase[] Rules
RuleSet has
Name
List
my code as far as I get:
<TreeView x:Name="ruleSetTree" Margin="0,10,0,0" ItemsSource="{Binding Path=SelectedTypeRuleSet>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type engine:RuleSet}">
<HierarchicalDataTemplate.ItemTemplate>
<HierarchicalDataTemplate x:Name="leafTemplate"
ItemsSource="{Binding Path=Rules}"
DataType="{x:Type engine:RuleBase}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<TextBlock x:Name="hierarchyItem" Text="{Binding Path=TargetType}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
What I see now is the Name of RuleSet. The toggle button of TreeView is hidden.
I deserialize an xml into my RuleSet model to get the data for this TreeView.
The RuleSet is filled in correctly...can anyone give a hand please?
Thank you!
There is no ItemsSource specified in the first HierarchicalDataTemplate. Shouldn't you bind it to the List property of your RuleSet ?
Why do you nest another hierarchical data template into the existing one? That may be the mistake. Especially because you didn't specify an ItemSource in your first data template. If all the nodes are of type RuleSet you can do it like this:
<TreeView x:Name="ruleSetTree" Margin="0,10,0,0" ItemsSource="{Binding Path=SelectedTypeRuleSet>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type engine:RuleSet}"
ItemsSource="{Binding Path=Rules}">
<StackPanel>
<TextBlock Text="{Binding Path=Name}"/>
<TextBlock Text="{Binding Path=TargetType}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
UPDATE:
Here's an updated version, which should match your requirements. This just works, though, if all the child nodes are of type RuleBase
<UserControl.Resources>
<HierarchicalDataTemplate x:Key="RuleBaseTemplate"
ItemsSource="{Binding Rules}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="RuleSetTemplate"
ItemsSource="{Binding Rules}"
ItemTemplate="{StaticResource RuleBaseTemplate}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding TargetType}"/>
</StackPanel>
</HierarchicalDataTemplate>
</UserControl.Resources>
<!-- rest of the code -->
<TreeView x:Name="ruleSetTree" Margin="0,10,0,0"
ItemsSource="{Binding SelectedTypeRuleSet}"
ItemTemplate="{StaticResource RuleSetTemplate}"/>

WPF: HierarchicalDataTemplate ItemsPanel

I have a ``TreeViewwhich uses a customItemsPanelto show the first level of items in aStackPanel, but I need to show subitems in aStackPaneltoo. The problem is, the second level of items are shown in aWrapPanel, and asHierarchicalDataTemplatedoesn't have anItemsPanel` property I'm not sure how to do this. This is my xaml:
<TreeView x:Name="treGlobalCards">
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel IsItemsHost="True" Orientation="{Binding Orientation,RelativeSource={x:Static RelativeSource.TemplatedParent}}"
MaxWidth="{Binding ActualWidth,RelativeSource={RelativeSource AncestorType={x:Type ScrollContentPresenter}}}"/>
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate x:Key="CardTypeTemplate" ItemsSource="{Binding Cards}">
<TextBlock Text="{Binding Path=CardType}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Create a new DataTemplate that uses a StackPanel and set the HierachicalDataTemplate's "ItemTemplate" to that new DataTemplate.
i.e.
<DataTemplate x:Key="someTemp">
<StackPanel />
</DataTemplate>
<HierarchicalDataTemplate x:Key="hierTemp" ItemSource="{Binding}" ItemTemplate="{StaticResource someTemp}" />

Resources