Editing in WPF TreeGrid (SfTreeGrid)

SfTreeGrid provides support for editing and it can be enabled or disabled by setting SfTreeGrid.AllowEditing property.

<syncfusion:SfTreeGrid x:Name="treeGrid"
						AllowEditing="True"
						AutoGenerateColumns="True"
						ItemsSource="{Binding EmployeeDetails}" />
this.treeGrid.AllowEditing = true;

You can enable or disable editing for particular column by setting TreeGridColumn.AllowEditing property.

<syncfusion:TreeGridTextColumn AllowEditing="True"
							HeaderText="First Name"
							MappingName="FirstName" />
this.treeGrid.Columns["FirstName"].AllowEditing = true;

NOTE

TreeGridColumn.AllowEditing takes higher priority than SfTreeGrid.AllowEditing

Editing in WPF treegrid

NOTE

It is mandatory to set the NavigationMode to Cell to enable CurrentCell navigation and editing.

Entering into edit mode

You can enter into edit mode by pressing <kbd>F2</kbd> key or clicking (touch also supported) the cell. You can allow users to edit the cell in single click (OnTap) or double click (OnDoubleTab) by setting SfTreeGrid.EditTrigger property.

<syncfusion:SfTreeGrid Name="treeGrid"
					EditTrigger="OnTap"
					AllowEditing="True"
					AutoExpandMode="RootNodesExpanded"                             
					ChildPropertyName="ReportsTo"
					ItemsSource="{Binding EmployeeInfo}"
					ParentPropertyName="ID"/>
this.treeGrid.EditTrigger = EditTrigger.OnTap;

Cursor placement

When the cell enters into edit mode, cursor is placed based on SfTreeGrid.EditorSelectionBehavior property.

SelectAll ֠selects the text of edit element loaded inside cell.

MoveLast ֠places the cursor at the last of edit element loaded inside cell.

<syncfusion:SfTreeGrid Name="treeGrid"
					AllowEditing="True"
					EditorSelectionBehavior="SelectAll"
					AutoExpandMode="RootNodesExpanded"
					ChildPropertyName="ReportsTo"
					EditTrigger="OnTap"
					ParentPropertyName="ID"
					ItemsSource="{Binding EmployeeInfo}" />
this.treeGrid.EditorSelectionBehavior = EditorSelectionBehavior.SelectAll;

Support for IEditableObject

SfTreeGrid supports to commit and roll back the changes in row level when underlying data object implements IEditableObject interface.

The editing changes in a row will be committed only when user move to next row or pressing enter key in EndEdit. Also when user press <kbd> Esc </kbd> key, then the changes made in a row will be reverted in CancelEdit.

IEditableObject has the following methods to capture editing,

BeginEdit - Gets called to begin edit on underlying data object when cell in a row get into edit mode.

CancelEdit - Gets called when user press the <kbd>Esc</kbd> key to discard the changes in a row since last BeginEdit call.

EndEdit - Gets called when user move to the next row or press Enter key to commit changes in underlying data object since last BeginEdit call.

In the below code snippet explains the simple implementation of IEditableObject.

public class EmployeeInfo : IEditableObject, INotifyPropertyChanged
{      
	int _id;
	/// <summary>
	/// Gets or sets the ID.
	/// </summary>
	/// <value>The ID.</value>

	public int ID
	{
		get
		{
			return _id;
		}
		set
		{
			_id = value;
			RaisePropertyChanged("ID");
		}
	}

	string _firstName;
	/// <summary>
	/// Gets or sets the first name.
	/// </summary>
	/// <value>The first name.</value>   

	public string FirstName
	{
		get { return _firstName; }
		set
		{
			_firstName = value;
			RaisePropertyChanged("FirstName");
		}
	}

	string _lastName;
	/// <summary>
	/// Gets or sets the last name.
	/// </summary>
	/// <value>The last name.</value>

