Editing in WinUI TreeGrid

3 Jun 202216 minutes to read

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

<treeGrid:SfTreeGrid Name="treeGrid"
                        ChildPropertyName="ReportsTo"
                        ColumnWidthMode="Star"
                        AutoGenerateColumns="False"
                        AllowEditing="True"
                        ItemsSource="{Binding Employees}"
                        ParentPropertyName="ID"
                        SelfRelationRootValue="-1" >
    <treeGrid:SfTreeGrid.Columns>
        <treeGrid:TreeGridTextColumn HeaderText="First Name" MappingName="FirstName"/>
        <treeGrid:TreeGridTextColumn HeaderText="Last Name" MappingName="LastName" />
        <treeGrid:TreeGridNumericColumn HeaderText="Employee ID" MappingName="ID" />
        <treeGrid:TreeGridTextColumn HeaderText="Title" MappingName="Title" />
        <treeGrid:TreeGridNumericColumn HeaderText="Salary" MappingName="Salary" DisplayNumberFormat="C2"/>
        <treeGrid:TreeGridNumericColumn HeaderText="Reports To" MappingName="ReportsTo" />
    </treeGrid:SfTreeGrid.Columns>
</treeGrid:SfTreeGrid>
this.treeGrid.AllowEditing = true;

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

<treeGrid: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 WinUI 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 F2 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.

<treeGrid:SfTreeGrid Name="treeGrid"
                        ChildPropertyName="ReportsTo"
                        ColumnWidthMode="Star"
                        AutoGenerateColumns="False"
                        AllowEditing="True"
                        EditTrigger="OnTap"
                        ItemsSource="{Binding Employees}"
                        ParentPropertyName="ID"
                        SelfRelationRootValue="-1" />
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.

<treeGrid:SfTreeGrid Name="treeGrid"
                        ChildPropertyName="ReportsTo"
                        ColumnWidthMode="Star"
                        AutoGenerateColumns="False"
                        AllowEditing="True"
                        EditTrigger="OnTap"
                        EditorSelectionBehavior="SelectAll"
                        ItemsSource="{Binding Employees}"
                        ParentPropertyName="ID"
                        SelfRelationRootValue="-1" />
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 Esc 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 Esc 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.

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.

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.

  • Record : Gets the record of the corresponding cell value.

  • 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.

<treeGrid:SfTreeGrid Name="treeGrid"
                               ChildPropertyName="ReportsTo"
                               ColumnWidthMode="Star"
                               IsReadOnly="True"
                               AutoGenerateColumns="True"
                               AllowEditing="True"
                               ItemsSource="{Binding Employees}"
                               ParentPropertyName="ID"
                               SelfRelationRootValue="-1" />
this.treeGrid.IsReadOnly = true;

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

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

NOTE

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