TreeView with multiple levels - wpf

Of the following code
<TreeView Name="tree" ItemsSource="{Binding Path=AllNotes}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type m:Note}" ItemsSource="{Binding Path=ListIssuesType}">
<TextBlock Text="{Binding Path=SoftwareVersion}" Margin="2" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type m:IssueType}" ItemsSource="{Binding Path=IssueNames}">
<TextBlock Text="{Binding Path=IssueTypeName}" Margin="2" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type m:IssueType}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=IssueTypeName}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
I get the error:
"Item has already been added. Key in dictionary: 'DataTemplateKey(ReleaseNotes_Window.Models.IssueType)' Key being added: 'DataTemplateKey(ReleaseNotes_Window.Models.IssueType)'"

When you put something into a ResourceDictionary it either needs an explicit x:Key or the key will be determined by the DictionaryKeyPropertyAttribute applied on the class.
For DataTemplate it is the following:
[DictionaryKeyProperty("DataTemplateKey")]
public class DataTemplate : FrameworkTemplate
This will depend on the DataType.
Because you have:
<HierarchicalDataTemplate DataType="{x:Type m:IssueType}" ItemsSource="{Binding Path=IssueNames}">
<TextBlock Text="{Binding Path=IssueTypeName}" Margin="2" />
</HierarchicalDataTemplate>
And
<DataTemplate DataType="{x:Type m:IssueType}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=IssueTypeName}" />
</StackPanel>
</DataTemplate>
Both with DataType="{x:Type m:IssueType}", that's why the program fails.
Use an additional x:Key for one of the DataTemplates and reference it as a StaticResource where you're planning to use it.

Related

WPF DataTemplate and binding with TextBlock

<Window.Resources>
<DataTemplate x:Key="pointGroupTemplate" DataType="{x:Type ac:PointGroup}">
<TextBlock Text="{Binding Name}" />
</DataTemplate>
<DataTemplate x:Key="tt2" DataType="{x:Type ac:PointGroup}">
<TextBlock Text="{Binding PointsCount}"/>
</DataTemplate>
</Window.Resources>
the first template works well with:
<ComboBox x:Name="comboBox1" ItemTemplate="{StaticResource pointGroupTemplate}" SelectionChanged="ComboBox1_SelectionChanged"
Height="25" Margin="0,5,0,5">
but i want to use the second one in a textblock
<TextBlock x:Name="textBlock1" Text="{Binding ElementName=comboBox1 ,Path=SelectedItem ?????}"/>
anyhelp.
In order to have a DataTemplate applied, you need a ContentPresenter or ContentControl:
<ContentControl ContentTemplate="{StaticResource tt2}"
Content="{Binding SelectedItem, ElementName=comboBox1}"/>

How to disable DataTemplate at a specific place?

Consider the following model:
var model = new object[] { "Ala ma kota", DateTime.Now };
Now, let's suppose, that we have the following DataTemplates for ListBox displaying this model:
<ListBox ItemsSource="{Binding Data}">
<ListBox.Resources>
<DataTemplate DataType="{x:Type sys:String}">
<StackPanel Orientation="Horizontal">
<TextBlock>String:</TextBlock>
<TextBlock Text="{Binding}" />
</StackPanel>
</DataTemplate>
<DataTemplate DataType={x:Type sys:DateTime}">
<StackPanel Orientation="Horizontal">
<TextBlock>Data i czas:</TextBlock>
<Calendar DisplayDate={Binding Mode=OneWay}" />
</StackPanel>
</DataTemplate>
</ListBox.Resources>
</ListBox>
If we run such program, quite funny effect will be achieved:
Is there a way to disable DataTemplate on some level? I'd like to "block" it in the second DataTemplate, such that the calendar will be displayed correctly.
One way i can think of is to take advantage of resource lookup behaviour in WPF. It traverses up the Visual tree till found a default resource for a control.
You can define resource locally for string inside dataTemplate of DateTime so that it gets applied locally for your DateTime template and for others it will continue to behave same:
<DataTemplate DataType="{x:Type sys:DateTime}">
<StackPanel Orientation="Horizontal">
<StackPanel.Resources>
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock Text="{Binding}"/>
</DataTemplate>
</StackPanel.Resources>
<TextBlock>Data i czas:</TextBlock>
<Calendar DisplayDate="{Binding Mode=OneWay}" />
</StackPanel>
</DataTemplate>
Output:

How can I specify multiple DataTemplate in windows.resources for use by a ContentControl

How can I specify multiple DataTemplate in windows.resources for use by a ContentControl?
My code:
<Window.Resources>
<DataTemplate x:Key="CustomerTemplate" DataType="{x:Type local:Customer}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text=" ("/>
<TextBlock Text="{Binding Occupation}"/>
<TextBlock Text=")"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="PersonTemplate" DataType="{x:Type local:Person}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstName}"/>
<TextBlock Text=" - "/>
<TextBlock Text="{Binding LastName}"/>
</StackPanel>
</DataTemplate>
</Window.Resources>
Thank you so much!
Use DataTemplateSelector to return the Datatemplate you want to be applied..
<ContentControl ContentTemplateSelector="{StaticResource MyTemplateSelector}"/>
here MYtemplateselector is DataTemplateSelector, in Select() method of selector you can check for the property bound to contentcontrol and return the corresponding Datatemplate.
Thanks
Remove x:Key from DataTemplate and try this:
<ContentControl Name="CustomerContentControl">
<local:Customer />
</ContentControl>
<ContentControl Name="PersonContentControl">
<local:Person />
</ContentControl>
In this article, Josh Smith show, how to get access the elements that are in the DataTemplate:
How to use FindName with a ContentControl

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

How can I change Item and Content Templates based on the object type?

I have a WPF TabControl that I have set the ItemTemplate as well as the ContentTemplate. This tab control displays Call Log information based on customer tech support information.
Inside of this same control, I would also like to be able to show a ReturnAuthorization template.
I would like to swap these out based on the object type added to the TabControl's Items collection. Is this something that is possible?
I have some Pseudo-code that sort of shows what I want to pull off:
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True" ItemContainerStyle="{StaticResource ClosableTabItemTemplate}" >
<TabControl.ItemTemplate>
if ( Type is Entities:Case )
{
<DataTemplate DataType="{x:Type Entities:Case}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
}
else if ( Type is Entities1:RAMaster )
{
<DataTemplate DataType="{x:Type Entities1:RAMaster}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
}
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
One way to do this is using something like an ItemTemplateSelector, which you can set on the TabControl. However, if you only need the different templates within the TabControl and know what they all are ahead of time, then you can just let them automatically be applied by using the DataTypes.
<TabControl x:Name="tabCases" IsSynchronizedWithCurrentItem="True" ItemContainerStyle="{StaticResource ClosableTabItemTemplate}" >
<TabControl.Resources>
<DataTemplate DataType="{x:Type Entities:Case}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
<DataTemplate DataType="{x:Type Entities1:RAMaster}">
<TextBlock Text="{Binding Path=Id}" />
</DataTemplate>
</TabControl.Resources>
<TabControl.ContentTemplate>
<DataTemplate DataType="{x:Type Entities:Case}">
<CallLog:CaseReadOnlyDisplay DataContext="{Binding}" />
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>

Resources