	public string LastName
	{
		get { return _lastName; }
		set
		{
			_lastName = value;
			RaisePropertyChanged("LastName");
		}
	}

	private string _title;
	/// <summary>
	/// Gets or sets the title.
	/// </summary>
	/// <value>The title.</value>

	public string Title
	{
		get
		{
			return _title;
		}
		set
		{
			_title = value;
			RaisePropertyChanged("Title");
		}
	}

	double? _salary;
	/// <summary>
	/// Gets or sets the salary.
	/// </summary>
	/// <value>The salary.</value>

	public double? Salary
	{
		get
		{
			return _salary;
		}
		set
		{
			_salary = value;
			RaisePropertyChanged("Salary");
		}
	}

	int _reportsTo;
	/// <summary>
	/// Gets or sets the reports to.
	/// </summary>
	/// <value>The reports to.</value>

	public int ReportsTo
	{
		get
		{
			return _reportsTo;
		}
		set
		{
			_reportsTo = value;
			RaisePropertyChanged("ReportsTo");
		}
	}
	  
	protected Dictionary<string, object> BackUp()
	{
		var dictionary = new Dictionary<string, object>();
		var itemProperties = this.GetType().GetTypeInfo().DeclaredProperties;

		foreach (var pDescriptor in itemProperties)
		{

			if (pDescriptor.CanWrite)
				dictionary.Add(pDescriptor.Name, pDescriptor.GetValue(this));
		}
		return dictionary;
	}

	private Dictionary<string, object> storedValues;

	public void BeginEdit()
	{
		this.storedValues = this.BackUp();
	}

	public void CancelEdit()
	{

		if (this.storedValues == null)
			return;

		foreach (var item in this.storedValues)
		{
			var itemProperties = this.GetType().GetTypeInfo().DeclaredProperties;
			var pDesc = itemProperties.FirstOrDefault(p => p.Name == item.Key);

			if (pDesc != null)
				pDesc.SetValue(this, item.Value);
		}
	}

	public void EndEdit()
	{           

		if (this.storedValues != null)
		{
			this.storedValues.Clear();
			this.storedValues = null;
		}
	}

	public event PropertyChangedEventHandler PropertyChanged;

	public void RaisePropertyChanged(string propertyName)
	{

		if (PropertyChanged != null)
			PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
	}
}

Events

SfTreeGrid triggers the following events during editing.

CurrentCellBeginEdit Event

CurrentCellBeginEdit event occurs when the CurrentCell enter into edit mode. TreeCurrentCellBeginEditEventArgs has following members which provides information for CurrentCellBeginEdit event.

  • Cancel : When set to true, the event is canceled and the CurrentCell does not enter into the edit mode.

  • RowColumnIndex : Gets the current row column index of the TreeGrid.

  • Column : Gets the Tree Grid Column of the SfTreeGrid.

this.treeGrid.CurrentCellBeginEdit += TreeGrid_CurrentCellBeginEdit;

void TreeGrid_CurrentCellBeginEdit(object sender, TreeGridCurrentCellBeginEditEventArgs args)
{
}

CurrentCellEndEdit Event

CurrentCellEndEdit event occurs when the CurrentCell exits the edit mode.
CurrentCellEndEditEventArgs has following members which provides information for CurrentCellEndEdit event.

  • RowColumnIndex : Gets the value for the current row column index.
this.treeGrid.CurrentCellEndEdit += TreeGrid_CurrentCellEndEdit;

void TreeGrid_CurrentCellEndEdit(object sender, CurrentCellEndEditEventArgs args)
{
}

CurrentCellValueChanged Event

CurrentCellValueChanged event occurs whenever a value changes in TreeGridColumn that supports editing.
TreeGridCurrentCellValueChangedEventArgs has following members which provides information for CurrentCellValueChanged event.

  • Column : Gets the Grid Column of the SfTreeGrid.
  • RowColumnIndex : Gets the value of the current RowColumnIndex.
