WPF: The key is already defined in this scope - c#

I'm working with TreeView and I want two ObservableCollections (KategorijeLekovi and KategorijeRadnici) to be shown under a node (which is an object of class Apoteka). I get this error: "The key is already defined in this scope." and it reffers to the second DataType="{x:Type local:Apoteka}". However, if I delete this DataType, I get a different error: "All objects added to an IDictionary must have a Key attribute or some other type of key associated with them."
<TreeView Grid.Column="0" Grid.Row="0" Name="trv1" >
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Apoteka}" ItemsSource="{Binding KategorijeLekovi}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Naziv}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Apoteka}" ItemsSource="{Binding KategorijeRadnici}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Naziv}"/>
</StackPanel>
</HierarchicalDataTemplate>
...

Thank you all for answering, I managed to solve it with your help. Instead of having two ObservableCollections I made one, which had items from both KategorijeLekovi and KategorijeRadnici

You just need to use the x:key attribute
<HierarchicalDataTemplate x:Key="LekoviTemplate" DataType="{x:Type local:Apoteka}" ItemsSource="{Binding KategorijeLekovi}">
<HierarchicalDataTemplate x:Key="RadniciTemplate" DataType="{x:Type local:Apoteka}" ItemsSource="{Binding KategorijeRadnici}">
Then set it in the tree view,
<TreeView ItemTemplate="{StaticResource LekoviTemplate}" ...
or
<TreeView ItemTemplate="{StaticResource RadniciTemplate}" ...

Related

WPF TreeView - Confusing data binding and style for child nodes

I am confused of WPFs data binding and style declaration for TreeViews, especially for child nodes.
My ViewModel contains an object with the following hierarchy:
- Component1
- SubcomponentA
- SubcomponentB
- Component2
- SubcomponentX
- SubcomponentY
- SubcomponentZ
I would like to modify the XAML file so I do not have to do anything within the .cs file.
This piece of code actually works:
<TreeView Name="tvComponent" ItemsSource="{Binding BpModule.BpComponentPrototypes.Elements}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding BpSubcomponents.Elements}">
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_run"></CheckBox>
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
However, I would like to create different styles for root and child nodes.
I tried different approaches with almost completely different XAML code. But the major problem was to describe the dependency of the binding of child nodes to their parent and so they remained empty during runtime.
Can you help me out?
Thank you.
In my opinion you can use the implicit DataTemplate mechanism (take a look here to the DataType property). In this way you can define more DataTemplates, each one of them "linked" to a specific Type.
<TreeView Name="tvComponent" ItemsSource="{Binding BpModule.BpComponentPrototypes.Elements}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:RootType}"ItemsSource="{Binding ...}">
...
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:ComponentType}" ItemsSource="{Binding BpSubcomponents.Elements}">
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_run"></CheckBox>
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:SubcomponentType}">
...
</DataTemplate>
</TreeView.Resources>
</TreeView>
Otherwise you can always use a DataTemplateSelector to create your own logic which chooses the right template for you.
Well, somehow I achieved to provide different designs for root and children nodes. Here is the XAML code:
<TreeView Name="tvSoftwareComponentPrototypes" ItemsSource="{Binding Path=BpModule.BpComponentPrototypes.Elements}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding BpSubcomponents.Elements}">
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_run"></CheckBox>
<Image Source="/Resources/SubComponent.png" Margin="5,0,3,0" />
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
<StackPanel Orientation="Horizontal">
<CheckBox Name="cb_swc" Checked="cb_swc_Checked" Unchecked="cb_swc_Unchecked"></CheckBox>
<Image Source="/Resources/Component.png" Margin="5,0,3,0" />
<TextBlock Text="{Binding ShortName}" />
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
And the next problem is that I cannot access the Checkboxes at runtime.
WPF freaks me out :/
EDIT:
Hold on .. actually this is quite easy by changing the checkbox to the following XAML code:
<CheckBox Name="cb_swc" IsChecked="{Binding Path=PropertyName, Mode=TwoWay}"/>

How to attach a different DataTemplate to the Same Hierarchical Template

