New to Telerik UI for Blazor? Download free 30-day trial

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

Use the Rebind method to refresh the data.

@* Add/remove task and rebind the Gantt to react to that change. *@

<TelerikButton OnClick="@AddRootTask">Add root task</TelerikButton>

<TelerikButton OnClick="@RemoveTask">Remove Task 1</TelerikButton>

<TelerikGantt @ref="@GanttRef"
              Data="@GanttData"
              @bind-View="@SelectedView"
              Width="1000px"
              TreeListWidth="500px"
              Height="600px"
              IdField="Id"
              ParentIdField="ParentId"
              OnUpdate="@UpdateItem"
              OnDelete="@DeleteItem">
    <GanttColumns>
        <GanttColumn Field="Title"
                     Expandable="true"
                     Width="160px"
                     Title="Task Title">
        </GanttColumn>
        <GanttColumn Field="PercentComplete"
                     Title="Status"
                     Width="60px">
        </GanttColumn>
        <GanttColumn Field="Start"
                     Width="100px"
                     DisplayFormat="{0:d}">
        </GanttColumn>
        <GanttColumn Field="End"
                     Width="100px"
                     DisplayFormat="{0:d}">
        </GanttColumn>
    </GanttColumns>
    <GanttViews>
        <GanttDayView></GanttDayView>
        <GanttWeekView></GanttWeekView>
        <GanttMonthView></GanttMonthView>
    </GanttViews>
</TelerikGantt>

@code {
    private TelerikGantt<FlatModel> GanttRef;

    private List<FlatModel> GanttData { get; set; }

    private GanttView SelectedView { get; set; } = GanttView.Week;

    private void AddRootTask()
    {
        var i = GanttData.Last().Id + 1;

        GanttData.Insert(0,new FlatModel()
        {
            Id = i,
            ParentId = null,
            Title = "new task",
            PercentComplete = 0,
            Start = new DateTime(2021, 7, 5),
            End = new DateTime(2021, 7, 15)
        });

        GanttRef.Rebind();
    }

    private void RemoveTask()
    {
        var taskToRemove = GanttData.FirstOrDefault(x => x.Title == "Task 1");

        GanttData.Remove(taskToRemove);

        GanttRef.Rebind();
    }

    class FlatModel
    {
        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string Title { get; set; }
        public double PercentComplete { get; set; }
        public DateTime Start { get; set; }
        public DateTime End { get; set; }
    }

    private int LastId { get; set; } = 1;

    protected override void OnInitialized()
    {
        GanttData = new List<FlatModel>();
        var random = new Random();

        for (int i = 1; i < 6; i++)
        {
            var newItem = new FlatModel()
            {
                Id = LastId,
                Title = "Task " + i.ToString(),
                Start = new DateTime(2021, 7, 5 + i),
                End = new DateTime(2021, 7, 11 + i),
                PercentComplete = Math.Round(random.NextDouble(), 2)
            };

            GanttData.Add(newItem);
            var parentId = LastId;
            LastId++;

            for (int j = 0; j < 5; j++)
            {
                GanttData.Add(new FlatModel()
                {
                    Id = LastId,
                    ParentId = parentId,
                    Title = "    Task " + i + " : " + j.ToString(),
                    Start = new DateTime(2021, 7, 5 + j),
                    End = new DateTime(2021, 7, 6 + i + j),
                    PercentComplete = Math.Round(random.NextDouble(), 2)
                });

                LastId++;
            }
        }

        base.OnInitialized();
    }

    private void UpdateItem(GanttUpdateEventArgs args)
    {
        var item = args.Item as FlatModel;

        var foundItem = GanttData.FirstOrDefault(i => i.Id.Equals(item.Id));

        if (foundItem != null)
        {
            foundItem.Title = item.Title;
            foundItem.Start = item.Start;
            foundItem.End = item.End;
            foundItem.PercentComplete = item.PercentComplete;
        }
    }

    private void DeleteItem(GanttDeleteEventArgs args)
    {
        var item = GanttData.FirstOrDefault(i => i.Id.Equals((args.Item as FlatModel).Id));

        RemoveChildRecursive(item);
    }

    private void RemoveChildRecursive(FlatModel item)
    {
        var children = GanttData.Where(i => item.Id.Equals(i.ParentId)).ToList();

        foreach (var child in children)
        {
            RemoveChildRecursive(child);
        }

        GanttData.Remove(item);
    }
}

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.

