TwoWay Binding WPF Treeview - c#

WPF beginner here.
I managed to bind a TreeView control to a DataViewManager using the code shown at the end of this post. Everything works fine when populating the TreeView control initially but I want to implement two way binding so that I can use a textbox to filter out unwanted TreeView items.
My problem is that the treeview isn't updated if
I'm trying to use something like this:
private void SearchTree_TextChanged(object sender, TextChangedEventArgs e)
{
if(SearchTree.Text.Length>0)
Command.dvm.DataViewSettings["Categories"].RowFilter = "CategoryName LIKE '%"+SearchTree.Text+"%'";
}
Can anyone please help me find out what I'm doing wrong here?!
Xaml:
...
<UserControl.Resources>
<ObjectDataProvider
x:Key="dataVMProvider"
MethodName="CreateDataVM"
ObjectType="{x:Type local:DataVMCreator}"
/>
<DataTemplate x:Key="InstancesTemplate">
<TextBlock Text="{Binding InstanceUID}"/>
</DataTemplate>
<HierarchicalDataTemplate
x:Key="SymbolsTemplate"
ItemsSource="{Binding Symbols2Instances}"
ItemTemplate="{StaticResource InstancesTemplate}"
>
<TextBlock Text="{Binding SymbolName}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="FamiliesTemplate"
ItemsSource="{Binding Families2Symbols}"
ItemTemplate="{StaticResource SymbolsTemplate}"
>
<TextBlock Text="{Binding FamilyName}"/>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
x:Key="CategoriesTemplate"
ItemsSource="{Binding Categories2Families}"
ItemTemplate="{StaticResource FamiliesTemplate}"
>
<TextBlock Text="{Binding CategoryName}"/>
</HierarchicalDataTemplate>
</UserControl.Resources>
...
<TreeView
x:Name="ElementsTree"
...
DataContext="{StaticResource dataVMProvider}"
ItemsSource="{Binding Categories}"
ItemTemplate="{StaticResource CategoriesTemplate}"
/>
The DataViewManager comes from:
public static class DataVMCreator
{
public static DataViewManager CreateDataVM()
{
return Command.dvm;
}
}

Try this binding for the DataContext of your TreeView:
DataContext="{Binding Source={StaticResource dataVMProvider}}"

Related

How to filter 3 level wpf treeview

Trying to filter level 2 and 3 nodes on a wpf treeview that is bound to a dataset.
I have tried using a value converter on the visibility property of the nodes but being a HierarchicalDataTemplate the converter isn't called.
<ObjectDataProvider x:Key="dataSetProvider" MethodName="GetDataSet" ObjectType="{x:Type local:DataSetCreator}"/>
<DataTemplate x:Key="SymbolTemplate">
<TextBlock Text="{Binding SymbolName}"/>
</DataTemplate>
<HierarchicalDataTemplate x:Key="FamilyTemplate" ItemsSource="{Binding Fam2Sym}" ItemTemplate="{StaticResource SymbolTemplate}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FamilyName}" />
<TextBlock><Run Text=" ("/><Run Text=")"/></TextBlock>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="Categorytemplate" ItemsSource="{Binding Cat2Fam}" ItemTemplate="{StaticResource FamilyTemplate}">
<TextBlock Text="{Binding LocalizedName}" />
</HierarchicalDataTemplate>
<TreeView x:Name="archTree" DataContext="{StaticResource dataSetProvider}" ItemsSource="{Binding RvtCat}"
ItemTemplate="{StaticResource Categorytemplate}"/>
I'm trying to filter a wpf treeview where if the level 2 OR 3 nodes match a string filter both levels are shown. I can't seem to find a way to do this. I've searched google but haven't found any similar questions. Suggestions?

WPF - I'm stumped on the TreeView control

Pun intended.
I want to create a simple TreeView using the HierarchicalDataTemplate class.
Here's my problem XAML:
<Window.Resources>
<ObjectDataProvider
x:Key="myDataProvider"
ObjectType="vm:ContractViewModel" />
</Window.Resources>
<Window.DataContext>
<Binding Source="{StaticResource myDataProvider}" Path="Contract" />
</Window.DataContext>
<StackPanel
Orientation="Vertical"
VerticalAlignment="Top">
<ListBox MinWidth="400" Margin="10"
ItemsSource="{Binding Commissions}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Id}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TreeView>
<HierarchicalDataTemplate DataType="{x:Type m:Contract}"
ItemsSource="{Binding Commissions}">
<TextBlock Text="{Binding Id}" />
</HierarchicalDataTemplate>
</TreeView>
</StackPanel>
I'm using the MVVM pattern. The StaticResource "myDataProvider" returns an instance of a Contract (custom) class. Here's my model:
internal class Contract
{
public string Name { get; set; }
public ObservableCollection<Commission> Commissions { get; set; }
}
internal class Commission
{
public string Id { get; set; }
}
FYI - my model is actually more complex; my classes contain more members than shown, they have constructors, and they implement INotifyPropertyChanged.
In my test, I load two Commission objects into a Contract object. The listbox works as expected: I can see the Id of each Commission object w/in Contract. The TreeView doesn't work: it returns a "System.Windows.HierarchicalDataTemplate" string in the TreeView control where I'd expect each Commission Id to be listed.
I've referred to other posts and MSDN to no avail. I'd be appreciative of your help!
From what I can tell is that you're not using the TreeView correctly in XAML. You need to put your HierarchicalDataTemplate at the TreeView.Resources level and assign a ItemsSource
As shown here you want to set the Template of the item.
Try to do something like this instead:
<TreeView ItemsSource="{Binding Contracts}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type m:Contract}"
ItemsSource="{Binding Commissions}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type m:Commission}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Id}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
I personally do it like this--using RadTreeView:
<telerik:RadTreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type vm:BaseType}"
ItemsSource="{Binding Children}">
<TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>
</telerik:RadTreeView.ItemTemplate>

