/// <summary>
        /// Copying the collection changes to other DetailsViewDataGrids/ SourceDataGrid
        /// </summary>
        public static void ProcessCollectionChanged(NotifyCollectionChangedEventArgs e, IList source, IList target, Type baseType)
        {
            if (target == null)
            {
                return;
            }
            switch (e.Action)
            {
            case NotifyCollectionChangedAction.Add:
            {
                foreach (var newItem in e.NewItems)
                {
                    var clonedNewItem = CloneHelper.CreateClonedInstance(newItem, baseType);
                    var index         = source.IndexOf(newItem);
                    // WPF-21377 (Issue 3) - while cloning columns, need to copy filter predicates also
                    if (newItem is GridColumn && (newItem as GridColumn).FilterPredicates != null && (newItem as GridColumn).FilterPredicates.Any())
                    {
                        CloneHelper.CloneCollection((newItem as GridColumn).FilterPredicates, (clonedNewItem as GridColumn).FilterPredicates, typeof(FilterPredicate));
                    }
                    target.Insert(index, clonedNewItem);
                }
            }
            break;

            case NotifyCollectionChangedAction.Remove:
            {
                foreach (var oldItem in e.OldItems)
                {
                    target.RemoveAt(e.OldStartingIndex);
                }
            }
            break;

            case NotifyCollectionChangedAction.Move:
            {
                var obj1 = target[e.OldStartingIndex];
                var obj2 = target[e.NewStartingIndex];
                var num  = (e.NewStartingIndex > e.OldStartingIndex) ? 1 : 0;
                target.Remove(obj1);
                target.Insert(target.IndexOf(obj2) + num, obj1);
            }
            break;

            case NotifyCollectionChangedAction.Reset:
            {
                target.Clear();
                CloneHelper.CloneCollection(source, target, baseType);
            }
            break;

            case NotifyCollectionChangedAction.Replace:
            {
                target[e.OldStartingIndex] = e.NewItems[0];
            }
            break;
            }
        }
        /// <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();
        }
        public void EnsureCollection <T, S>(T source, Func <SfDataGrid, T> target, Func <S, S, bool> predicate, IDetailsViewNotifier notifier) where T : IList <S>
        {
            if (this.SourceDataGrid == notifier)
            {
                return;
            }
            var targetList = target(this.SourceDataGrid);

            if (source.Count != targetList.Count)
            {
                targetList.Clear();
                CloneHelper.CloneCollection((IList)source, this.SourceDataGrid.Columns, typeof(S));
                return;
            }
            if (!source.Any(column => targetList.All(col => predicate(col, column))))
            {
                return;
            }
            targetList.Clear();
            CloneHelper.CloneCollection((IList)source, this.SourceDataGrid.Columns, typeof(S));
        }
        /// <summary>
        /// Copy Properties from SourceDataGrid to DetailsViewDataGrid
        /// </summary>
        /// <param name="sourceDataGrid">Source DataGrid</param>
        /// <param name="destinationDataGrid">DetailsViewDataGrid</param>
        /// <param name="needToClearProperties">whether need to clear DetailsViewDataGrid properties before assigning new properties from Source DataGrid</param>
        internal void CopyPropertiesFromSourceDataGrid(SfDataGrid sourceDataGrid, DetailsViewDataGrid destinationDataGrid, bool needToClearProperties = false)
        {
            if (needToClearProperties)
            {
                ClearDetailsViewDataGridProperties(destinationDataGrid);
            }
            // Copying the properties from sourceDataGrid to DetailsViewDataGrid
            CloneHelper.CloneProperties(sourceDataGrid, destinationDataGrid, typeof(SfGridBase));
            CloneHelper.CloneCollection(sourceDataGrid.Columns, destinationDataGrid.Columns, typeof(GridColumnBase));

            // Need to clone GroupColumnDescriptions first. Else, SortColumnDescriptions will be changed when GroupColumnDescriptions is changed
            CloneHelper.CloneCollection(sourceDataGrid.GroupColumnDescriptions, destinationDataGrid.GroupColumnDescriptions, typeof(GroupColumnDescription));
            CloneHelper.CloneCollection(sourceDataGrid.SortColumnDescriptions, destinationDataGrid.SortColumnDescriptions, typeof(SortColumnDescription));
            CloneHelper.CloneCollection(sourceDataGrid.GroupSummaryRows, destinationDataGrid.GroupSummaryRows, typeof(GridSummaryRow));
            CloneHelper.CloneCollection(sourceDataGrid.TableSummaryRows, destinationDataGrid.TableSummaryRows, typeof(GridSummaryRow));
            CloneHelper.CloneCollection(sourceDataGrid.UnBoundRows, destinationDataGrid.UnBoundRows, typeof(GridUnBoundRow));
            CloneHelper.CloneCollection(sourceDataGrid.CoveredCells, destinationDataGrid.CoveredCells, typeof(CoveredCellInfoCollection));
            // UWP-4752 Need to clone SortComparer from sourceDataGrid to DetailsViewDataGrid
            CloneHelper.CloneCollection(sourceDataGrid.SortComparers, destinationDataGrid.SortComparers, typeof(SortComparer));
            CloneHelper.CloneCollection(sourceDataGrid.StackedHeaderRows, destinationDataGrid.StackedHeaderRows, typeof(StackedHeaderRow));
            CloneHelper.CloneCollection(sourceDataGrid.DetailsViewDefinition, destinationDataGrid.DetailsViewDefinition, typeof(ViewDefinition));

#if WPF
            destinationDataGrid.SearchHelper.SearchText             = sourceDataGrid.SearchHelper.SearchText;
            destinationDataGrid.SearchHelper.AllowFiltering         = sourceDataGrid.SearchHelper.AllowFiltering;
            destinationDataGrid.SearchHelper.SearchType             = sourceDataGrid.SearchHelper.SearchType;
            destinationDataGrid.SearchHelper.CanHighlightSearchText = sourceDataGrid.SearchHelper.CanHighlightSearchText;
#endif

            // Copying the columns from sourceDataGrid to DetailsViewDataGrid
            foreach (var targetColumn in destinationDataGrid.Columns)
            {
                var sourceColumn = sourceDataGrid.Columns.FirstOrDefault(x => x.MappingName == targetColumn.MappingName);
                if (sourceColumn != null)
                {
                    CloneHelper.CloneCollection(sourceColumn.FilterPredicates, targetColumn.FilterPredicates, typeof(FilterPredicate));
                }
            }
            // Copying the StackedHeaderRows from sourceDataGrid to DetailsViewDataGrid
            foreach (var targetColumn in destinationDataGrid.StackedHeaderRows)
            {
                var sourceColumn = sourceDataGrid.StackedHeaderRows.ElementAt(destinationDataGrid.StackedHeaderRows.IndexOf(targetColumn));
                if (sourceColumn != null)
                {
                    CloneHelper.CloneCollection(sourceColumn.StackedColumns, targetColumn.StackedColumns, typeof(StackedColumn));
                }
            }

            //The following properties should be same for Parent grid and DetailsViewDataGrid.
            // Suspend sourceDataGrid notification since it will set properties for all DetailsViewDataGrids
            (sourceDataGrid as IDetailsViewNotifier).SuspendNotifyListener();
            sourceDataGrid.AllowSelectionOnPointerPressed = destinationDataGrid.AllowSelectionOnPointerPressed = _parentDataGrid.AllowSelectionOnPointerPressed;
            sourceDataGrid.SelectionMode                = destinationDataGrid.SelectionMode = _parentDataGrid.SelectionMode;
            sourceDataGrid.SelectionUnit                = destinationDataGrid.SelectionUnit = _parentDataGrid.SelectionUnit;
            sourceDataGrid.NavigationMode               = destinationDataGrid.NavigationMode = _parentDataGrid.NavigationMode;
            sourceDataGrid.DetailsViewPadding           = destinationDataGrid.DetailsViewPadding = _parentDataGrid.DetailsViewPadding;
            sourceDataGrid.ReuseRowsOnItemssourceChange = destinationDataGrid.ReuseRowsOnItemssourceChange = _parentDataGrid.ReuseRowsOnItemssourceChange;
#if WPF
            sourceDataGrid.UseDrawing = destinationDataGrid.UseDrawing = _parentDataGrid.UseDrawing;
#endif
            // Resume sourceDataGrid notification
            (sourceDataGrid as IDetailsViewNotifier).ResumeNotifyListener();
        }