Custom TreeViewItem Structure - c#

I've to create a custom tree structure which should looks like:
-Start
--Process
--Decision
---DecisionOption
----Process
----Process
---DecisionOption
----Process
Each of these Types has a set of custom attributes. Basically a TreeViewItem structure works fine and the 'hierarquical facilities' (like get parent and childs) within is a plus.
What is 'best' way to do it?
I did some ways but I'm having problem when trying to apply HierarquicalDataTemplates. (e.g.). It simply doesn't work.
<HierarchicalDataTemplate DataType="{x:Type local:Start}" ItemsSource="{Binding Items}">
<Border >
<TextBlock Text="{Binding Path=Title}" />
</Border>
</HierarchicalDataTemplate>
Any ideias how to implement that structure?

This shows the multi-tiered Treeview -- Here is a step by step usage of HierarchicalDataTemplate
As Mike indicates in the second article the HDT does not exactly program itself. Follow his steps for using it to create an East/West conference list and you should have your answer as what to do.

Related

WPF Designer DataTemplate.DataType cannot be type object

I have a tree view that I'm binding to with some custom viewmodels. The viewmodels are in an ObservableCollection and inherit ViewModelBase which inherits INotifyPropertyChanged.
It compiles and run fine, but in the designer I'm getting the error:
"DataTemplate.DataType cannot be type object
Parameter name: value"
My XAML is:
<TreeView Grid.Row="1" ItemsSource="{Binding ResultsTree}" SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:TreeViewItemViewModel}" ItemsSource="{Binding Path=Children}">
<StackPanel Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:CorrectionAndFreqViewModel}">
<StackPanel Orientation="Horizontal" ToolTip="{Binding AmbientText}">
<Rectangle Width="20" Height="5" Fill="{Binding LineColor, Converter={StaticResource ColorToSolidColorBrushValueConverter}}"></Rectangle>
<CheckBox IsChecked="{Binding IsChecked}"/>
<TextBlock Text="{Binding Text}"/>
</StackPanel>
</DataTemplate>
</TreeView.Resources>
</TreeView>
The properties window says its an Object too, but I have no idea why:
Any ideas?
I was able to solve this WPF Designer Bug by adding a x:Key to the DataTemplate
<ResourceDictionary>
<DataTemplate x:Key="ThisKeySolvesDesignersNullRef"
DataType="viewmodels:MyViewModel">
<views:MyView/>
</DataTemplate>
</ResourceDictionary>
I had been searching for months, because it eventually appeared on different projects and sometimes appeared and disappeard without an explicit reason.
Thanks to the helping answer on SO
I think it wants you to use an interface type instead of a class type.
So, if you define an interface ICorrectionAndFreqViewModel that exposes all of the properties that you'll be using for data binding and then have CorrectionAndFreqViewModel implement that interface, you should be good.
Like you said, the code will still compile and run without using an interface here. My guess as to why the designer complains about this is that data binding can only be used on public properties, so by using an interface, there's a guarantee that all the properties will be public.
You should have an xmlns tag like local, l, or some such. In the datatype you need to use local:CorrectionAndFreqViewModel rather than {x:Type CorrectionAndFreqViewModel}. If you don't have one of these xmlns values then you need to define it so that it points to the dll that you're using (or use a different marker if you're looking at another project e.g. xmlns:msl="clr-namespace:MediaSystems")
I was able to fix this by making sure the file name is exactly as the class name.
I had the same problem. To fix do the following:
Build and rebuild the project successfully.
Go to Tool > Option > XAML > Uncheck Automaticaly name interactive....
Restart Visual Studio, and then the problem will go away.
Instead of 'object' set the 'DataType' to your actual view model type (e.g CorrectionAndFreqViewModel in your case) in properties.
Hope this will fix the issue.
Please mark it as answer if satisfies.
Ideally, it should automatically pick correct data type in properties, in my case it works correct.

How do you add a button to a TreeView using a HierarchicalDataTemplate?

I've got a TreeView that is constructed like this:
//This is for dynamically building a treeview with templates from an XML file
XmlTextReader xmlReader1 = new XmlTextReader("HierarchicalDataTemplate1.xml");
HierarchicalDataTemplate hierarchicalDataTemplate1 = XamlReader.Load(xmlReader1) as HierarchicalDataTemplate;
And it reads an XML file like this:
<HierarchicalDataTemplate xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" ItemsSource="{Binding XPath=SubCategory}">
<TextBlock FontSize="36" FontFamily="K22 Monastic" Text="{Binding XPath=#CategoryName}" />
<Button>Add Subordinate Unit</Button>
</HierarchicalDataTemplate>
But it throws a runtime error on adding the button:
''Template' property has already been set on 'HierarchicalDataTemplate'.' Line number '3' and line position '4'.
Is what I'm trying to do possible? If I take out the script for adding a button everything works fine.
Thanks!
One obvious error is that you've got two elements at the root level of the template's visual tree. You can't do that. A DataTemplate or HierarchicalDataTemplate can have only one child. So your first step is to make that one child a control that supports multiple children of its own, then put your TextBlock and your Button in that. StackPanel is a good one:
<HierarchicalDataTemplate
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
ItemsSource="{Binding XPath=SubCategory}"
>
<StackPanel Orientation="Horizontal">
<TextBlock
FontSize="36"
FontFamily="K22 Monastic"
Text="{Binding XPath=#CategoryName}"
/>
<Button>Add Subordinate Unit</Button>
</StackPanel>
</HierarchicalDataTemplate>
It's interesting to note that when I paste your template XAML into the XAML designer, I get a different error: "The property 'VisualTree' is set more than once" -- but when I duplicate your XamlReader.Load(), code, I get the same exception and message as you (and the same fix corrects it).
Google turns up zero results for "Template property has already been set on HierarchicalDataTemplate". Well, maybe it'll have one now.

Treeview "Items collection must be empty before using ItemsSource."

If I use the following code without <DataTemplate> it is working and I can see only the SoftwareVersion, when I add <DataTemple> throws an exception. Any idea why?
ObservableCollection<Note> AllNotes
<TreeView Name="tree" ItemsSource="{Binding Path=AllNotes}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type m:Note}" ItemsSource="{Binding Path=ListIssuesType}">
<TextBlock Text="{Binding Path=SoftwareVersion}" Margin="2" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<DataTemplate DataType="{x:Type m:IssueType}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=IssueTypeName}" />
</StackPanel>
</DataTemplate>
</TreeView>
It is not clear at all why you are adding a DataTemplate to your control. But it is clear why you are getting the exception: you have added the DataTemplate object as a direct child of the TreeView, which makes it an item in the Items collection. It's "template" nature becomes completely irrelevant; you are telling the control to just include that object as an element in the view.
And of course, now that the Items collection is non-empty, you are not allowed to send the ItemsSource property.
So the fix for the exception is "don't do that". I.e. stop trying to make the DataTemplate element an item in the tree view's list of items.
Beyond that, there's not enough context in your question to say how you should be using the DataTemplate object. Presumably you intend it to be used as part of the template for an actual data item in the tree view; maybe it needs to be incorporated into the HierarchicalDataTemplate somehow.
But without more specifics regarding exactly what the code does now and what you want it to do instead, as well as you providing a good Minimal, Complete, and Verifiable example clearly illustrating your scenario, I don't see a good way to address that part of your problem. If you still need help with defining the data template, please post a new question that provides the necessary details.

ContentPresenter in ItemControl.ItemTemplate to show displaymemberpath of itemscontrol

I want to know is there anyway to put contentpresenter in itemtemplate of an itemscontrol to display my data. I don't want hard code binding like Text="{Binding username}" cause I am building a custom control, I think ContentPresenter is what I want. But after I tried using contentpresenter, it give me stackoverflowexception.
<ItemsControl ItemsSource="{Binding SelectedItems, ElementName=listbox}" DisplayMemberPath={Binding DisplayMemberPath}">
<ItemsControl.ItemPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="Separator" Text=", "/>
<ContentPresenter/>
<!--<TextBlock Text="{Binding username}"/>-->
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
That's my code.
If without those seperator and itemtemplate, I able to display my data by just using the displaymemberpath, but it stack all the name together. I still finding any solution to solve it. I hope you can provide some ideas to do this.
The answer is no, you can't. A ContentPresenter is supposed to be used in a ControlTemplate, not a DataTemplate, so it is not the right control to use. From the linked page on MSDN:
You typically use the ContentPresenter in the ControlTemplate of a ContentControl to specify where the content is to be added.
What you can do alternatively, is to declare a number of DataTemplates in a Resources section (complete with Binding Paths) for different types of data and omit the x:Key directives, eg. do not name them. Also, do not specify one for the ItemsControl.ItemTemplate.
When doing this, WPF will implicitly select the correct DataTemplate for the relevant data type and so you can have different outputs for different data types. See the The DataType Property section of the Data Templating Overview page on MSDN for further explanation of this technique.
Yes, and it works well. Outside of a ContentControl's template, you must bind the Content by hand:
<ContentPresenter Content="{Binding username}"/>
I do this a great deal and it never misbehaves. ContentPresenter seems to be implemented for general use. I wonder if the API docs overstate its relationship to ContentControl.
I found an easier way to solve this problem by using horizontal listbox. Thanks for responses

HierarchicalDataTemplate: first level of children only

I have a tree view of items, which currently shows all the levels of children, down to the furthest. How can I achieve to show only the first level of children? Is the HierarchicalDataTemplate the wrong approach, perhaps? Collapsing the children of level 2 and further would not be sufficent.
How about using a filtered version of your datasource so only the levels you want are included, then you can use a HierarchialDataTemplate without any problem.
Just use a DataTemplate, instead of the HierarchicalDataTemplate.
Edit: Got it. There's a number of options. Tommy's recommendation above is a good one and elegant. Another option is to override the TreeViewItem's ControlTemplate for any item whose children you don't want to see and hide the expander area.
Well, without manipulating the data it's not possible to just show one level of children. The control would have needed a property, which is able to determine the deepness of shown nodes.
This solution came to me and was quite obvious: I just use two flat tree views, the second one dependent on the SelectedItem of the first one. No HierarchicalDataTemplate needed, at all. Just a common DataTemplate.
As I understand it, you want the top level nodes, and 1 level of children of those, and no further (so there will be 2 levels of nodes overall). Then you can do it with 2 templates if you want to do it in XAML:
<Grid>
<Grid.Resources>
<DataTemplate x:Key="TemplateLeaf">
<TextBlock Text="{Binding Text}" /> <!-- Whatever leaf view you want -->
</DataTemplate>
<sdk:HierarchicalDataTemplate ItemsSource="{Binding Items}" ItemTemplate="{StaticResource TemplateLeaf}" x:Key="TemplateNode">
<TextBlock Text="{Binding Text}" />
</sdk:HierarchicalDataTemplate>
</Grid.Resources>
<sdk:TreeView ItemsSource="{Binding Items}" ItemTemplate="{StaticResource TemplateNode}" />
</Grid>
(That's the Silverlight version but it's the same). By default the HierarchicalDataTemplate uses itself as its own ItemTemplate, but you can replace that with some other template for the next level (including a plain DataTemplate) if you want.

Categories

Resources