TreeView - Refresh Data
The most common reason you would use an ObservableCollection is to make a component (like a grid, treeview, treelist, dropdown) change or react when you change that collection.
When you want to refresh the component data source like that, there are two important framework behaviors you need to be aware of - when ObservableCollection instances fire events, and how to refresh the data of a component when it is not an observable collection.
In this article:
Rebind Method
You can refresh the data by invoking the Rebind
method. Use the component reference to call the Rebind
method after you have made the data changes (for example adding, removing items). This is needed in case you are not using Observable data or resetting the collection reference. Calling Rebind
will force the component process the available data anew to reflect the updates.
@* Add/remove an item and rebind the TreeView to react to that change. *@
@using System.Collections.ObjectModel
<TelerikButton OnClick="@AddItem">Add item</TelerikButton>
<TelerikButton OnClick="@RemoveItem">Remove item</TelerikButton>
<TelerikTreeView @ref="@TreeViewRef"
Data="@TreeViewData">
<TreeViewBindings>
<TreeViewBinding IdField="Id"
ParentIdField="ParentIdValue"
TextField="Text"
HasChildrenField="HasChildren"
IconField="Icon">
</TreeViewBinding>
</TreeViewBindings>
</TelerikTreeView>
@code {
private TelerikTreeView TreeViewRef;
private List<TreeItem> TreeViewData { get; set; } = new List<TreeItem>();
private void AddItem()
{
TreeViewData.Add(
new TreeItem
{
Id = TreeViewData.Count + 1,
Text = "Testing",
ParentIdValue = 1,
HasChildren = false,
Icon = SvgIcon.Gears
});
TreeViewRef.Rebind();
}
private void RemoveItem()
{
if (TreeViewData.Count > 0)
{
TreeViewData.RemoveAt(TreeViewData.IndexOf(TreeViewData.Last()));
}
TreeViewRef.Rebind();
}
protected override void OnInitialized()
{
TreeViewData = new List<TreeItem>() {
new TreeItem()
{
Id = 1,
Text = "Project",
ParentIdValue = null,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 2,
Text = "Design",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Brush
},
new TreeItem()
{
Id = 3,
Text = "Implementation",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 4,
Text = "site.psd",
ParentIdValue = 2,
HasChildren = false,
Icon = SvgIcon.FilePsd
},
new TreeItem()
{
Id = 5,
Text = "index.js",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Js
},
new TreeItem()
{
Id = 6,
Text = "index.html",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Html5
},
new TreeItem()
{
Id = 7,
Text = "styles.css",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Css
}
};
}
public class TreeItem
{
public int Id { get; set; }
public string Text { get; set; }
public int? ParentIdValue { get; set; }
public bool HasChildren { get; set; }
public ISvgIcon Icon { get; set; }
}
}
Observable Data
Databound components can benefit from live updates - when the data source collection changes, the components should update to reflect that change. Most data-bound components in the Telerik UI for Blazor suite implement such functionality.
When the Data
of the component is a collection that implements the INotifyCollectionChanged
interface (such as ObservableCollection
), the Telerik components subscribe to its CollectionChanged
event to make live update. This means that adding items, removing items, or clearing the collection updates the components (its .Add()
, .Remove()
and .Clear()
methods).
The Observable collections fire the CollectionChanged
event only when their Add
, Remove
and Clear
methods are called. They do not fire it when you change the value of a field of one of their elements.
@* Add/remove an item to see how the TreeView reacts to that change. *@
@using System.Collections.ObjectModel
<TelerikButton OnClick="@AddItem">Add item</TelerikButton>
<TelerikButton OnClick="@RemoveItem">Remove item</TelerikButton>
<TelerikTreeView Data="@TreeViewData">
<TreeViewBindings>
<TreeViewBinding IdField="Id"
ParentIdField="ParentIdValue"
TextField="Text"
HasChildrenField="HasChildren"
IconField="Icon">
</TreeViewBinding>
</TreeViewBindings>
</TelerikTreeView>
@code {
private ObservableCollection<TreeItem> TreeViewData { get; set; } = new ObservableCollection<TreeItem>();
private void AddItem()
{
TreeViewData.Add(
new TreeItem
{
Id = TreeViewData.Count + 1,
Text = "Testing",
ParentIdValue = 1,
HasChildren = false,
Icon = SvgIcon.Gears
});
}
private void RemoveItem()
{
if (TreeViewData.Count > 0)
{
TreeViewData.RemoveAt(TreeViewData.IndexOf(TreeViewData.Last()));
}
}
protected override void OnInitialized()
{
TreeViewData = new ObservableCollection<TreeItem>() {
new TreeItem()
{
Id = 1,
Text = "Project",
ParentIdValue = null,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 2,
Text = "Design",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Brush
},
new TreeItem()
{
Id = 3,
Text = "Implementation",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 4,
Text = "site.psd",
ParentIdValue = 2,
HasChildren = false,
Icon = SvgIcon.FilePsd
},
new TreeItem()
{
Id = 5,
Text = "index.js",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Js
},
new TreeItem()
{
Id = 6,
Text = "index.html",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Html5
},
new TreeItem()
{
Id = 7,
Text = "styles.css",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Css
}
};
}
public class TreeItem
{
public int Id { get; set; }
public string Text { get; set; }
public int? ParentIdValue { get; set; }
public bool HasChildren { get; set; }
public ISvgIcon Icon { get; set; }
}
}
If you need to add/remove many items to/from the collection, consider creating a new collection and provide its reference to the data parameter. Thus, the component will re-render only once (when the data collection reference is changed) instead of re-rendering multiple times in response to the Add/Remove events.
New Collection Reference
In Blazor, the framework will fire the OnParametersSet
event of a child component (which is how child components can react to outside changes) only when it can detect a change in the object it receives through the corresponding parameter (like Data
for the data sources of Telerik components). This detection works as follows:
For strings and value types, this happens when their value changes.
-
For reference types (such as data collections like
List
, or anyIEnumerable
, and application-specific objects), this happens when the object reference changes.Thus, you would usually need to create a
new
reference for the view-model field (such asTreeViewData = new List<MyTreeViewItem>(theUpdatedDataCollection);
) when you want the component to update.
@* Add/remove item or change the collection to see how the TreeView reacts to that change. *@
<TelerikButton OnClick="@AddItem">Add item</TelerikButton>
<TelerikButton OnClick="@RemoveItem">Remove item</TelerikButton>
<TelerikButton OnClick="@ChangeItems">Change items data</TelerikButton>
<TelerikTreeView Data="@Items">
<TreeViewBindings>
<TreeViewBinding IdField="Id" ParentIdField="ParentIdValue" TextField="Text" HasChildrenField="HasChildren" IconField="Icon" />
</TreeViewBindings>
</TelerikTreeView>
@code {
void AddItem()
{
Items.Add(
new TreeItem
{
Id = Items.Count + 1,
Text = "Testing",
ParentIdValue = 1,
HasChildren = false,
Icon = SvgIcon.Gears
});
Items = new List<TreeItem>(Items);
}
void RemoveItem()
{
if (Items.Count > 0)
{
Items.RemoveAt(Items.IndexOf(Items.Last()));
Items = new List<TreeItem>(Items);
}
}
void ChangeItems()
{
Items = new List<TreeItem>()
{
new TreeItem()
{
Id = 1,
Text = "New root item",
ParentIdValue = null,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 2,
Text = "New child item 1",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Brush
},
new TreeItem()
{
Id = 3,
Text = "New child item 2",
ParentIdValue = 1,
HasChildren = false,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 4,
Text = "Child of item 1",
ParentIdValue = 2,
HasChildren = false,
Icon = SvgIcon.Gears
}
};
Items = new List<TreeItem>(Items);
}
public class TreeItem
{
public int Id { get; set; }
public string Text { get; set; }
public int? ParentIdValue { get; set; }
public bool HasChildren { get; set; }
public ISvgIcon Icon { get; set; }
}
public List<TreeItem> Items { get; set; } = new List<TreeItem>() {
new TreeItem()
{
Id = 1,
Text = "Project",
ParentIdValue = null,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 2,
Text = "Design",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Brush
},
new TreeItem()
{
Id = 3,
Text = "Implementation",
ParentIdValue = 1,
HasChildren = true,
Icon = SvgIcon.Folder
},
new TreeItem()
{
Id = 4,
Text = "site.psd",
ParentIdValue = 2,
HasChildren = false,
Icon = SvgIcon.FilePsd
},
new TreeItem()
{
Id = 5,
Text = "index.js",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Js
},
new TreeItem()
{
Id = 6,
Text = "index.html",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Html5
},
new TreeItem()
{
Id = 7,
Text = "styles.css",
ParentIdValue = 3,
HasChildren = false,
Icon = SvgIcon.Css
}
};
}