WPF TreeView Binding to a complex model - wpf

I've started to learn about WPF. And I've chosen to build simple ItemStructureCreator.
I am using MVVM pattern as well.
I implemented some classes, and faced an problem to properly bind it to my TreeView.
Now I want my StructureManagerView to have TreeView control assosiated with my structure.
I tried to bind it like this:
<TreeView Name="tree" DataContext="{Binding MainItem}" Grid.Column="0" Background="Beige">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Item.Children}">
<TextBlock Text="{Binding Item.Code}" HorizontalAlignment="Stretch"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Or like this (Here I think is wrong cause ItemsSource property expects collection):
<TreeView Name="tree" ItemsSource="{Binding MainItem}" Grid.Column="0" Background="Beige">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Item.Children}">
<TextBlock Text="{Binding Item.Code}" HorizontalAlignment="Stretch"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
Can you please help me to set Bindigs correctly.
Regards, Dmitry.

Converting My comment into an answer:
The TreeView doesn't have the concept of a "Main Item".
You should Bind the ItemsSource Property of the TreeView Itself.
ItemsSource="{Binding MainItem}"
should be replaced by
ItemsSource="{Binding MainItems}"
where MainItems is an IEnumerable

Related

WPF binding child controls DataContext to HierarchicalDataTemplate ItemsSource item

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.

TreeView/HierarchicalDataTemplate - How to get the selected item?

<TreeView
x:Name="TreeView"
DataContext="{Binding ApplicationMenu, Mode=TwoWay}"
ItemsSource="{Binding ApplicationMenuNodes}"
Width="Auto"
FontFamily="Segoe UI"
BorderThickness="0"
BorderBrush="Transparent"
Background="Transparent"
>
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type businessobject:ApplicationMenu}"
ItemsSource="{Binding ApplicationMenuNodes}"
/>
</TreeView.Resources>
</TreeView>
I have a treeview with a hierarchical data template. This is bound to a collec tion of ApplicationMenu objects, each containing it's own collection of ApplicationMenu objects.
I'm trying to obtain the selected ApplicationMenu, but I can't seem to find an way to do so. I don't care if it's MVVM or code behind.
Any help would be greatly appreciated.

WPF TreeView selection over entire HierarchyItem

I have a TreeView bound to an MVVM observable collection.
My item template is composed by an image and a textblock like the following code show:
<HierarchicalDataTemplate x:Key="TreeViewItemTemplate" ItemsSource="{Binding Items, Mode=OneWay, NotifyOnSourceUpdated=True}">
<TreeViewItem>
<TreeViewItem.Header>
<StackPanel Orientation="Horizontal">
<Image
Margin="-20,0,5,0"
Source="{Binding Icon, Converter={StaticResource TreeViewIconConverter}, Mode=OneWay}"
Style="{DynamicResource SmallIcon}"/>
<Label Content="{Binding Label}"/>
</StackPanel>
</TreeViewItem.Header>
</TreeViewItem>
</HierarchicalDataTemplate>
The problem happens when you Click over an item. If the Mouse cursor is over the StackPanel, the selection will not happen.
I have included also a screenshot to make this more clear.
Of course this happens because the StackPanel is now over the selection area.
Is there any workaround?
I found the answer by myself.
When you customize the TreeView using an hierarchical data template then you should not replicate the TreeViewItem.Header template because at runtime WPF will create one for you.
So, in order to have a custom TreeViewItem this code is enough:
<HierarchicalDataTemplate x:Key="TreeViewItemTemplate" ItemsSource="{Binding Items, Mode=OneWay, NotifyOnSourceUpdated=True}">
<StackPanel Orientation="Horizontal">
<Image
Margin="0,0,5,0"
Source="{Binding Icon, Converter={StaticResource TreeViewIconConverter}, Mode=OneWay}"
Style="{DynamicResource SmallIcon}"/>
<Label Content="{Binding Label}"/>
</StackPanel>
</HierarchicalDataTemplate>

How to add icons to wpf treeview using dockpanel and binding?

I have a treeview inside of a dockpanel and all of the elements of the treeview are inside HierarchicalDataTemplates. Here is the code:
<DockPanel Margin="10,10,0,0" VerticalAlignment="Stretch" Grid.Row="0" Grid.RowSpan="5" Grid.Column="0">
<DockPanel.Resources>
<src:TreeViewFilter x:Key="MyList" />
<HierarchicalDataTemplate DataType="{x:Type src:TreeViewParent}" ItemsSource="{Binding Path=OrderAttributes}">
<TextBlock Text="{Binding Path=Name}" FontSize="24"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type src:OrderAttribute}" ItemsSource="{Binding Path=OrderAttributes}">
<TextBlock Text="{Binding Path=NameAndCount}" FontSize="16"/>
</HierarchicalDataTemplate>
</DockPanel.Resources>
<TreeView Name="treeView1" BorderThickness="2" ItemsSource="{Binding Source={StaticResource MyList}, UpdateSourceTrigger=PropertyChanged}" TreeViewItem.Selected="treeViewFilter"/>
</DockPanel>
As you can see, the DockPanel wraps around the TreeView. The icons I am trying to add would be in the second HierarchicalDataTemplate which binds to a string and displays as a textbox. Depending on the name of the "NameAndCount", I would choose an icon to be displayed next to it on the left.
Any ideas on a solution for my example? Or do I need to think about using different templates like StackPanel?
Add an Image-Control wherever you want, bind its Source to "NameAndCount" and use a IValueConverter to convert it to an image-path.

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}"/>

Resources