How can I create a Hierarchical data template using tree view?

I'm using a class created from entity frameworks (Categories table in database)
And only contains three fields:
CategoryID
CategoryName
ParentCategory
And entity framework created me two navigation: Subcategories and Parent
And when I load the collection in a treeview, it show me everything, where it should only show the top levels.
I think I should create a hierarquical data template, but I really have no idea about creating it.
EDIT: It similars these case: Entity Framework - Binding WPF Tree view control
My control XAML contains:
<TreeView x:Name="objectiveTree" ItemsSource="{Binding Objectives}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Subcategories}">
<TextBlock Text="{Binding Path=CategoryName}"
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
You can try something like this:
Code-behind:
objectiveTree.ItemsSource = (List<YourMainEntity>) _entities;
XAML:
<TreeView x:Name="objectiveTree">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Subcategories}">
<TextBlock Text="{Binding ParentCategory}" />
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding CategoryName}"/>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<TreeView ItemsSource="{Binding YourItems}" ItemContainerStyle="
{StaticResource Level1}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}"
ItemContainerStyle="{StaticResource Level3}">
<TextBlock Text="{Binding Name}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

How to bind SelectedItem (from a ListBox) to a Variable?

I'm working on my first WP7 App and this problem causes me some headache.
I've a ListBox defined like this
<ListBox Grid.Row="1" ItemsSource="{Binding MyItemList}" SelectedItem="{Binding MySelectedItem}">
<ListBox.ItemTemplate>
<DataTemplate >
<StackPanel>
<TextBlock Text="{Binding Name}" FontSize="35" />
<TextBlock Text="{Binding Details}" FontSize="15"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Binding the ItemsSource works fine, but the MySelectedItem-Property doesn't get updated when selecting an item. Is this function not implemented (like in WPF) or am I just doing something? :-)
Just use -
SelectedItem="{Binding MySelectedItem, Mode=TwoWay}" and it should be fine.
You might have to set IsSynchronizedWithCurrentItem="True" for your ListBox.
This is my workaround.. I hope someone will post a more elegant solution.
XAML:
<ListBox Name="DecksListBox" ItemsSource="{Binding MyItemsList}"
SelectionChanged="UpdateSelectedItem"
Code-behind:
private void UpdateSelectedItem(object sender, SelectionChangedEventArgs e)
{
// Ignore if there is no selection
if (DecksListBox.SelectedIndex == -1)
return;
App.ViewModel.MySelectedItem = App.ViewModel.MyItemsList[DecksListBox.SelectedIndex];
}
Maybe this might help someone in the meantime.

Nested DataTemplates in ListBox

Is there any way to make a DataTemplate reference itself just from XAML? In this particular case trying to reference a DataTemplate from a ListBox contained within the same DataTemplate. Here is the solution I'd like, which doesn't work.
<DataTemplate x:Key="nestedItem" DataType="{x:Type local:NestedItem}">
<Expander Header="{Binding Path=Name}">
<ListBox ItemsSource="{Binding Path=Items}" x:Name="itemsList"
ItemTemplate="{StaticResource nestedItem}"/>
</Expander>
</DataTemplate>
And here's the solution I am currently using, which works.
<DataTemplate x:Key="nestedItem" DataType="{x:Type local:NestedItem}">
<Expander Header="{Binding Path=Name}" Expanded="OnItemExpanded">
<ListBox ItemsSource="{Binding Path=Items}" x:Name="itemsList"/>
</Expander>
</DataTemplate>
With code behind:
private void OnItemExpanded(object sender, RoutedEventArgs e)
{
if (e.OriginalSource != sender) return;
var source = (Expander) sender;
ListBox listBox = source.FindName("itemsList") as ListBox;
NestedItem item = source.DataContext as NestedItem;
listBox.ItemsSource = item.Items;
listBox.ItemTemplate = (DataTemplate) FindResource("nestedItem");
}
If you change your inner reference to be a DynamicResource instead of a StaticResource then it will work as you want. This is because there are some differences in how a StaticResource and DynamicResource actually look for the Resource item.
<DataTemplate x:Key="Local_NestedItem"
DataType="{x:Type local:NestedItem}">
<Expander Header="{Binding Path=Name}">
<ListBox ItemsSource="{Binding Path=Items}"
x:Name="itemsList"
ItemTemplate="{DynamicResource Local_NestedItem}" />
</Expander>
</DataTemplate>
Also, if you don't mind using some code, another good option is to use a DataTemplateSelector
Did you try using HierarchicalDataTemplate instead of DataTemplate for your first solution?
Did not test it for your case, but for treeviews it usually works that way.

Categories

Resources