this.treeGrid.CurrentCellValueChanged += TreeGrid_CurrentCellValueChanged;

void TreeGrid_CurrentCellValueChanged(object sender, TreeGridCurrentCellValueChangedEventArgs args)
{
}

NOTE

For TreeGridComboBoxColumn, you have to use the ‘CurrentCellDropDownSelectionChanged’ event.

CurrentCellDropDownSelectionChanged Event

CurrentCellDropDownSelectionChanged event occurs whenever the SelectedItem of TreeGridComboBoxColumn column changed.
CurrentCellDropDownSelectionChangedEventArgs has following members which provides information for CurrentCellDropDownSelectionChanged event.

  • RowColumnIndex - Gets the RowColumnIndex of the corresponding item that were selected from the drop-down control.
  • SelectedIndex - Gets the index of the corresponding item that were selected from the drop-down control.
  • SelectedItem - Gets the data item that were selected from the drop-down control.
this.treeGrid.CurrentCellDropDownSelectionChanged += TreeGrid_CurrentCellDropDownSelectionChanged;

void TreeGrid_CurrentCellDropDownSelectionChanged(object sender, CurrentCellDropDownSelectionChangedEventArgs args)
{
}

Programmatically edit the cell

BeginEdit

SfTreeGrid allows you to edit the cell programmatically by calling the BeginEdit method. Initially theCurrentCell need to set before calling the BeginEdit method when the CurrentCell value is null.

this.treeGrid.Loaded += TreeGrid_Loaded;

void TreeGrid_Loaded(object sender, RoutedEventArgs e)
{            
	RowColumnIndex rowColumnIndex = new RowColumnIndex(2, 3);
	treeGrid.SelectionController.MoveCurrentCell(rowColumnIndex);
	treeGrid.SelectionController.CurrentCellManager.BeginEdit();
}

EndEdit

You can call the EndEdit method to programmatically end edit.

this.treeGrid.Loaded += TreeGrid_Loaded;

void TreeGrid_Loaded(object sender, RoutedEventArgs e)
{            
	RowColumnIndex rowColumnIndex = new RowColumnIndex(2, 3);
	treeGrid.SelectionController.MoveCurrentCell(rowColumnIndex);
	treeGrid.SelectionController.CurrentCellManager.EndEdit();
}

CancelEdit

You can use the CurrentCellBeginEdit event to cancel the editing operation for the corresponding cell.

this.treeGrid.CurrentCellBeginEdit += TreeGrid_CurrentCellBeginEdit;

void TreeGrid_CurrentCellBeginEdit(object sender, TreeGridCurrentCellBeginEditEventArgs args)
{
	var mappingName = treeGrid.Columns[args.RowColumnIndex.ColumnIndex].MappingName;
	var node = treeGrid.View.GetNodeAt(args.RowColumnIndex.RowIndex);

	if (args.RowColumnIndex == new RowColumnIndex(2, 2))
		args.Cancel = true;
}

ReadOnly

You can prevent users from modifying the contents of a treegrid cell by setting the SfTreeGrid.IsReadOnly  property, but the user can able to perform copy and selection operation.

<syncfusion:SfTreeGrid Name="treeGrid"
            AllowEditing="True"
            IsReadOnly="True"
            AutoGenerateColumns="True"
            ItemsSource="{Binding EmployeeDetails}"/>
this.treeGrid.IsReadOnly = true;

You can enable or disable editing for particular column by setting TreeGridColumn.IsReadOnly property.

<syncfusion:TreeGridTextColumn  HeaderText="Order ID" 
                                MappingName="OrderID"
                                IsReadOnly="True"/>
this.treeGrid.Columns["OrderID"].IsReadOnly = true;

NOTE

We should set the AllowEditing property to achieve the IsReadOnly behavior.
TreeGridColumn.IsReadOnly takes higher priority than SfTreeGrid.IsReadOnly.

Mouse and Keyboard operations for UIElement inside Template