Is it possible to attach different DataTemplates so that the children render differently to the same HierarchicalDataTemplate, which as I understand controls the View of the header
I am trying to do it without success::
<Window.Resources>
<DataTemplate
x:Key="ChildTemplate1">
<Label Content="Blah">
</DataTemplate>
<DataTemplate
x:Key="ChildTemplate2">
<Label Content="Blah2">
</DataTemplate>
<HierarchicalDataTemplate
x:Key="RootTemplate"
ItemTemplate={StaticResource ChildTemplate2}"
ItemsSource="{Binding Path=Children}">
<Label Content="Header">
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView ItemTemplate="{StaticResource RootTemplate}">
<TreeViewItem ItemTemplate="{StaticResource ChildTemplate1}"/>
</TreeView>
So again, what I am trying to do is override the DataTemplate set in HierarchicalDataTemplate(ChildTemplate2) with ChildTemplate1

WPF: Binding a Recursive Dictionary to TreeView

I want to use XAML to display a TreeView of Dictionary<string, object>. Every Dictionary's Value is either a string, a Dictionary<string, object> or Dictionary<string, object[]>. I'm unable to find XAML that displays all three cases. The following XAML will show a nice TreeView but the terminal nodes (string), are blank lines. What's the correct XAML or do I have to use a converter?
<TreeView>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Value}">
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
You should provide more than one template with specialization for the strings:
<TreeView xmlns:system="clr-namespace:System;assembly=mscorlib">
<TreeView.Resources>
<HierarchicalDataTemplate ItemsSource="{Binding Value}">
<TextBlock Text="{Binding Key}"/>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type system:String}">
<TextBlock Text="{Binding}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
Create multiple hierarchical data templates, then use an ItemTemplateSelector to select between them based on the type of the object being displayed.

Unable to bind model to TreeView

This is a logging project, the Title provides the name of the item and the message logs each stage. Therefore, there are many Messages for each Title.
For the purpose of asking a question, I am simplifying my objects.
My Log class has 2 properties.
List<LogDetails>
string Title
And my LogDetails class has 1 property:
string Message
I am not able to bind the Message to my XAML. The Title binds as desired.
My xaml code:
<Window x:Class="BackUps.Logging.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:myData="clr-namespace:BackUps.Logging"
Title="MainWindow"
Height="350"
Width="525">
<Grid>
<TreeView ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type myData:Log}"
ItemsSource="{Binding LogDetailsList}">
<TextBlock Text="{Binding Title}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type myData:LogDetails}">
<StackPanel>
<TextBlock Text="{Binding Message}" />
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
and my code behind
public MainWindow(List<Log> logs)
{
InitializeComponent();
this.DataContext = logs;
}
My result is (where you can see the missing entries):
This is the Auto's window, which shows the object I'm trying to bind.
What have I missed or doing wrong?
I had a similar problem in the past, and fixed it by (completely) changing the xaml to the form:
<Grid>
<TreeView ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type myData:Log}"
ItemsSource="{Binding LogDetailsList}">
<TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type myData:LogDetails}>
<TextBlock Text="{Binding Message}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>

Binding WPF TreeView to Object

How to bind TreeView to the grouping collection ListCollectionView?
code cs:
ListCollectionView view=new ListCollectionView(Global._subjectCollection);
view.GroupDescriptions.Add(new PropertyGroupDescription("Fund"));
view.GroupDescriptions.Add(new PropertyGroupDescription("Cipher"));
treeView1.ItemsSource = view.Groups;
code XAML:
<TreeView>???</TreeView>
Check out Bea Stollnitz's blog entry "How do I display grouped data in a TreeView?".
You use a HierarchicalDataTemplate to present the CollectionViewGroup. The Name property will have the value of the property you grouped by, so the value of Fund or Cipher, and the Items property will have the nested group for outer groupings and the actual object for the innermost grouping. It will look something like this:
<Window.Resources>
<!-- Template for actual object -->
<DataTemplate x:Key="ThirdTemplate">
<TextBlock Text="{Binding OtherData}"/>
</DataTemplate>
<!-- Template for Cipher groups -->
<HierarchicalDataTemplate x:Key="SecondTemplate"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource ThirdTemplate}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
<!-- Template for Fund groups -->
<HierarchicalDataTemplate x:Key="FirstTemplate"
ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource SecondTemplate}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</Window.Resources>
<TreeView Name="treeView1" ItemTemplate="{StaticResource FirstTemplate}"/>

Categories