This is a migrated thread and some comments may be shown as answers.

Handlng Children CollectionChanged

4 Answers 74 Views
GanttView
This is a migrated thread and some comments may be shown as answers.
Kenny
Top achievements
Rank 1
Kenny asked on 04 Jun 2014, 10:15 AM
Hi Telerik.

I use my own MyGantTaskCollection as a custom collection class for storing MyGanttTask (also custom, based on GanttTask).
MyGanttTask.Children is also a MyGanttTakCollection.

I noticed that the GanttView always uses the base.Children collection for displaying children. That is why I set up a sync between both collections. Basically: this.Children.CollectionChanged += ....   // sync added and/or removed with base.Children.
This solves the issue for my children to show up in the GanttChart.

The problem I'm facing now is that when the user drags/drops in the gantt chart from/to a child collection, there is no way for me to monitor this changement and sync the changements made in base.children to this.children as base.children is not observable..

Could you provide a solution for this? Ideally the solution would solve the first issue; the fact that GanttView does not accept a custom childcollection..

4 Answers, 1 is accepted

Sort by
0
Polya
Telerik team
answered on 05 Jun 2014, 12:22 PM
Hi Kenny,

What I understand is that the GanttTask Children collection is not suitable for your scenario and so a new Children collection of type MyGanttTaskCollection is created.
Unfortunately, for the reason that GanttTask Children is of type IList<IGanttTask> there is no event available for items change notification. We would have to insert/remove items in both collections when adding or removing them.
What I might suggest is implementing IGanttTask instead of inheriting GanttTask in the MyGanttTask class. This way we can include only the necessary fields needed and create Child collection of type MyGanttTask instead of IList<IGanttTask>. Then use these MyGanttTaskCollection<MyGanttTask> to populate the TasksSource of the RadGanttView.

Regards,
Polya
Telerik
 
Check out Telerik Analytics, the service which allows developers to discover app usage patterns, analyze user data, log exceptions, solve problems and profile application performance at run time. Watch the videos and start improving your app based on facts, not hunches.
 
0
Jayesh
Top achievements
Rank 1
Veteran
answered on 23 Sep 2020, 01:27 PM
Can you please provide an example?
0
Vladimir Stoyanov
Telerik team
answered on 28 Sep 2020, 09:59 AM

Hello Jayesh,

I am adding the source code of the GanttTask class for your reference:

