/// <summary>
 /// When collection is chnaged
 /// If it is SourceDataGrid then we will update the collection to all the cloned child grids(DetailsViewDataGrids). If it is cloned child grid(DetailsViewDataGrid), then we will change the property to the SourceDataGrid, it will change the property to other cloned child grid(DetailsViewDataGrids) using ClonedDataGrid list.
 /// </summary>
 public void NotifyCollectionChanged(object source, NotifyCollectionChangedEventArgs e, Func <SfDataGrid, object> target, IDetailsViewNotifier notifier, Type baseType)
 {
     if (notifier.IsListenerSuspended)
     {
         return;
     }
     notifier.SuspendNotifyListener();
     if (this.SourceDataGrid != notifier)
     {
         var rootNotifier = SourceDataGrid as IDetailsViewNotifier;
         if (!rootNotifier.IsListenerSuspended)
         {
             var targetElement = target(SourceDataGrid);
             ProcessCollectionChanged(e, (IList)source, (IList)targetElement, baseType);
         }
     }
     else
     {
         foreach (var clonedDataGrid in ClonedDataGrid)
         {
             var clonedNotifier = clonedDataGrid as IDetailsViewNotifier;
             if (clonedNotifier != null && clonedNotifier.IsListenerSuspended)
             {
                 continue;
             }
             var clonedTargetElement = target(clonedDataGrid);
             ProcessCollectionChanged(e, (IList)source, (IList)clonedTargetElement, baseType);
         }
     }
     notifier.ResumeNotifyListener();
 }
        /// <summary>
        /// When property is chnaged
        /// If it is SourceDataGrid then we will change the property to all the cloned child grids(DetailsViewDataGrids). If it is cloned child grid(DetailsViewDataGrid), then we will change the property to the SourceDataGrid, it will change the property to other cloned child grid using ClonedDataGrid list.
        /// </summary>
        public void NotifyPropertyChanged(object source, string propertyName, DependencyPropertyChangedEventArgs e, Func <SfDataGrid, object> target, IDetailsViewNotifier notifier, Type ownerType)
        {
            if (notifier.IsListenerSuspended)
            {
                return;
            }
#if WinRT || UNIVERSAL
            if (!ownerType.GetTypeInfo().IsAssignableFrom(source.GetType().GetTypeInfo()))
            {
                return;
            }
#else
            if (!ownerType.IsInstanceOfType(source))
            {
                return;
            }
#endif
            var propertyDescriptor = CloneHelper.GetCloneableProperty(source.GetType(), ownerType, propertyName);
            if (propertyDescriptor == null)
            {
                return;
            }
            notifier.SuspendNotifyListener();
            // If the notifier is SourceDataGrid, we should not set the properties to SourceDataGrid
            if (this.SourceDataGrid != notifier)
            {
                var rootNotifier = SourceDataGrid as IDetailsViewNotifier;
                if (!rootNotifier.IsListenerSuspended)
                {
                    var targetElement = target(SourceDataGrid);
#if WPF
                    propertyDescriptor.SetValue(targetElement, e.NewValue);
#else
                    propertyDescriptor.SetValue(targetElement, e.NewValue, null);
#endif
                }
            }
            else
            {
                // Based on the SourceDataGrid property, other DetailsViewDataGrids property is set
                foreach (var clonedDataGrid in ClonedDataGrid)
                {
                    var clonedNotifier = clonedDataGrid as IDetailsViewNotifier;
                    if (clonedNotifier != null && clonedNotifier.IsListenerSuspended)
                    {
                        continue;
                    }
                    var clonedTargetElement = target(clonedDataGrid);
#if WPF
                    propertyDescriptor.SetValue(clonedTargetElement, e.NewValue);
#else
                    propertyDescriptor.SetValue(clonedTargetElement, e.NewValue, null);
#endif
                }
            }
            notifier.ResumeNotifyListener();
        }
        /// <summary>
        /// When SortColumnDescriptions, GroupColumnDescriptions are changed, need to update this for other DetailsViewDataGrids
        /// </summary>
        /// <param name="notifier">DataGrid(SourceDataGrid/ DetailsViewDataGrid) which notfifies the changes</param>
        /// <param name="baseType">collection type</param>
        public void NotifyCollectionPropertyChanged(IDetailsViewNotifier notifier, Type baseType)
        {
            if (notifier.IsListenerSuspended)
            {
                return;
            }
            notifier.SuspendNotifyListener();

            // Based on the SourceDataGrid property, other DetailsViewDataGrids collection is updated
            foreach (var clonedDataGrid in ClonedDataGrid)
            {
                var clonedNotifier = clonedDataGrid as IDetailsViewNotifier;
                if (clonedNotifier != null && clonedNotifier.IsListenerSuspended)
                {
                    continue;
                }
                var sourceDataGrid = notifier as SfDataGrid;
                if (baseType.Equals(typeof(GroupColumnDescriptions)))
                {
                    CloneHelper.EnsureCollection <GroupColumnDescriptions, GroupColumnDescription>(sourceDataGrid.GroupColumnDescriptions, clonedDataGrid.GroupColumnDescriptions, (target, source) => target.ColumnName == source.ColumnName);
                }
                if (baseType.Equals(typeof(SortColumnDescriptions)))
                {
                    CloneHelper.EnsureCollection <SortColumnDescriptions, SortColumnDescription>(sourceDataGrid.SortColumnDescriptions, clonedDataGrid.SortColumnDescriptions, (target, source) => target.ColumnName == source.ColumnName && target.SortDirection == source.SortDirection);
                }
                if (baseType.Equals(typeof(StackedHeaderRows)))
                {
                    CloneHelper.EnsureCollection <StackedHeaderRows, StackedHeaderRow>(sourceDataGrid.StackedHeaderRows, clonedDataGrid.StackedHeaderRows, (target, source) => target.Name == source.Name);
                    // Copying the StackedHeaderRows from sourceDataGrid to DetailsViewDataGrid
                    foreach (var targetColumn in clonedDataGrid.StackedHeaderRows)
                    {
                        var sourceColumn = sourceDataGrid.StackedHeaderRows.ElementAt(clonedDataGrid.StackedHeaderRows.IndexOf(targetColumn));
                        if (sourceColumn != null)
                        {
                            CloneHelper.CloneCollection(sourceColumn.StackedColumns, targetColumn.StackedColumns, typeof(StackedColumn));
                        }
                    }
                }
                if (baseType.Equals(typeof(UnBoundRows)))
                {
                    CloneHelper.EnsureCollection <UnBoundRows, GridUnBoundRow>(sourceDataGrid.UnBoundRows, clonedDataGrid.UnBoundRows, (target, source) => target.Position == source.Position && target.ShowBelowSummary == source.ShowBelowSummary);
                }
            }
            notifier.ResumeNotifyListener();
        }