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.
Related
I have a list of parameters in an Observable Collection in my ViewModel that I want to be displayed as textboxes or comboboxes dependent on the datatype, but I'm struggling to find a way to implement any kind of conditional functionality in XAML.
So, say I have an observable collection of parameters (title, datatype, value):
Valid,Boolean,
Name,String,
Age,UInt,
I currently have these generating a sequence of textboxes in the window next to labels indicating the type and parameter name using:
<ItemsControl ItemsSource="{Binding Parameters}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Textbox Text="{Binding Value}"
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But I don't want this to be a textbox every time; I want to be able to have something like an "if" or a "switch" to make a combobox instead if the datatype facilitates pre-defined responses like True/False.
I've seen similar posts where the answers seemed to suggest using Triggers or DataTriggers to do this, which looks exactly like what I need. However, they always seem to put it in a Style, with Style.Triggers, rather than any of the elements I currently have. Any attempts to replicate what I've seen have failed due to slight differences in what we've used; The example will use something like ContentControl and bind the style with "Content = {…}" which I can't do because "Content" isn't something I can apply to "ItemControl", but I need ItemControl due to the way it implements ObservableCollection in a way Content control doesn't.
Is there a simple way to put "If datatype == Boolean, make a combobox here" sort of thing? If I can make this happen in the ViewModel, I'm open to that too. Don't want to be doing anything in the code-behind, as MVVM doesn't seem to play nice with it and has always bit me in the behind later down the road when I try to mix them and I can't get my values to interact properly.
Would very much appreciate any help.
I realise I could just have the user TYPE true/false and interpret it in the viewmodel as Boolean, but there's several reasons this won't really work in my case. For one thing, there will be many, many options.
Really think you should be using DataTemplates:
... xmlns:sys="clr-namespace:System;assembly=mscorlib"
<ItemsControl ItemsSource="{Binding Parameters}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type sys:Boolean}">
<Checkbox IsChecked="{Binding}" />
</DataTemplate>
<DataTemplate DataType="{x:Type sys:String}">
<TextBlock Text="{Binding}" />
</DataTemplate>
</ItemsControl.Resources>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Title}" />
<ContentPresenter Content="{Binding Value}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
You can use your own types as well that it will auto detect and use the datatype for.
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.
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.
I know this has been asked before but Im a bit confused !
I'm writing my app with MVVM so far so good. but now I need to know what is the best way to access my controls inside a data template in a listbox.
I want to access them through the code behind and also be able to change them based on the other values from the database !
Here is the view :
<ListBox Margin="0,8,0,0" toolkit:TiltEffect.IsTiltEnabled="True" x:Name="counterlist" ItemsSource="{Binding Groups}" HorizontalAlignment="Center" Tap="list_OnTap"
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Background="Orange" Width="125" Height="125" Margin="6">
<TextBlock Name="name" Foreground="White" Text="{Binding Name}" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
<TextBlock Name="items" Foreground="White" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
This list box is bound to the Groups Observable collection in my viewModel. Again so far so good.
Now I have a method called
public int ItemsinGroup(int gid)
This method returns number of items in each group but its not simply based on this database and it also get some info from an external source so I cant simply make a query to add this also to the observable collection.
I just need to add this to each item in the list box so that it shows the associated item counts for each group.
I want to be able to change it in the code behind. I mean I want to access each loop of data in code behind as well as XAML (Which we are already doing it through binding) .
If I can do so it will be easy to inject ItemsinGroup results to its related item in the list box loop.
Can I do that by placing my method in viewModel ? but what about the current item in the loop, how can I find out what is the current ID of each Group in the listbox loop ?
I need to know what is the best way to do such things, what usually everyone does in these cases !
Thanks a lot
Your desire to use MVVM and yet update individual items in a collection from code behind seem contradictory.
This simplest solution is probably to get your collection of groups and before you bind them to the UI you loop through them and add the count to the objects in your collection.
Alternatively, if you want to bind the collection as quickly as possible and then update it. You could step through the collection once bound and as long as the objects in your collection implement INotifyPropertyChanged you could update them and have a second TextBlock in the ItemTemplate show this when set.
I have a TreeView databound to a CollectionViewSource Groups collection. This is so that I can display the data using the power of the CollectionViewSource, and the data itself also has a hierarchical structure, which is why I need the TreeView. I have a second control which is bound to the SelectedItem of the TreeView.
The problem is that when the group header is selected, the program crashes with the following exception.
{"A TwoWay or OneWayToSource binding cannot work on the read-only property 'Name' of type 'MS.Internal.Data.CollectionViewGroupInternal'."}
The objects in my TreeView contain a Name property that is two way bound in another control. The binding engine seems to find the Name property for the Group and attempt to bind to that. How can I prevent this exception from occuring? I would like for the rest of my program to treat it as if nothing is selected when the group header is selected, or disallow selecting the group header all together. Below is a simplified version of the code.
<TreeView
x:Name="CustomersTree"
ItemsSource="{Binding CustomersViewSource.Groups}"
ItemTemplate="{StaticResource CustomerGroupsTemplate}">
<MyUserControl DataContext="{Binding ElementName=CustomersTree, Path=SelectedItem, Mode=OneWay}" />
<HierarchicalDataTemplate x:Key="CustomerGroupsTemplate" ItemsSource="{Binding Path=Items}" ItemTemplate="{StaticResource CustomerTreeItemTemplate}">
<TextBlock Text="{Binding Path=Name}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="CustomerTreeItemTemplate" ItemsSource="{Binding Customers}">
<StackPanel>
<Image Source="{Binding ImageSource}" />
<TextBlock Text="{Binding Path=Name}" />
</StackPanel>
</HierarchicalDataTemplate>
To be clear, the error is a result of the binding in the CustomerGroupsTemplate as far as I can tell, and changing this binding to OneWay results in the same error. The information in the tree shows up the way it is expected to, it is only when a group header is selected that the exception occurs.
The problem was the result of a two way binding within the user control. I ended up using a converter to check for the type of the object being bound, ignoring it if it wasn't the object I wanted.