This example adds two-way synchronization between the expanded state of each TreeListNode
and a Boolean
property in the ViewModel
.
IsExpanded
is not a dependency property - you cannot bind this property directly to a Boolean
property in your data model.
This example defines a helper class (BindableExpandingBehavior
) that attaches to a GridControl
and synchronizes the expanded state for each node with the IsExpanded
property in bound data objects.
The BindableExpandingBehavior
class updates each node in response to underlying property value changes. This helper class also tracks expand/collapse actions in the UI and updates the corresponding data property to reflect the change.
You can use this technique to:
-
Maintain node expanded state consistency across user sessions.
-
Manage node expanded/collapsed states in code at the data model level.
-
Respond to UI actions using the
ViewModel
.
You can reuse the BindableExpandingBehavior
class in any GridControl
that includes a hierarchical TreeListView
.
The BindableExpandingBehavior
class synchronizes the TreeListNode
's expanded state with a Boolean
property in your ViewModel
:
-
The example attaches
BindableExpandingBehavior
to theGridControl
and sets itsExpandingProperty
toIsExpanded
(the name of the property declared in each data item). -
Every time the
IsExpanded
property value changes in the data object, the corresponding node expands or collapses automatically. -
When a user expands or collapses a node in the UI,
BindableExpandingBehavior
updates theIsExpanded
property value for the bound object.
State synchronization is implemented as two event handlers corresponding to forward and reverse directions:
- Forward synchronization (when data changes)
public void PropertyChanged(object obj, PropertyChangedEventArgs args) {
if(args.PropertyName == this.ExpandingProperty) {
var node = FindNodeByValue(obj, treeView.Nodes);
node.IsExpanded = (bool)obj.GetType().GetProperty(args.PropertyName).GetValue(obj);
}
}
- Reverse synchronization (when a user expands/collapses a node)
void GridNodeChanged(object sender, TreeListNodeEventArgs e) {
var propInfo = e.Node.Content.GetType().GetProperty(this.ExpandingProperty);
propInfo.SetValue(e.Node.Content, e.Node.IsExpanded);
}
Both Parent
and Child
classes expose the IsExpanded
property required for synchronization:
public bool IsExpanded {
get { return this._IsExpanded; }
set { this.SetProperty(ref this._IsExpanded, value, "IsExpanded"); }
}
Each Parent
contains a list of Child
objects. In turn, each Child
can contain a list of Toy
objects, creating a three-level tree structure.
The DataHelper
class generates a large collection of Parent
objects populated with nested Child
objects.
The main window binds the GridControl
to an ObservableCollection<Parent>
. Each Parent
has a collection of Child
objects, and each Child
has a collection of Toy
items. The TreeListView
displays this hierarchy across three levels.
To synchronize node expanded states with the ViewModel
, the grid includes the BindableExpandingBehavior
class as follows:
<dxg:GridControl ItemsSource="{Binding Parents}" AutoGenerateColumns="None">
<dxg:GridControl.View>
<dxg:TreeListView Name="view"
KeyFieldName="Name"
ParentFieldName=""
AutoWidth="True"
ShowIndicator="False"
ChildNodesPath="Children">
<dxmvvm:Interaction.Behaviors>
<local:BindableExpandingBehavior ExpandingProperty="IsExpanded" />
</dxmvvm:Interaction.Behaviors>
</dxg:TreeListView>
</dxg:GridControl.View>
</dxg:GridControl>
- MainWindow.xaml (VB: MainWindow.xaml)
- MainWindow.xaml.cs (VB: MainWindow.xaml.vb)
- BindableExpandingBehavior.cs (VB: BindableExpandingBehavior.vb)
- DataHelper.cs (VB: DataHelper.vb)
- Parent.cs (VB: Parent.vb)
- WPF Data Grid - Specify Custom Content for Headers Displayed in the Column Chooser
- WPF Data Grid - Bind to Dynamic Data
- Implement CRUD Operations in the WPF Data Grid
- WPF Grid - Resize Rows Using a Splitter
(you will be redirected to DevExpress.com to submit your response)