Handlng Children CollectionChanged

5 posts, 0 answers
  1. Kenny
    Kenny avatar
    16 posts
    Member since:
    Feb 2013

    Posted 04 Jun 2014 Link to this post

    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..
  2. Polya
    Admin
    Polya avatar
    267 posts

    Posted 05 Jun 2014 Link to this post

    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.
     
  3. Jayesh
    Jayesh avatar
    5 posts
    Member since:
    Sep 2020

    Posted 23 Sep in reply to Polya Link to this post

    Can you please provide an example?
  4. Vladimir Stoyanov
    Admin
    Vladimir Stoyanov avatar
    707 posts

    Posted 28 Sep Link to this post

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

  5. Jayesh
    Jayesh avatar
    5 posts
    Member since:
    Sep 2020

    Posted 11 Nov in reply to Vladimir Stoyanov Link to this post

    thank you for the reply
Back to Top