Bind the Gantt to an ObservableCollection, so it can react to collection changes.

@* Add/remove task to see how the Gantt reacts to that change.*@

@using System.Collections.ObjectModel

<TelerikButton OnClick="@AddRootTask">Add root task</TelerikButton>

<TelerikButton OnClick="@RemoveTask">Remove Task 1</TelerikButton>

<TelerikGantt Data="@GanttData"
              @bind-View="@SelectedView"
              Width="1000px"
              TreeListWidth="500px"
              Height="600px"
              IdField="Id"
              ParentIdField="ParentId"
              OnUpdate="@UpdateItem"
              OnDelete="@DeleteItem">
    <GanttColumns>
        <GanttColumn Field="Title"
                     Expandable="true"
                     Width="160px"
                     Title="Task Title">
        </GanttColumn>
        <GanttColumn Field="PercentComplete"
                     Title="Status"
                     Width="60px">
        </GanttColumn>
        <GanttColumn Field="Start"
                     Width="100px"
                     DisplayFormat="{0:d}">
        </GanttColumn>
        <GanttColumn Field="End"
                     Width="100px"
                     DisplayFormat="{0:d}">
        </GanttColumn>
    </GanttColumns>
    <GanttViews>
        <GanttDayView></GanttDayView>
        <GanttWeekView></GanttWeekView>
        <GanttMonthView></GanttMonthView>
    </GanttViews>
</TelerikGantt>

@code {
    private ObservableCollection<FlatModel> GanttData { get; set; }

    private GanttView SelectedView { get; set; } = GanttView.Week;

    private void AddRootTask()
    {
        GanttData.Insert(0,new FlatModel()
        {
            Id = ++LastId,
            ParentId = null,
            Title = "new task",
            PercentComplete = 0,
            Start = new DateTime(2021, 7, 5),
            End = new DateTime(2021, 7, 15)
        });
    }

    private void RemoveTask()
    {
        var taskToRemove = GanttData.FirstOrDefault(x => x.Title == "Task 1");

        GanttData.Remove(taskToRemove);
    }

    class FlatModel
    {
        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string Title { get; set; }
        public double PercentComplete { get; set; }
        public DateTime Start { get; set; }
        public DateTime End { get; set; }
    }

    private int LastId { get; set; } = 1;

    protected override void OnInitialized()
    {
        GanttData = new ObservableCollection<FlatModel>();
        var random = new Random();

        for (int i = 1; i < 6; i++)
        {
            var newItem = new FlatModel()
            {
                Id = LastId,
                Title = "Task " + i.ToString(),
                Start = new DateTime(2021, 7, 5 + i),
                End = new DateTime(2021, 7, 11 + i),
                PercentComplete = Math.Round(random.NextDouble(), 2)
            };

            GanttData.Add(newItem);
            var parentId = LastId;
            LastId++;

            for (int j = 0; j < 5; j++)
            {
                GanttData.Add(new FlatModel()
                {
                    Id = LastId,
                    ParentId = parentId,
                    Title = "    Task " + i + " : " + j.ToString(),
                    Start = new DateTime(2021, 7, 5 + j),
                    End = new DateTime(2021, 7, 6 + i + j),
                    PercentComplete = Math.Round(random.NextDouble(), 2)
                });

                LastId++;
            }
        }

        base.OnInitialized();
    }

    private void UpdateItem(GanttUpdateEventArgs args)
    {
        var item = args.Item as FlatModel;

        var foundItem = GanttData.FirstOrDefault(i => i.Id.Equals(item.Id));

        if (foundItem != null)
        {
            foundItem.Title = item.Title;
            foundItem.Start = item.Start;
            foundItem.End = item.End;
            foundItem.PercentComplete = item.PercentComplete;
        }
    }

    private void DeleteItem(GanttDeleteEventArgs args)
    {
        var item = GanttData.FirstOrDefault(i => i.Id.Equals((args.Item as FlatModel).Id));

        RemoveChildRecursive(item);
    }

    private void RemoveChildRecursive(FlatModel item)
    {
        var children = GanttData.Where(i => item.Id.Equals(i.ParentId)).ToList();

        foreach (var child in children)
        {
            RemoveChildRecursive(child);
        }

        GanttData.Remove(item);
    }
}

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 any IEnumerable, 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 as TreeViewData = new List<MyTreeViewItem>(theUpdatedDataCollection);) when you want the component to update.