You can directly load edit element using TreeGridTemplateColumn.CellTemplate property. In this case, you can provide focus and control to the UIElement inside CellTemplate in the below ways,

Providing focus to the control inside the Template

You can focus to the particular UIElement loaded inside template when cell gets activated by setting FocusedManager.FocusedElement attached property.

<syncfusion:SfTreeGrid Name="treeGrid"
						AutoGenerateColumns="False"
						ColumnSizer="Star" 
						AllowEditing="True"
						AutoExpandMode="RootNodesExpanded"                    
						ChildPropertyName="Children"                  
						ItemsSource="{Binding EmployeeDetails}">
	<syncfusion:SfTreeGrid.Columns>                        
		<syncfusion:TreeGridTemplateColumn HeaderText="First Name" MappingName="FirstName" >
			<syncfusion:TreeGridTemplateColumn.CellTemplate>
				<DataTemplate>
					<TextBlock Syncfusion:FocusManagerHelper.FocusedElement="True"
								FontStyle="Italic"
								FontWeight="SemiBold"
								Padding="2,0"
								Text="{Binding FirstName}" />
				</DataTemplate>
			</syncfusion:TreeGridTemplateColumn.CellTemplate>
		</syncfusion:TreeGridTemplateColumn>                
	</syncfusion:SfTreeGrid.Columns>
</syncfusion:SfTreeGrid>

Mouse and keyboard operation in WPF treegrid cell template

Providing keyboard control to UIElement inside CellTemplate

You can allow UIElement loaded inside CellTemplate to handle keyboard interaction by setting FocusManagerHelper.WantsKeyInput attached property to TreeGridColumn.

<syncfusion:SfTreeGrid Name="treeGrid"
							AutoGenerateColumns="False"
							AllowEditing="True"
							AutoExpandMode="RootNodesExpanded"                    
							ChildPropertyName="Children"                  
							ItemsSource="{Binding EmployeeDetails}">
	<syncfusion:SfTreeGrid.Columns>                        
		<syncfusion:TreeGridTemplateColumn HeaderText="First Name" MappingName="FirstName"
											syncfusion:FocusManagerHelper.WantsKeyInput= "True">
			<syncfusion:TreeGridTemplateColumn.CellTemplate>
				<DataTemplate>
					<Grid>
						<TextBox x:Name="text" Text="{Binding FirstName}"/>
					</Grid>
				</DataTemplate>
			</syncfusion:TreeGridTemplateColumn.CellTemplate>
		</syncfusion:TreeGridTemplateColumn>                
	</syncfusion:SfTreeGrid.Columns>
</syncfusion:SfTreeGrid>

Keyboard operations in WPF treegrid cell template

NOTE

Enter and Tab keys are always handled by SfTreeGrid only.

Providing mouse control to UIElement inside template

You can allow UIElement loaded inside template to handle mouse interaction in required cases by setting VisualContainer.WantsMouseInput attached property to TreeGridColumn.

<syncfusion:SfTreeGrid Name="treeGrid"
							AutoGenerateColumns="False"
							AllowEditing="True"
							AutoExpandMode="RootNodesExpanded"                    
							ChildPropertyName="Children"                  
							ItemsSource="{Binding EmployeeDetails}">
	<syncfusion:SfTreeGrid.Columns>                        
		<syncfusion:TreeGridTemplateColumn HeaderText="City" MappingName="City" >
			<syncfusion:TreeGridTemplateColumn.CellTemplate>
				<DataTemplate>
					<ComboBox ItemsSource="{Binding CityCollection, Source={StaticResource viewModel}}"                                                           
											syncfusion:VisualContainer.WantsMouseInput="True"/>
				</DataTemplate>
			</syncfusion:TreeGridTemplateColumn.CellTemplate>
		</syncfusion:TreeGridTemplateColumn>                
	</syncfusion:SfTreeGrid.Columns>
</syncfusion:SfTreeGrid>