WPF TreeView data binding to custom objects - c#

I am having trouble understanding how to Bind Data to a WPF TreeView when custom objects are used. I have researched and watched tutorials but I am still stuck.
BACKGROUND: consider three classes (I have simplified my problem to this). They represent a database which has a Table, each table can have Fields. There are a list of Tables.
1) TableList Class
With Property
List<Table Objects>
2) Table Class:
Property Name
With a TableFields Property
SortedDictionary <Name, Field Object>
3) Field Class:
With a Name Property
An example of my current attempt to bind a field (lowest level) to Table.TableFields.Key
<DataTemplate x:Key="fieldTemplate">
<TextBlock Text="{Binding Path=Table.TableFields.Key}"/>
</DataTemplate>
DESIRED OUTPUT - a hierarchical view of the table list, containing tables and their fields.
Table 1
Field 1
Field 2
Field 3
Table 2
Field 1
Field 2
Field 3
Table N
Field N
I am after guidance so I can better understand how to bind this data, an example of my issue is the data binding has to look at a Table Objects TableFields property which is a SortedDictionary, in which I want to get the Key which will be a Field Name.
I am confused with how to bind custom objects and access the information like this.

This will display your TreeView
<TreeView ItemsSource="{Binding TableList}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource = "{Binding Path=TableFields}">
<TextBlock Text="{Binding Path=Name}"/>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Key}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Related

Binding to multiple objects

In my current situation, I have a list to display in my app. This list should be based on two things. Description, and a color, which is based on the current state of each element. The challenge is that description and color are set in each their own tables. Is there a way to set my itemsource/ bindingcontext to two different objects/ tables? Or is there a different way to solve this problem?
This is my XAML file binding to the table where the description is accessible:
<StackLayout>
<ListView x:Name="postListView" ItemSelected="Handle_ItemSelected" >
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Description}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
In my code behind postListview is set to one of the tables:
PostListView.itemSource = _chekc;
I am not able to set two different itemsources, thus not able to bind to color in my other table _answer.
Any workaround for this?
This is a common problem: you have to display a list that is a combination of data from more than one table. The fact that you cannot set the ItemsSource to more than one source is not a bug in the ListView that has to be worked around...it is a limitation in your design...you need to construct a view model that properly handles this situation.
So one way of doing this is to have a PostRowView class that is a pairing of color and description from your two tables and a ObservableCollection that manages the PostRowViews. You bind the ItemsSource of the ListView to the observable collection.

C# TreeView and binding to a database

I'm querying a database via a stored procedure and getting data back. which I'm populating into an object as such:
private GetMiscVars _batchVariablesData;
public GetMiscVars BatchVariablesData
{
get { return _batchVariablesData; }
set
{
if (_batchVariablesData == value) return;
_batchVariablesData = value;
OnPropertyChanged("BatchVariablesData");
}
}
In my XAML I have this:
<TreeView>
<TreeViewItem Header="Batch Data" ItemsSource="{Binding BatchVariablesData}">
<TreeViewItem.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding VarDesc}" />
</DataTemplate>
</TreeViewItem.HeaderTemplate>
</TreeViewItem>
</TreeView>
What I am seeing when my code runs is my parent node is blank instead of saying "Batch Data" like I hoped and my child nodes return the name of the ObservableCollection used in calling the database, in this DgTabData.
So, where am I screwing things up?
Thanks
To clarify a little bit more, I have a stored procedure that returns data that looks like this:
VarId EventId VarDesc
11 2489 WP1.WC01 Quantity
1196 2489 WP1.WC01 Brew Number
1197 2489 WP1.WC01 Operator Name
1216 2489 WP1.WC01 Integer Test
1217 2489 WP1.WC01 Logical Test
1218 2489 WP1.WC01 Float-4 Test
1219 2489 WP1.WC01 Float-3 Test
I want to take the VarDesc field and place it in a TreeView under a heading of Batch Data. Once I can figure this out I want to be able to grab the VarId and EventId values from the item selected in the TreeView as I will use those to populate a datagrid.
Firstly, a TreeView displays hierarchical data. That means that your data must have a public collection property to use for the child nodes. Next, to display hierarchical data, you need to declare a HierarchicalDataTemplate, rather than trying to define the controls as you were. Try this XAML instead:
<TreeView ItemsSource="{Binding CollectionOfParents}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type YourPrefix.YourClassName}"
ItemsSource="{Binding CollectionOfChildrenPropertyInParent}">
<TextBlock Text="{Binding PropertyInParent}" /><!-- Parent DataTemplate -->
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate> <!-- Child DataTemplate -->
<TextBlock Text="{Binding PropertyInChild}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
UPDATE >>>
As I said, a TreeView displays hierarchical data. That means that your data must have a public collection property to use for the child nodes. So create a class, let's say named Data, with a property to hold the Batch Data text, let's say named Name, and an ObservableCollection<string> property, let's say named Items to hold the VarDesc column values.
Then you need to populate the collection with the items returned from the stored procedure in any way you see fit. Finally, create an ObservableCollection<Data> property, let's say named DataItems in the code behind or view model and add your Data class, complete with collection items. Then you could bind to the TreeView like this:
<TreeView ItemsSource="{Binding DataItems}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type YourXamlNamespacePrefix.Data}"
ItemsSource="{Binding Items}">
<TextBlock Text="{Binding Name}" /> <!-- Parent DataTemplate -->
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate> <!-- Child DataTemplate -->
<TextBlock Text="{Binding}" />
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>

TreeView and Entity Framework binding

I'm new to WPF and EF; I've looked but I wasn't able to find appropriate help.
This is what I have:
Entity Framework (ReportDefinition.ParentID and ReportDefinition.SectionID are Section.idSections), ReportDefinition example and Section example.
This is what I would like to present:
TreeView.
.
I'm trying to achieve this programmatically. I would much appreciate any help.
You need a collection of top-level ReportDefinition objects:
TopLevelReportDefinitions = ReportDefinitions.Where(rd => rd.ParentID == 0)
You need to bind this collection to the ItemsSource of the TreeView.
In EF, you also need to create a parent-child relation on ReportDefinition linking the children to the parent using ParentID. For convenience you can name the reverse collection Children. The collection of ReportDefinition objects directly below another ReportDefinition is then the collection:
ReportDefinition.Children
You then have to create HierarchicalTemplate in the TreeView:
<TreeView ItemsSource="{Binding TopLevelReportDefinitions}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Name}"/>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

Collection View Source Grouping in Tree View - Binding Error

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.

How to create a template to display data from a class in WPF

I have a data layer which is returning lists of classes containing data. I want to display this data in my form in WPF. The data is just properties on the class such as Class.ID, Class.Name, Class.Description (for the sake of example)
How can i create a custom control or template an existing control so that it can be given one of these classes and display its data in a data-bound fashion.
Thanks :)
You could use a ListBox and set its ItemsSource property to the list containing your data items. Then you define a DataTemplate for your type like this:
<DataTemplate x:Key="MyDataTemplate" DataType="{x:Type MyType}">
<StackPanel>
<TextBlock Text="{Binding ID}"/>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Description}"/>
</StackPanel>
</DataTemplate>
...and tell the ListBox to use this DataTemplate by setting the ItemTemplate property.
It is also sufficient to just define the DataTemplate as above and give it no key. Then it will be used for all items which have the respective type.
BTW: You can find a more detailed example in MSDN on the page for the ItemTemplate property.

Categories

Resources