[Serializable]
    public class GanttTask : PropertyChangedBase, IGanttTask, IMilestone, ISummary, IEditableHierarchical, IDependant
    {
        private ObservableCollection<IResource> resources;

        private DateTime start;
        private DateTime end;
        private string title = string.Empty;
        private string description = string.Empty;
        private double progress;
        private DateTime? deadLine;
        private bool isExpired;
        private bool isExpiredUpdate = true;

        private bool isMilestone;
        private string uniqueId;

        private ObservableCollection<IGanttTask> children;
        private ObservableCollection<IDependency> dependencies;

        /// <summary>
        /// Initializes a new instance of the <see cref="GanttTask"/> class.
        /// </summary>
        public GanttTask()
        {
            this.resources = new ObservableCollection<IResource> { };
            this.children = new ObservableCollection<IGanttTask> { };
            this.dependencies = new ObservableCollection<IDependency> { };

            this.dependencies.CollectionChanged += (s, e) => this.OnPropertyChanged(() => this.Dependencies);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GanttTask"/> class.
        /// </summary>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        public GanttTask(DateTime start, DateTime end)
            : this()
        {
            this.start = start;
            this.end = end;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="GanttTask"/> class.
        /// </summary>
        /// <param name="start">The start.</param>
        /// <param name="end">The end.</param>
        /// <param name="title">The title.</param>
        public GanttTask(DateTime start, DateTime end, string title)
            : this(start, end)
        {
            this.title = title;
        }

        /// <summary>
        /// Gets or sets the start.
        /// </summary>
        /// <value>
        /// The start.
        /// </value>
        public DateTime Start
        {
            get
            {
                return this.start;
            }
            set
            {
                if (this.start != value)
                {
                    this.start = value;
                    this.OnPropertyChanged(() => this.Start);
                    this.OnPropertyChanged(() => this.Duration);
                    this.OnPropertyChanged(() => this.IsMilestone);
                    this.OnPropertyChanged(() => this.IsExpired);
                }
            }
        }

        /// <summary>
        /// Gets or sets the end.
        /// </summary>
        /// <value>
        /// The end.
        /// </value>
        public DateTime End
        {
            get
            {
                return this.end;
            }
            set
            {
                if (this.end != value)
                {
                    this.end = value;
                    this.OnPropertyChanged(() => this.End);
                    this.OnPropertyChanged(() => this.Duration);
                    this.OnPropertyChanged(() => this.IsMilestone);
                    this.OnPropertyChanged(() => this.IsExpired);
                }
            }
        }

        /// <summary>
        /// Gets whether the GanttTask is expired, i.e. its Start or End is after the Deadline date.
        /// </summary>
        public bool IsExpired
        {
            get
            {
                if (isExpiredUpdate)
                {
                    isExpiredUpdate = false;
                    this.isExpired = this.CheckIsExpired();
                }
                return this.isExpired;
            }
        }

        /// <summary>
        /// Gets the children (subtasks).
        /// </summary>
        public IList<IGanttTask> Children
        {
            get
            {
                return this.children;
            }
        }

        /// <summary>
        /// Collection with relations to other tasks.
        /// </summary>
        public IList<IDependency> Dependencies
        {
            get
            {
                return this.dependencies;
            }
        }

        /// <summary>
        /// Collection with all resources associated with this task.
        /// </summary>
        public IList<IResource> Resources
        {
            get
            {
                return this.resources;
            }
        }

        /// <summary>
        /// Gets or set the duration of the task.
        /// </summary>
        public TimeSpan Duration
        {
            get
            {
                return this.End.Subtract(this.Start);
            }
            set
            {
                if (this.End.Subtract(this.Start) != value)
                {
                    this.End = this.Start.Add(value);
                }
            }
        }

        /// <summary>
        /// Gets or set the title of the task.
        /// </summary>
        public string Title
        {
            get
            {
                return this.title;
            }
            set
            {
                if (this.title != value)
                {
                    this.title = value;
                    this.OnPropertyChanged(() => this.Title);
                }
            }
        }

        /// <summary>
        /// Gets or set the description of the task.
        /// </summary>
        public string Description
        {
            get
            {
                return this.description;
            }
            set
            {
                if (this.description != value)
                {
                    this.description = value;
                    this.OnPropertyChanged(() => this.Description);
                }
            }
        }

        /// <summary>
        /// Gets or set the progress in percent of completion of the task.
        /// </summary>
        public double Progress
        {
            get
            {
                return this.progress;
            }
            set
            {
                if (this.progress != value)
                {
                    this.progress = value;
                    this.OnPropertyChanged(() => this.Progress);
                }
            }
        }

        /// <summary>
        /// Gets or set the deadline date of the task. This property is also used for calculating the critical path.
        /// </summary>
        public DateTime? Deadline
        {
            get
            {
                return this.deadLine;
            }
            set
            {
                if (this.deadLine != value)
                {
                    this.deadLine = value;
                    this.OnPropertyChanged(() => this.Deadline);
                    this.OnPropertyChanged(() => this.IsExpired);
                }
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the instance is a milestone.
        /// </summary>
        public bool IsMilestone
        {
            get
            {
                return isMilestone || this.Duration == TimeSpan.Zero;
            }
            set
            {
                if (this.isMilestone != value)
                {
                    this.isMilestone = value;
                    this.OnPropertyChanged(() => this.IsMilestone);
                }
            }
        }

        /// <summary>
        /// Gets a value indicating whether the instance is a summary.
        /// </summary>
        public bool IsSummary
        {
            get { return this.children.Count > 0; }
        }

        /// <summary>
        /// Gets or sets the unique id.
        /// </summary>
        /// <value>
        /// The unique id.
        /// </value>
        public string UniqueId
        {
            get
            {
                return this.uniqueId;
            }
            set
            {
                if (this.uniqueId != value)
                {
                    this.uniqueId = value;
                    this.OnPropertyChanged(() => this.UniqueId);
                }
            }
        }

        /// <summary>
        /// Gets the children (subtasks).
        /// </summary>
        IEnumerable IHierarchical.Children
        {
            get { return this.children; }
        }

        /// <summary>
        /// Collection with relations to other tasks.
        /// </summary>
        IEnumerable IGanttTask.Dependencies
        {
            get { return this.dependencies; }
        }

        IEnumerable IDependant.Dependencies
        {
            get { return this.dependencies; }
        }

        /// <summary>
        /// Gets the resources assigned to the task.
        /// </summary>
        IList IResourceContainer.Resources
        {
            get { return this.resources; }
        }

        /// <summary>
        /// Returns a <see cref="System.String"/> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return this.title;
        }

        /// <summary>
        /// Adds a dependency to the task. Returns the created dependency.
        /// </summary>
        /// <param name="fromTask">A <see cref="Telerik.Windows.Controls.GanttView.IGanttTask"/> from which the dependency will be added. </param>
        /// <param name="type">The type of the dependency.</param>
        /// <returns>Returns an object the added dependency.</returns>
        public IDependency AddDependency(IGanttTask fromTask, DependencyType type)
        {
            if (fromTask != null)
            {
                var dependency = new Dependency { FromTask = fromTask, Type = type };
                this.dependencies.Add(dependency);
                return dependency;
            }
            return null;
        }

        /// <summary>
        /// Removes a dependency from a task.
        /// </summary>
        /// <param name="dependency">The dependency to be removed.</param>
        /// <returns>Returns true if item is successfully removed; otherwise, false. This method also returns false if item was not found into the collection of dependencies.</returns>
        public bool RemoveDependency(IDependency dependency)
        {
            bool isRemoveSuccessful = false;
            if (this.dependencies.Contains(dependency))
            {
                isRemoveSuccessful = this.dependencies.Remove(dependency);
            }
            return isRemoveSuccessful;
        }

        void IStateProvider.LoadState(object state)
        {
            var range = state as IDateRange;
            if (range != null)
            {
                this.Start = range.Start;
                this.End = range.End;
            }
        }

        object IStateProvider.SaveState()
        {
            return new DateRange(this.start, this.end);
        }

        void IEditableHierarchical.InsertChildAtIndex(object item, int index)
        {
            var ganttTask = item as IGanttTask;
            if (ganttTask != null && index <= this.Children.Count)
            {
                this.Children.Insert(index, ganttTask);
            }
        }

        void IEditableHierarchical.Remove(object item)
        {
            var ganttItem = item as IGanttTask;
            if (ganttItem != null)
            {
                this.Children.Remove(ganttItem);
            }
        }

        protected internal virtual bool CheckIsExpired()
        {
            return this.Deadline < this.End;
        }

        protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs args)
        {
            if (args.PropertyName == "IsExpired")
            {
                this.isExpiredUpdate = true;
            }

            base.OnPropertyChanged(args);
        }
    }

You can observe that the default implementation of the Children property is an IList<IGanttTask>. You can change this to suit your scenario and reuse the rest of the code.

I hope you find this helpful.

Regards,
Vladimir Stoyanov
Progress Telerik

Virtual Classroom, the free self-paced technical training that gets you up to speed with Telerik and Kendo UI products quickly just got a fresh new look + new and improved content including a brand new Blazor course! Check it out at https://learn.telerik.com/.

0
Jayesh
Top achievements
Rank 1
Veteran
answered on 11 Nov 2020, 06:10 AM
thank you for the reply
Tags
GanttView
Asked by
Kenny
Top achievements
Rank 1
Answers by
Polya
Telerik team
Jayesh
Top achievements
Rank 1
Veteran
Vladimir Stoyanov
Telerik team
Share this question
or