Create new collection reference to refresh the Gantt data.

@* Add/remove task and create new collection reference to react to that change.*@

<TelerikButton OnClick="@AddRootTask">Add root task</TelerikButton>

<TelerikButton OnClick="@RemoveTask">Remove Task 1</TelerikButton>

<TelerikGantt Data="@GanttData"
              @bind-View="@SelectedView"
              Width="1000px"
              TreeListWidth="500px"
              Height="600px"
              IdField="Id"
              ParentIdField="ParentId"
              OnUpdate="@UpdateItem"
              OnDelete="@DeleteItem">
    <GanttColumns>
        <GanttColumn Field="Title"
                     Expandable="true"
                     Width="160px"
                     Title="Task Title">
        </GanttColumn>
        <GanttColumn Field="PercentComplete"
                     Title="Status"
                     Width="60px">
        </GanttColumn>
        <GanttColumn Field="Start"
                     Width="100px"
                     DisplayFormat="{0:d}">
        </GanttColumn>
        <GanttColumn Field="End"
                     Width="100px"
                     DisplayFormat="{0:d}">
        </GanttColumn>
    </GanttColumns>
    <GanttViews>
        <GanttDayView></GanttDayView>
        <GanttWeekView></GanttWeekView>
        <GanttMonthView></GanttMonthView>
    </GanttViews>
</TelerikGantt>

@code {
    private List<FlatModel> GanttData { get; set; }

    private GanttView SelectedView { get; set; } = GanttView.Week;


    void AddRootTask()
    {
        var i = GanttData.Last().Id + 1;

        GanttData.Insert(0, new FlatModel()
        {
            Id = i,
            ParentId = null,
            Title = "new task",
            PercentComplete = 0,
            Start = new DateTime(2021, 7, 5),
            End = new DateTime(2021, 7, 15)
        });

        GanttData = new List<FlatModel>(GanttData);
    }

    private void RemoveTask()
    {
        var taskToRemove = GanttData.FirstOrDefault(x => x.Title == "Task 1");

        GanttData.Remove(taskToRemove);

        GanttData = new List<FlatModel>(GanttData);
    }

    class FlatModel
    {
        public int Id { get; set; }
        public int? ParentId { get; set; }
        public string Title { get; set; }
        public double PercentComplete { get; set; }
        public DateTime Start { get; set; }
        public DateTime End { get; set; }
    }

    private int LastId { get; set; } = 1;

    protected override void OnInitialized()
    {
        GanttData = new List<FlatModel>();
        var random = new Random();

        for (int i = 1; i < 6; i++)
        {
            var newItem = new FlatModel()
            {
                Id = LastId,
                Title = "Task " + i.ToString(),
                Start = new DateTime(2021, 7, 5 + i),
                End = new DateTime(2021, 7, 11 + i),
                PercentComplete = Math.Round(random.NextDouble(), 2)
            };

            GanttData.Add(newItem);
            var parentId = LastId;
            LastId++;

            for (int j = 0; j < 5; j++)
            {
                GanttData.Add(new FlatModel()
                {
                    Id = LastId,
                    ParentId = parentId,
                    Title = "    Task " + i + " : " + j.ToString(),
                    Start = new DateTime(2021, 7, 5 + j),
                    End = new DateTime(2021, 7, 6 + i + j),
                    PercentComplete = Math.Round(random.NextDouble(), 2)
                });

                LastId++;
            }
        }

        base.OnInitialized();
    }

    private void UpdateItem(GanttUpdateEventArgs args)
    {
        var item = args.Item as FlatModel;

        var foundItem = GanttData.FirstOrDefault(i => i.Id.Equals(item.Id));

        if (foundItem != null)
        {
            foundItem.Title = item.Title;
            foundItem.Start = item.Start;
            foundItem.End = item.End;
            foundItem.PercentComplete = item.PercentComplete;
        }
    }

    private void DeleteItem(GanttDeleteEventArgs args)
    {
        var item = GanttData.FirstOrDefault(i => i.Id.Equals((args.Item as FlatModel).Id));

        RemoveChildRecursive(item);
    }

    private void RemoveChildRecursive(FlatModel item)
    {
        var children = GanttData.Where(i => item.Id.Equals(i.ParentId)).ToList();

        foreach (var child in children)
        {
            RemoveChildRecursive(child);
        }

        GanttData.Remove(item);
    }
}

See Also

In this article