From c80d2f58e605485c3c5a9b3731cdcc10a101f4f5 Mon Sep 17 00:00:00 2001 From: Pat Limosnero Date: Wed, 7 Aug 2024 10:58:29 -0400 Subject: [PATCH] upgrade Xceed.Wpf.DataGrid fix a couple of issues and some commented. we don't really care much about this project since we dont use it in propresenter --- .../DataGridCollectionViewGroup.cs | 1716 ++--- .../EntityDetailDescription.cs | 128 +- .../QueryEntityDetailsEventArgs.cs | 58 +- .../Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs | 96 +- .../Converters/ImageConverter.cs | 134 +- .../Src/Xceed.Wpf.DataGrid/DataGridContext.cs | 6776 ++++++++--------- .../GenericContentTemplateSelector.cs | 568 +- .../Xceed.Wpf.DataGrid/GroupHeaderControl.cs | 637 +- .../Xceed.Wpf.DataGrid/ItemsSourceHelper.cs | 4319 +++++------ .../Properties/AssemblyInfo.cs | 78 - .../Wpf/DragDrop/DragSourceManagerBase.cs | 1142 +-- .../Xceed.Wpf.DataGrid.csproj | 1182 +-- .../Xceed.Wpf.Toolkit.sln | 2 +- 13 files changed, 7924 insertions(+), 8912 deletions(-) delete mode 100644 ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Properties/AssemblyInfo.cs diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs index aeb74be4..8ea26cba 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/DataGridCollectionViewGroup.cs @@ -28,1028 +28,1028 @@ using System.Windows.Data; namespace Xceed.Wpf.DataGrid { - internal class DataGridCollectionViewGroup : CollectionViewGroup, ICustomTypeDescriptor - { - protected DataGridCollectionViewGroup( int capacity ) - : this( null, null, 0, capacity, 4 ) + internal class DataGridCollectionViewGroup : CollectionViewGroup, ICustomTypeDescriptor { - } - - protected DataGridCollectionViewGroup( DataGridCollectionViewGroup template, DataGridCollectionViewGroup parent ) - : this( template.Name, parent, template.m_unsortedIndex, template.m_sortedRawItems.Count, template.m_subGroups.Count ) - { - m_nextSubGroupUnsortedIndex = template.m_nextSubGroupUnsortedIndex; - m_subGroupBy = template.m_subGroupBy; - m_groupByName = template.GroupByName; - } - - private DataGridCollectionViewGroup( object name, DataGridCollectionViewGroup parent, int unsortedIndex ) - : this( name, parent, unsortedIndex, 4, 4 ) - { - } - - private DataGridCollectionViewGroup( object name, DataGridCollectionViewGroup parent, int unsortedIndex, int rawCapacity, int groupCapacity ) - : base( name ) - { - m_parent = parent; - m_unsortedIndex = unsortedIndex; - m_protectedItems = ObservableCollectionHelper.GetItems( base.ProtectedItems ); - m_protectedItemsCollectionChanged = ObservableCollectionHelper.GetCollectionChanged( base.ProtectedItems ); - m_optimizedItems = new OptimizedReadOnlyObservableCollection( this ); - m_subGroups = new Dictionary( groupCapacity ); - m_sortedRawItems = new List( rawCapacity ); - } - - #region IsBottomLevel Property - - public override bool IsBottomLevel - { - get - { - // returns true if .Items contain DataItem - return ( m_subGroupBy == null ); - } - } - - #endregion - - #region Items Property - - internal new ReadOnlyObservableCollection Items - { - get - { - return m_optimizedItems; - } - } - - #endregion - - #region ProtectedItems Property - - internal new ObservableCollection ProtectedItems - { - get - { - return base.ProtectedItems; - } - } - - #endregion - - #region UnsortedIndex Property - - internal int UnsortedIndex - { - get - { - return m_unsortedIndex; - } - } - - #endregion + protected DataGridCollectionViewGroup(int capacity) + : this(null, null, 0, capacity, 4) + { + } - #region GroupByName Property + protected DataGridCollectionViewGroup(DataGridCollectionViewGroup template, DataGridCollectionViewGroup parent) + : this(template.Name, parent, template.m_unsortedIndex, template.m_sortedRawItems.Count, template.m_subGroups.Count) + { + m_nextSubGroupUnsortedIndex = template.m_nextSubGroupUnsortedIndex; + m_subGroupBy = template.m_subGroupBy; + m_groupByName = template.GroupByName; + } - internal string GroupByName - { - get - { - return m_groupByName; - } - set - { - m_groupByName = value; - } - } + private DataGridCollectionViewGroup(object name, DataGridCollectionViewGroup parent, int unsortedIndex) + : this(name, parent, unsortedIndex, 4, 4) + { + } - private string m_groupByName; + private DataGridCollectionViewGroup(object name, DataGridCollectionViewGroup parent, int unsortedIndex, int rawCapacity, int groupCapacity) + : base(name) + { + m_parent = parent; + m_unsortedIndex = unsortedIndex; + m_protectedItems = ObservableCollectionHelper.GetItems(base.ProtectedItems); + m_protectedItemsCollectionChanged = ObservableCollectionHelper.GetCollectionChanged(base.ProtectedItems); + m_optimizedItems = new OptimizedReadOnlyObservableCollection(this); + m_subGroups = new Dictionary(groupCapacity); + m_sortedRawItems = new List(rawCapacity); + } - #endregion + #region IsBottomLevel Property - #region SubGroupBy Property + public override bool IsBottomLevel + { + get + { + // returns true if .Items contain DataItem + return (m_subGroupBy == null); + } + } - internal GroupDescription SubGroupBy - { - get - { - return m_subGroupBy; - } - } + #endregion - #endregion + #region Items Property - #region Parent Property + internal new ReadOnlyObservableCollection Items + { + get + { + return m_optimizedItems; + } + } - internal DataGridCollectionViewGroup Parent - { - get - { - return m_parent; - } - } + #endregion - #endregion + #region ProtectedItems Property - #region GlobalRawItemCount Property + internal new ObservableCollection ProtectedItems + { + get + { + return base.ProtectedItems; + } + } - internal int GlobalRawItemCount - { - get - { - return m_globalRawItemCount; - } - } + #endregion - #endregion + #region UnsortedIndex Property - #region RawItems Property + internal int UnsortedIndex + { + get + { + return m_unsortedIndex; + } + } - internal List RawItems - { - get - { - return m_sortedRawItems; - } - } + #endregion - #endregion + #region GroupByName Property - protected virtual DataGridCollectionView GetCollectionView() - { - if( m_parent != null ) - return m_parent.GetCollectionView(); + internal string GroupByName + { + get + { + return m_groupByName; + } + set + { + m_groupByName = value; + } + } - return null; - } + private string m_groupByName; - internal bool Contains( object item ) - { - var group = item as DataGridCollectionViewGroup; - if( group != null ) - { - //Must make sure the group the group is ref equals, because there can be groups with a null name at more than one level. - DataGridCollectionViewGroup foundGroup; - if( m_subGroups.TryGetValue( DataGridCollectionViewGroup.GetHashKeyFromName( group.Name ), out foundGroup ) ) - return ( foundGroup == group ); - - return false; - } - - DataGridCollectionView collectionView = this.GetCollectionView(); - if( collectionView != null ) - { - RawItem rawItem = collectionView.GetFirstRawItemFromDataItem( item ); - if( rawItem != null ) - return ( rawItem.ParentGroup == this ); - } - - return false; - } + #endregion - internal int IndexOf( object item ) - { - if( item is DataGridCollectionViewGroup ) - return this.ProtectedItems.IndexOf( item ); + #region SubGroupBy Property - DataGridCollectionView collectionView = this.GetCollectionView(); + internal GroupDescription SubGroupBy + { + get + { + return m_subGroupBy; + } + } - if( collectionView != null ) - { - RawItem rawItem = collectionView.GetFirstRawItemFromDataItem( item ); + #endregion - if( ( rawItem != null ) && ( rawItem.ParentGroup == this ) ) - return rawItem.SortedIndex; - } + #region Parent Property - return -1; - } + internal DataGridCollectionViewGroup Parent + { + get + { + return m_parent; + } + } - internal int GetFirstRawItemGlobalSortedIndex() - { - var index = 0; - var group = this; - var parent = this.Parent; - var currentGroup = default( DataGridCollectionViewGroup ); + #endregion - while( parent != null ) - { - var items = parent.ProtectedItems; - var count = items.Count; + #region GlobalRawItemCount Property - for( int i = 0; i < count; i++ ) + internal int GlobalRawItemCount { - var value = items[ i ]; - if( value == group ) - break; - - currentGroup = value as DataGridCollectionViewGroup; - index += currentGroup.GlobalRawItemCount; + get + { + return m_globalRawItemCount; + } } - group = parent; - parent = parent.Parent; - } + #endregion - return index; - } - - internal void SetSubGroupBy( GroupDescription groupBy ) - { - bool oldIsBottomLevel = this.IsBottomLevel; - m_subGroupBy = groupBy; + #region RawItems Property - if( oldIsBottomLevel != this.IsBottomLevel ) - { - this.OnPropertyChanged( new PropertyChangedEventArgs( "IsBottomLevel" ) ); - } - } - - internal DataGridCollectionViewGroup GetGroup( - RawItem rawItem, - int level, - CultureInfo culture, - ObservableCollection groupByList, - List groupSortComparers ) - { - // If sortComparers is null, we are in massive group creation, no order check. + internal List RawItems + { + get + { + return m_sortedRawItems; + } + } - if( this.IsBottomLevel ) - throw new InvalidOperationException( "An attempt was made to get a group for which a GroupDescription has not been provided." ); + #endregion - object groupName = m_subGroupBy.GroupNameFromItem( rawItem.DataItem, level, culture ); - DataGridCollectionViewGroup group; + protected virtual DataGridCollectionView GetCollectionView() + { + if (m_parent != null) + return m_parent.GetCollectionView(); - if( ( m_subGroupBy is DataGridGroupDescription ) || ( m_subGroupBy is PropertyGroupDescription ) ) - { - m_subGroups.TryGetValue( DataGridCollectionViewGroup.GetHashKeyFromName( groupName ), out group ); - } - else - { - //If dealing with an unknown GroupDescription type, use the standard method to retrieve a group, in case group retrival is handle differently. - group = null; + return null; + } - foreach( var tempGroup in m_subGroups.Values ) + internal bool Contains(object item) { - if( m_subGroupBy.NamesMatch( tempGroup.Name, groupName ) ) - { - group = tempGroup; - break; - } + var group = item as DataGridCollectionViewGroup; + if (group != null) + { + //Must make sure the group the group is ref equals, because there can be groups with a null name at more than one level. + DataGridCollectionViewGroup foundGroup; + if (m_subGroups.TryGetValue(DataGridCollectionViewGroup.GetHashKeyFromName(group.Name), out foundGroup)) + return (foundGroup == group); + + return false; + } + + DataGridCollectionView collectionView = this.GetCollectionView(); + if (collectionView != null) + { + RawItem rawItem = collectionView.GetFirstRawItemFromDataItem(item); + if (rawItem != null) + return (rawItem.ParentGroup == this); + } + + return false; } - } - if( group == null ) - { - group = this.CreateSubGroup( groupName, level, groupByList, groupSortComparers ); - } + internal int IndexOf(object item) + { + if (item is DataGridCollectionViewGroup) + return this.ProtectedItems.IndexOf(item); - return group; - } + DataGridCollectionView collectionView = this.GetCollectionView(); - internal void SortItems( - IList sortDescriptionInfos, - List groupSortComparers, - int level, - List globalRawItems, - DataGridCollectionViewGroup newSortedGroup ) - { - var itemCount = this.ProtectedItemCount; - if( itemCount == 0 ) - return; + if (collectionView != null) + { + RawItem rawItem = collectionView.GetFirstRawItemFromDataItem(item); - if( this.IsBottomLevel ) - { - var indexes = new int[ itemCount + 1 ]; + if ((rawItem != null) && (rawItem.ParentGroup == this)) + return rawItem.SortedIndex; + } - for( int i = 0; i < itemCount; i++ ) + return -1; + } + + internal int GetFirstRawItemGlobalSortedIndex() { - indexes[ i ] = m_sortedRawItems[ i ].Index; + var index = 0; + var group = this; + var parent = this.Parent; + var currentGroup = default(DataGridCollectionViewGroup); + + while (parent != null) + { + var items = parent.ProtectedItems; + var count = items.Count; + + for (int i = 0; i < count; i++) + { + var value = items[i]; + if (value == group) + break; + + currentGroup = value as DataGridCollectionViewGroup; + index += currentGroup.GlobalRawItemCount; + } + + group = parent; + parent = parent.Parent; + } + + return index; } - // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] - var collectionViewSort = new DataGridCollectionViewSort( indexes, sortDescriptionInfos ); + internal void SetSubGroupBy(GroupDescription groupBy) + { + bool oldIsBottomLevel = this.IsBottomLevel; + m_subGroupBy = groupBy; - collectionViewSort.Sort( itemCount ); - var index = 0; + if (oldIsBottomLevel != this.IsBottomLevel) + { + this.OnPropertyChanged(new PropertyChangedEventArgs("IsBottomLevel")); + } + } - for( int i = 1; i <= itemCount; i++ ) + internal DataGridCollectionViewGroup GetGroup( + RawItem rawItem, + int level, + CultureInfo culture, + ObservableCollection groupByList, + List groupSortComparers) { - newSortedGroup.InsertRawItem( index, globalRawItems[ indexes[ i ] ] ); - index++; + // If sortComparers is null, we are in massive group creation, no order check. + + if (this.IsBottomLevel) + throw new InvalidOperationException("An attempt was made to get a group for which a GroupDescription has not been provided."); + + object groupName = m_subGroupBy.GroupNameFromItem(rawItem.DataItem, level, culture); + DataGridCollectionViewGroup group; + + if ((m_subGroupBy is DataGridGroupDescription) || (m_subGroupBy is PropertyGroupDescription)) + { + m_subGroups.TryGetValue(DataGridCollectionViewGroup.GetHashKeyFromName(groupName), out group); + } + else + { + //If dealing with an unknown GroupDescription type, use the standard method to retrieve a group, in case group retrival is handle differently. + group = null; + + foreach (var tempGroup in m_subGroups.Values) + { + if (m_subGroupBy.NamesMatch(tempGroup.Name, groupName)) + { + group = tempGroup; + break; + } + } + } + + if (group == null) + { + group = this.CreateSubGroup(groupName, level, groupByList, groupSortComparers); + } + + return group; } - } - else - { - var indexes = new int[ itemCount + 1 ]; - for( int i = 0; i < itemCount; i++ ) + internal void SortItems( + IList sortDescriptionInfos, + List groupSortComparers, + int level, + List globalRawItems, + DataGridCollectionViewGroup newSortedGroup) { - indexes[ i ] = i; + var itemCount = this.ProtectedItemCount; + if (itemCount == 0) + return; + + if (this.IsBottomLevel) + { + var indexes = new int[itemCount + 1]; + + for (int i = 0; i < itemCount; i++) + { + indexes[i] = m_sortedRawItems[i].Index; + } + + // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] + var collectionViewSort = new DataGridCollectionViewSort(indexes, sortDescriptionInfos); + + collectionViewSort.Sort(itemCount); + var index = 0; + + for (int i = 1; i <= itemCount; i++) + { + newSortedGroup.InsertRawItem(index, globalRawItems[indexes[i]]); + index++; + } + } + else + { + var indexes = new int[itemCount + 1]; + + for (int i = 0; i < itemCount; i++) + { + indexes[i] = i; + } + + var subGroupsArray = new DataGridCollectionViewGroup[itemCount]; + m_subGroups.Values.CopyTo(subGroupsArray, 0); + + // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] + var collectionViewSort = new DataGridCollectionViewGroupSort(indexes, groupSortComparers[level], subGroupsArray); + + collectionViewSort.Sort(itemCount); + int index = 0; + level++; + + for (int i = 1; i <= itemCount; i++) + { + DataGridCollectionViewGroup oldGroup = subGroupsArray[indexes[i]]; + DataGridCollectionViewGroup newGroup = new DataGridCollectionViewGroup(oldGroup, newSortedGroup); + + // Sort sub items + oldGroup.SortItems(sortDescriptionInfos, groupSortComparers, level, globalRawItems, newGroup); + + newSortedGroup.InsertGroup(index, newGroup); + index++; + } + } } - var subGroupsArray = new DataGridCollectionViewGroup[ itemCount ]; - m_subGroups.Values.CopyTo( subGroupsArray, 0 ); - - // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] - var collectionViewSort = new DataGridCollectionViewGroupSort( indexes, groupSortComparers[ level ], subGroupsArray ); - - collectionViewSort.Sort( itemCount ); - int index = 0; - level++; - - for( int i = 1; i <= itemCount; i++ ) + internal void SortGroups(List groupSortComparers, int level) { - DataGridCollectionViewGroup oldGroup = subGroupsArray[ indexes[ i ] ]; - DataGridCollectionViewGroup newGroup = new DataGridCollectionViewGroup( oldGroup, newSortedGroup ); + int itemCount = this.ProtectedItemCount; - // Sort sub items - oldGroup.SortItems( sortDescriptionInfos, groupSortComparers, level, globalRawItems, newGroup ); + if (itemCount == 0) + return; - newSortedGroup.InsertGroup( index, newGroup ); - index++; - } - } - } - - internal void SortGroups( List groupSortComparers, int level ) - { - int itemCount = this.ProtectedItemCount; + int[] indexes; + indexes = new int[itemCount + 1]; + for (int i = 0; i < itemCount; i++) + { + indexes[i] = i; + } - if( itemCount == 0 ) - return; + DataGridCollectionViewGroup[] subGroupsArray = new DataGridCollectionViewGroup[itemCount]; + m_subGroups.Values.CopyTo(subGroupsArray, 0); - int[] indexes; - indexes = new int[ itemCount + 1 ]; - for( int i = 0; i < itemCount; i++ ) - { - indexes[ i ] = i; - } + // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] + DataGridCollectionViewGroupSort collectionViewSort = new DataGridCollectionViewGroupSort(indexes, groupSortComparers[level], subGroupsArray); - DataGridCollectionViewGroup[] subGroupsArray = new DataGridCollectionViewGroup[ itemCount ]; - m_subGroups.Values.CopyTo( subGroupsArray, 0 ); + collectionViewSort.Sort(itemCount); + level++; + m_protectedItems.Clear(); - // "Weak heap sort" sort array[0..NUM_ELEMENTS-1] to array[1..NUM_ELEMENTS] - DataGridCollectionViewGroupSort collectionViewSort = new DataGridCollectionViewGroupSort( indexes, groupSortComparers[ level ], subGroupsArray ); + for (int i = 1; i <= itemCount; i++) + { + DataGridCollectionViewGroup group = subGroupsArray[indexes[i]]; - collectionViewSort.Sort( itemCount ); - level++; - m_protectedItems.Clear(); + // Sort sub groups + if (!group.IsBottomLevel) + { + group.SortGroups(groupSortComparers, level); + } - for( int i = 1; i <= itemCount; i++ ) - { - DataGridCollectionViewGroup group = subGroupsArray[ indexes[ i ] ]; + m_protectedItems.Add(group); + } - // Sort sub groups - if( !group.IsBottomLevel ) - { - group.SortGroups( groupSortComparers, level ); + this.ProtectedItemCount = m_protectedItems.Count; + m_protectedItemsCollectionChanged.Invoke(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } - m_protectedItems.Add( group ); - } - - this.ProtectedItemCount = m_protectedItems.Count; - m_protectedItemsCollectionChanged.Invoke( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ) ); - } - - internal void CreateFixedGroupNames( int fixedGroupLevel, ObservableCollection groupByList, List groupSortComparers ) - { - GroupDescription groupDescription = this.SubGroupBy; + internal void CreateFixedGroupNames(int fixedGroupLevel, ObservableCollection groupByList, List groupSortComparers) + { + GroupDescription groupDescription = this.SubGroupBy; - if( groupDescription == null ) - return; + if (groupDescription == null) + return; - Debug.Assert( groupByList[ fixedGroupLevel ] == this.SubGroupBy ); + Debug.Assert(groupByList[fixedGroupLevel] == this.SubGroupBy); - ObservableCollection groupNames = groupDescription.GroupNames; - int count = groupNames.Count; + ObservableCollection groupNames = groupDescription.GroupNames; + int count = groupNames.Count; - for( int i = 0; i < count; i++ ) - { - this.CreateSubGroup( groupNames[ i ], fixedGroupLevel, groupByList, groupSortComparers ); - } - } + for (int i = 0; i < count; i++) + { + this.CreateSubGroup(groupNames[i], fixedGroupLevel, groupByList, groupSortComparers); + } + } - internal RawItem GetRawItemAtGlobalSortedIndex( int index ) - { - if( this.IsBottomLevel ) - { - return m_sortedRawItems[ index ]; - } - else - { - foreach( object value in this.ProtectedItems ) + internal RawItem GetRawItemAtGlobalSortedIndex(int index) { - DataGridCollectionViewGroup subGroup = value as DataGridCollectionViewGroup; + if (this.IsBottomLevel) + { + return m_sortedRawItems[index]; + } + else + { + foreach (object value in this.ProtectedItems) + { + DataGridCollectionViewGroup subGroup = value as DataGridCollectionViewGroup; + + int subGroupCount = subGroup.GlobalRawItemCount; + + if (index < subGroupCount) + return subGroup.GetRawItemAtGlobalSortedIndex(index); + + index -= subGroupCount; + } + } + + throw new ArgumentOutOfRangeException("index"); + } - int subGroupCount = subGroup.GlobalRawItemCount; + internal int RawItemIndexOf(RawItem rawItem) + { + Debug.Assert(m_sortedRawItems != null); - if( index < subGroupCount ) - return subGroup.GetRawItemAtGlobalSortedIndex( index ); + if (m_sortedRawItems == null) + return -1; - index -= subGroupCount; + return m_sortedRawItems.IndexOf(rawItem); } - } - throw new ArgumentOutOfRangeException( "index" ); - } + internal virtual void InsertRawItem(int index, RawItem rawItem) + { + Debug.Assert(this.IsBottomLevel); - internal int RawItemIndexOf( RawItem rawItem ) - { - Debug.Assert( m_sortedRawItems != null ); + m_globalRawItemCount++; + DataGridCollectionViewGroup parent = m_parent; - if( m_sortedRawItems == null ) - return -1; + while (parent != null) + { + parent.m_globalRawItemCount++; + parent = parent.m_parent; + } - return m_sortedRawItems.IndexOf( rawItem ); - } + int count = m_sortedRawItems.Count; - internal virtual void InsertRawItem( int index, RawItem rawItem ) - { - Debug.Assert( this.IsBottomLevel ); + for (int i = index; i < count; i++) + { + m_sortedRawItems[i].SetSortedIndex(i + 1); + } - m_globalRawItemCount++; - DataGridCollectionViewGroup parent = m_parent; + m_sortedRawItems.Insert(index, rawItem); + rawItem.SetParentGroup(this); + rawItem.SetSortedIndex(index); - while( parent != null ) - { - parent.m_globalRawItemCount++; - parent = parent.m_parent; - } + this.ProtectedItemCount++; + this.ProtectedItems.Insert(index, rawItem.DataItem); + } - int count = m_sortedRawItems.Count; + internal virtual void RemoveRawItemAt(int index) + { + Debug.Assert(this.IsBottomLevel); + Debug.Assert(m_sortedRawItems.Count > 0); + + int count = m_sortedRawItems.Count; + if (count == 0) + return; + + if (index != -1) + { + m_globalRawItemCount--; + DataGridCollectionViewGroup parent = m_parent; + + while (parent != null) + { + parent.m_globalRawItemCount--; + parent = parent.Parent; + } + + for (int i = index + 1; i < count; i++) + { + m_sortedRawItems[i].SetSortedIndex(i - 1); + } + + RawItem rawItem = m_sortedRawItems[index]; + rawItem.SetParentGroup(null); + rawItem.SetSortedIndex(-1); + m_sortedRawItems.RemoveAt(index); + + this.ProtectedItemCount--; + this.ProtectedItems.RemoveAt(index); + + if ((this.ProtectedItemCount == 0) && (m_parent != null)) + { + m_parent.RemoveGroup(this); + } + } + } - for( int i = index; i < count; i++ ) - { - m_sortedRawItems[ i ].SetSortedIndex( i + 1 ); - } + internal virtual void MoveRawItem(int oldIndex, int newIndex) + { + Debug.Assert(this.IsBottomLevel); + Debug.Assert(m_sortedRawItems != null); - m_sortedRawItems.Insert( index, rawItem ); - rawItem.SetParentGroup( this ); - rawItem.SetSortedIndex( index ); + if (m_sortedRawItems == null) + return; - this.ProtectedItemCount++; - this.ProtectedItems.Insert( index, rawItem.DataItem ); - } + RawItem rawItem = m_sortedRawItems[oldIndex]; - internal virtual void RemoveRawItemAt( int index ) - { - Debug.Assert( this.IsBottomLevel ); - Debug.Assert( m_sortedRawItems.Count > 0 ); + m_sortedRawItems.RemoveAt(oldIndex); + m_sortedRawItems.Insert(newIndex, rawItem); - int count = m_sortedRawItems.Count; - if( count == 0 ) - return; + int startIndex = Math.Min(oldIndex, newIndex); + int endIndex = Math.Max(oldIndex, newIndex); - if( index != -1 ) - { - m_globalRawItemCount--; - DataGridCollectionViewGroup parent = m_parent; + for (int i = startIndex; i <= endIndex; i++) + { + m_sortedRawItems[i].SetSortedIndex(i); + } - while( parent != null ) - { - parent.m_globalRawItemCount--; - parent = parent.Parent; + this.ProtectedItems.Move(oldIndex, newIndex); } - for( int i = index + 1; i < count; i++ ) + internal int BinarySearchRawItem(RawItem value, IComparer comparer) { - m_sortedRawItems[ i ].SetSortedIndex( i - 1 ); + if (comparer == null) + throw new ArgumentNullException("comparer"); + + if (m_sortedRawItems == null) + return -1; // ~0 + + Debug.Assert((m_sortedRawItems.Count == this.ProtectedItemCount) || (this is DataGridCollectionViewGroupRoot)); + + int low = 0; + int hi = (m_sortedRawItems.Count) - 1; + + while (low <= hi) + { + int compareResult; + int median = (low + ((hi - low) >> 1)); + + RawItem medianRawItem = m_sortedRawItems[median]; + + // We exclude ourself from the research because we seek for a new valid position + if (medianRawItem == value) + { + if (low == hi) + return low; + + median++; + medianRawItem = m_sortedRawItems[median]; + } + + try + { + compareResult = comparer.Compare(medianRawItem, value); + } + catch (Exception exception) + { + throw new InvalidOperationException("IComparer has failed to compare the values.", exception); + } + + if (compareResult == 0) + { + return median; + } + if (compareResult < 0) + { + low = median + 1; + } + else + { + hi = median - 1; + } + } + + return ~low; } - RawItem rawItem = m_sortedRawItems[ index ]; - rawItem.SetParentGroup( null ); - rawItem.SetSortedIndex( -1 ); - m_sortedRawItems.RemoveAt( index ); - - this.ProtectedItemCount--; - this.ProtectedItems.RemoveAt( index ); - - if( ( this.ProtectedItemCount == 0 ) && ( m_parent != null ) ) + private int BinarySearchGroup(DataGridCollectionViewGroup value, IComparer comparer) { - m_parent.RemoveGroup( this ); + if (comparer == null) + throw new ArgumentNullException("comparer"); + + int low = 0; + int hi = (this.ProtectedItemCount) - 1; + int median; + int compareResult; + + while (low <= hi) + { + median = (low + ((hi - low) >> 1)); + + DataGridCollectionViewGroup medianGroup = this.ProtectedItems[median] as DataGridCollectionViewGroup; + + if (medianGroup == value) + { + if (low == hi) + return low; + + return median; + } + + try + { + compareResult = comparer.Compare(medianGroup, value); + } + catch (Exception exception) + { + throw new InvalidOperationException("IComparer has failed to compare the values.", exception); + } + + if (compareResult == 0) + { + return median; + } + if (compareResult < 0) + { + low = median + 1; + } + else + { + hi = median - 1; + } + } + + return ~low; } - } - } - internal virtual void MoveRawItem( int oldIndex, int newIndex ) - { - Debug.Assert( this.IsBottomLevel ); - Debug.Assert( m_sortedRawItems != null ); + private static object GetHashKeyFromName(object groupName) + { + if (groupName == null) + return DBNull.Value; - if( m_sortedRawItems == null ) - return; + return groupName; + } - RawItem rawItem = m_sortedRawItems[ oldIndex ]; + private DataGridCollectionViewGroup CreateSubGroup(object groupName, int level, ObservableCollection groupByList, + List groupSortComparers) + { + // If sortComparers is null, we are in massive group creation, no order check. + var group = new DataGridCollectionViewGroup(groupName, this, m_nextSubGroupUnsortedIndex); + + var dataGridGroupDescription = groupByList[level] as DataGridGroupDescription; + if (dataGridGroupDescription != null) + { + group.GroupByName = dataGridGroupDescription.PropertyName; + } + + unchecked + { + m_nextSubGroupUnsortedIndex++; + } + + int index; + + if (groupSortComparers == null) + { + Debug.Assert(this.ProtectedItemCount == this.ProtectedItems.Count); + index = this.ProtectedItemCount; + } + else + { + index = this.BinarySearchGroup(group, groupSortComparers[level]); + + if (index < 0) + { + index = ~index; + } + } + + level++; + + if (level < groupByList.Count) + { + group.SetSubGroupBy(groupByList[level]); + group.CreateFixedGroupNames(level, groupByList, groupSortComparers); + } + + this.InsertGroup(index, group); + return group; + } - m_sortedRawItems.RemoveAt( oldIndex ); - m_sortedRawItems.Insert( newIndex, rawItem ); + private void InsertGroup(int index, DataGridCollectionViewGroup group) + { + Debug.Assert(!this.IsBottomLevel); - int startIndex = Math.Min( oldIndex, newIndex ); - int endIndex = Math.Max( oldIndex, newIndex ); + m_subGroups.Add(DataGridCollectionViewGroup.GetHashKeyFromName(group.Name), group); + this.ProtectedItemCount++; + this.ProtectedItems.Insert(index, group); + } - for( int i = startIndex; i <= endIndex; i++ ) - { - m_sortedRawItems[ i ].SetSortedIndex( i ); - } + private void RemoveGroup(DataGridCollectionViewGroup group) + { + if (group == null) + throw new ArgumentNullException("group"); - this.ProtectedItems.Move( oldIndex, newIndex ); - } + Debug.Assert(this == group.m_parent); - internal int BinarySearchRawItem( RawItem value, IComparer comparer ) - { - if( comparer == null ) - throw new ArgumentNullException( "comparer" ); + // We do not remove group forced in SubGroupBy.GroupNames + if (group.UnsortedIndex < this.SubGroupBy.GroupNames.Count) + return; - if( m_sortedRawItems == null ) - return -1; // ~0 + Debug.Assert(!this.IsBottomLevel); + Debug.Assert((group.m_globalRawItemCount == 0) && (group.ProtectedItemCount == 0)); - Debug.Assert( ( m_sortedRawItems.Count == this.ProtectedItemCount ) || ( this is DataGridCollectionViewGroupRoot ) ); + m_subGroups.Remove(DataGridCollectionViewGroup.GetHashKeyFromName(group.Name)); - int low = 0; - int hi = ( m_sortedRawItems.Count ) - 1; + this.ProtectedItemCount--; + this.ProtectedItems.Remove(group); - while( low <= hi ) - { - int compareResult; - int median = ( low + ( ( hi - low ) >> 1 ) ); + if ((m_subGroups.Count == 0) && (m_parent != null)) + { + m_parent.RemoveGroup(this); + } + } - RawItem medianRawItem = m_sortedRawItems[ median ]; + #region ICustomTypeDescriptor Members - // We exclude ourself from the research because we seek for a new valid position - if( medianRawItem == value ) + AttributeCollection ICustomTypeDescriptor.GetAttributes() { - if( low == hi ) - return low; - - median++; - medianRawItem = m_sortedRawItems[ median ]; + return AttributeCollection.Empty; } - try + string ICustomTypeDescriptor.GetClassName() { - compareResult = comparer.Compare( medianRawItem, value ); + return null; } - catch( Exception exception ) + + string ICustomTypeDescriptor.GetComponentName() { - throw new InvalidOperationException( "IComparer has failed to compare the values.", exception ); + return null; } - if( compareResult == 0 ) + TypeConverter ICustomTypeDescriptor.GetConverter() { - return median; + return null; } - if( compareResult < 0 ) + + EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() { - low = median + 1; + return null; } - else + + PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() { - hi = median - 1; + return null; } - } - - return ~low; - } - private int BinarySearchGroup( DataGridCollectionViewGroup value, IComparer comparer ) - { - if( comparer == null ) - throw new ArgumentNullException( "comparer" ); - - int low = 0; - int hi = ( this.ProtectedItemCount ) - 1; - int median; - int compareResult; - - while( low <= hi ) - { - median = ( low + ( ( hi - low ) >> 1 ) ); - - DataGridCollectionViewGroup medianGroup = this.ProtectedItems[ median ] as DataGridCollectionViewGroup; - - if( medianGroup == value ) + object ICustomTypeDescriptor.GetEditor(Type editorBaseType) { - if( low == hi ) - return low; - - return median; + return null; } - try + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) { - compareResult = comparer.Compare( medianGroup, value ); + return EventDescriptorCollection.Empty; } - catch( Exception exception ) + + EventDescriptorCollection ICustomTypeDescriptor.GetEvents() { - throw new InvalidOperationException( "IComparer has failed to compare the values.", exception ); + return EventDescriptorCollection.Empty; } - if( compareResult == 0 ) + // This method returns the StatFunction properties as defined by the "parent" + // DataGridCollectionView as well as the other "standard" properties for this class. + // The StatFunction properties are NOT filtered by the specified attributes. + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) { - return median; + if (attributes == null) + { + // We only cache the full property list. + if (m_classProperties == null) + { + DataGridCollectionView view = this.GetCollectionView(); + + Debug.Assert(view != null, "A group should always have a parent CollectionView for the StatFunctions to work."); + + if (view == null) + return TypeDescriptor.GetProperties(typeof(DataGridCollectionViewGroup)); + + PropertyDescriptorCollection classProperties = TypeDescriptor.GetProperties(typeof(DataGridCollectionViewGroup)); + PropertyDescriptor[] properties = new PropertyDescriptor[classProperties.Count]; + classProperties.CopyTo(properties, 0); + + m_classProperties = new PropertyDescriptorCollection(properties); + } + + return m_classProperties; + } + else + { + PropertyDescriptorCollection props = TypeDescriptor.GetProperties(this, attributes); + DataGridCollectionView view = this.GetCollectionView(); + + return props; + } } - if( compareResult < 0 ) + + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() { - low = median + 1; + return ((ICustomTypeDescriptor)this).GetProperties(null); } - else + + object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) { - hi = median - 1; + return this; } - } - return ~low; - } + #endregion - private static object GetHashKeyFromName( object groupName ) - { - if( groupName == null ) - return DBNull.Value; + #region INotifyPropertyChanged Members - return groupName; - } - - private DataGridCollectionViewGroup CreateSubGroup( object groupName, int level, ObservableCollection groupByList, - List groupSortComparers ) - { - // If sortComparers is null, we are in massive group creation, no order check. - var group = new DataGridCollectionViewGroup( groupName, this, m_nextSubGroupUnsortedIndex ); - - var dataGridGroupDescription = groupByList[ level ] as DataGridGroupDescription; - if( dataGridGroupDescription != null ) - { - group.GroupByName = dataGridGroupDescription.PropertyName; - } - - unchecked - { - m_nextSubGroupUnsortedIndex++; - } - - int index; - - if( groupSortComparers == null ) - { - Debug.Assert( this.ProtectedItemCount == this.ProtectedItems.Count ); - index = this.ProtectedItemCount; - } - else - { - index = this.BinarySearchGroup( group, groupSortComparers[ level ] ); - - if( index < 0 ) + protected sealed override event PropertyChangedEventHandler PropertyChanged { - index = ~index; + add + { + this.PropertyChangedImpl += value; + } + remove + { + this.PropertyChangedImpl -= value; + } } - } - - level++; - - if( level < groupByList.Count ) - { - group.SetSubGroupBy( groupByList[ level ] ); - group.CreateFixedGroupNames( level, groupByList, groupSortComparers ); - } - - this.InsertGroup( index, group ); - return group; - } - - private void InsertGroup( int index, DataGridCollectionViewGroup group ) - { - Debug.Assert( !this.IsBottomLevel ); - - m_subGroups.Add( DataGridCollectionViewGroup.GetHashKeyFromName( group.Name ), group ); - this.ProtectedItemCount++; - this.ProtectedItems.Insert( index, group ); - } - - private void RemoveGroup( DataGridCollectionViewGroup group ) - { - if( group == null ) - throw new ArgumentNullException( "group" ); - - Debug.Assert( this == group.m_parent ); - - // We do not remove group forced in SubGroupBy.GroupNames - if( group.UnsortedIndex < this.SubGroupBy.GroupNames.Count ) - return; - - Debug.Assert( !this.IsBottomLevel ); - Debug.Assert( ( group.m_globalRawItemCount == 0 ) && ( group.ProtectedItemCount == 0 ) ); - - m_subGroups.Remove( DataGridCollectionViewGroup.GetHashKeyFromName( group.Name ) ); - - this.ProtectedItemCount--; - this.ProtectedItems.Remove( group ); - - if( ( m_subGroups.Count == 0 ) && ( m_parent != null ) ) - { - m_parent.RemoveGroup( this ); - } - } - - #region ICustomTypeDescriptor Members - - AttributeCollection ICustomTypeDescriptor.GetAttributes() - { - return AttributeCollection.Empty; - } - string ICustomTypeDescriptor.GetClassName() - { - return null; - } - - string ICustomTypeDescriptor.GetComponentName() - { - return null; - } - - TypeConverter ICustomTypeDescriptor.GetConverter() - { - return null; - } - - EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() - { - return null; - } - - PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() - { - return null; - } - - object ICustomTypeDescriptor.GetEditor( Type editorBaseType ) - { - return null; - } - - EventDescriptorCollection ICustomTypeDescriptor.GetEvents( Attribute[] attributes ) - { - return EventDescriptorCollection.Empty; - } - - EventDescriptorCollection ICustomTypeDescriptor.GetEvents() - { - return EventDescriptorCollection.Empty; - } - - // This method returns the StatFunction properties as defined by the "parent" - // DataGridCollectionView as well as the other "standard" properties for this class. - // The StatFunction properties are NOT filtered by the specified attributes. - PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties( Attribute[] attributes ) - { - if( attributes == null ) - { - // We only cache the full property list. - if( m_classProperties == null ) + protected override void OnPropertyChanged(PropertyChangedEventArgs e) { - DataGridCollectionView view = this.GetCollectionView(); - - Debug.Assert( view != null, "A group should always have a parent CollectionView for the StatFunctions to work." ); + var handler = this.PropertyChangedImpl; + if (handler == null) + return; - if( view == null ) - return TypeDescriptor.GetProperties( typeof( DataGridCollectionViewGroup ) ); - - PropertyDescriptorCollection classProperties = TypeDescriptor.GetProperties( typeof( DataGridCollectionViewGroup ) ); - PropertyDescriptor[] properties = new PropertyDescriptor[ classProperties.Count ]; - classProperties.CopyTo( properties, 0 ); - - m_classProperties = new PropertyDescriptorCollection( properties ); + handler.Invoke(this, e); } - return m_classProperties; - } - else - { - PropertyDescriptorCollection props = TypeDescriptor.GetProperties( this, attributes ); - DataGridCollectionView view = this.GetCollectionView(); - - return props; - } - } - - PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() - { - return ( ( ICustomTypeDescriptor )this ).GetProperties( null ); - } - - object ICustomTypeDescriptor.GetPropertyOwner( PropertyDescriptor pd ) - { - return this; - } - - #endregion - - #region INotifyPropertyChanged Members - - protected sealed override event PropertyChangedEventHandler PropertyChanged - { - add - { - this.PropertyChangedImpl += value; - } - remove - { - this.PropertyChangedImpl -= value; - } - } - - protected override void OnPropertyChanged( PropertyChangedEventArgs e ) - { - var handler = this.PropertyChangedImpl; - if( handler == null ) - return; + private bool HasPropertyChangedListeners + { + get + { + return (this.PropertyChangedImpl != null); + } + } - handler.Invoke( this, e ); - } + private event PropertyChangedEventHandler PropertyChangedImpl; - private bool HasPropertyChangedListeners - { - get - { - return ( this.PropertyChangedImpl != null ); - } - } - - private event PropertyChangedEventHandler PropertyChangedImpl; + #endregion - #endregion + private PropertyDescriptorCollection m_classProperties; - private PropertyDescriptorCollection m_classProperties; + protected int m_globalRawItemCount; + protected readonly List m_sortedRawItems; - protected int m_globalRawItemCount; - protected readonly List m_sortedRawItems; + private readonly OptimizedReadOnlyObservableCollection m_optimizedItems; + private readonly Dictionary m_subGroups; + private readonly IList m_protectedItems; + private readonly Action m_protectedItemsCollectionChanged; - private readonly OptimizedReadOnlyObservableCollection m_optimizedItems; - private readonly Dictionary m_subGroups; - private readonly IList m_protectedItems; - private readonly Action m_protectedItemsCollectionChanged; + private GroupDescription m_subGroupBy; + private readonly DataGridCollectionViewGroup m_parent; + private readonly int m_unsortedIndex; + private int m_nextSubGroupUnsortedIndex; - private GroupDescription m_subGroupBy; - private readonly DataGridCollectionViewGroup m_parent; - private readonly int m_unsortedIndex; - private int m_nextSubGroupUnsortedIndex; + #region OptimizedReadOnlyObservableCollection Private Class - #region OptimizedReadOnlyObservableCollection Private Class + // We re-implement IList and IList to override the implementation of the + // IndexOf and Contains methods to use our optimized way. + private sealed class OptimizedReadOnlyObservableCollection : ReadOnlyObservableCollection, IList, IList + { + internal OptimizedReadOnlyObservableCollection(DataGridCollectionViewGroup dataGridCollectionViewGroup) + : base(dataGridCollectionViewGroup.ProtectedItems) + { + if (dataGridCollectionViewGroup == null) + throw new ArgumentNullException("dataGridCollectionViewGroup"); + + m_dataGridCollectionViewGroup = dataGridCollectionViewGroup; + } + + public new int IndexOf(object item) + { + // The DataGridCollectionViewGroup has been optimized to use the information + // stored on the RawItem associated with the data item instead of searching the item in the list. + return m_dataGridCollectionViewGroup.IndexOf(item); + } + + public new bool Contains(object item) + { + // The DataGridCollectionViewGroup has been optimized to use the information + // stored on the RawItem associated with the data item instead of searching the item in the list. + return m_dataGridCollectionViewGroup.Contains(item); + } + + private readonly DataGridCollectionViewGroup m_dataGridCollectionViewGroup; + } - // We re-implement IList and IList to override the implementation of the - // IndexOf and Contains methods to use our optimized way. - private sealed class OptimizedReadOnlyObservableCollection : ReadOnlyObservableCollection, IList, IList - { - internal OptimizedReadOnlyObservableCollection( DataGridCollectionViewGroup dataGridCollectionViewGroup ) - : base( dataGridCollectionViewGroup.ProtectedItems ) - { - if( dataGridCollectionViewGroup == null ) - throw new ArgumentNullException( "dataGridCollectionViewGroup" ); - - m_dataGridCollectionViewGroup = dataGridCollectionViewGroup; - } - - public new int IndexOf( object item ) - { - // The DataGridCollectionViewGroup has been optimized to use the information - // stored on the RawItem associated with the data item instead of searching the item in the list. - return m_dataGridCollectionViewGroup.IndexOf( item ); - } - - public new bool Contains( object item ) - { - // The DataGridCollectionViewGroup has been optimized to use the information - // stored on the RawItem associated with the data item instead of searching the item in the list. - return m_dataGridCollectionViewGroup.Contains( item ); - } - - private readonly DataGridCollectionViewGroup m_dataGridCollectionViewGroup; - } + #endregion - #endregion + #region ObservableCollectionHelper Private Class - #region ObservableCollectionHelper Private Class + private static class ObservableCollectionHelper + { + private const string AssemblyName = "Xceed.Wpf.DataGrid.CollectionViewGroupExtractor"; + private const string GetItemsMethodName = "GetItems"; + private const string GetCollectionChangedMethodName = "GetCollectionChanged"; + + private static readonly Func, IList> s_getItems; + private static readonly Func, Action> s_collectionChanged; + + static ObservableCollectionHelper() + { + var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(ObservableCollectionHelper.AssemblyName), AssemblyBuilderAccess.RunAndCollect); + var moduleBuilder = assemblyBuilder.DefineDynamicModule(ObservableCollectionHelper.AssemblyName); + + var typeBuilder = moduleBuilder.DefineType("ObservableCollectionExtractor", TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.AutoLayout, typeof(ObservableCollection)); + + ObservableCollectionHelper.DefineGetItemsMethod(typeBuilder); + ObservableCollectionHelper.DefineGetCollectionChangedMethod(typeBuilder); + + var targetType = typeBuilder.CreateType(); + + s_getItems = (Func, IList>)Delegate.CreateDelegate(typeof(Func, IList>), targetType.GetMethod(ObservableCollectionHelper.GetItemsMethodName, BindingFlags.Public | BindingFlags.Static)); + s_collectionChanged = (Func, Action>)Delegate.CreateDelegate(typeof(Func, Action>), targetType.GetMethod(ObservableCollectionHelper.GetCollectionChangedMethodName, BindingFlags.Public | BindingFlags.Static)); + } + + internal static IList GetItems(ObservableCollection source) + { + if (source == null) + throw new ArgumentNullException("source"); + + var storage = (s_getItems != null) ? s_getItems.Invoke(source) : null; + if (storage == null) + throw new InvalidOperationException("Unable to retrieve the ObservableCollection<>'s items storage."); + + return storage; + } + + internal static Action GetCollectionChanged(ObservableCollection source) + { + if (source == null) + throw new ArgumentNullException("source"); + + var collectionChanged = (s_collectionChanged != null) ? s_collectionChanged.Invoke(source) : null; + if (collectionChanged == null) + throw new InvalidOperationException("Unable to retrieve the ObservableCollection<>'s collection change method."); + + return collectionChanged; + } + + private static void DefineGetItemsMethod(TypeBuilder typeBuilder) + { + var propertyInfo = typeof(ObservableCollection).GetProperty("Items", BindingFlags.Instance | BindingFlags.NonPublic, null, typeof(IList), new Type[0], null); + if ((propertyInfo == null) || !propertyInfo.CanRead) + throw new InvalidOperationException("Unable to retrieve the ObservableCollection<>.Items property."); + + var methodInfo = propertyInfo.GetGetMethod(true); + if ((methodInfo == null) || !ObservableCollectionHelper.HasCallingConvention(methodInfo.CallingConvention, CallingConventions.HasThis)) + throw new InvalidOperationException("Unable to retrieve the ObservableCollection<>.Items property."); + + var methodBuilder = typeBuilder.DefineMethod( + ObservableCollectionHelper.GetItemsMethodName, + MethodAttributes.Public | MethodAttributes.Static, + CallingConventions.Standard, + typeof(IList), + new Type[] { typeof(ObservableCollection) }); + + var body = methodBuilder.GetILGenerator(); + // Load the reference to the ObservableCollection and put it on top of the stack. + body.Emit(OpCodes.Ldarg_0); + // Invoke the property getter of the reference. This operation pops the reference + // from the stack and pushes the result of the property getter. + body.Emit(OpCodes.Callvirt, methodInfo); + // Since the result of the propery getter will be retrieved by the method's caller, + // we may leave it on the stack and simply return. + body.Emit(OpCodes.Ret); + } + + private static void DefineGetCollectionChangedMethod(TypeBuilder typeBuilder) + { + var methodInfo = typeof(ObservableCollection).GetMethod("OnCollectionChanged", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof(NotifyCollectionChangedEventArgs) }, null); + if ((methodInfo == null) || methodInfo.IsPrivate || !ObservableCollectionHelper.HasCallingConvention(methodInfo.CallingConvention, CallingConventions.HasThis)) + throw new InvalidOperationException("Unable to retrieve the ObservableCollection<>.OnCollectionChanged method."); + + var constructorInfo = typeof(Action).GetConstructor(new Type[] { typeof(object), typeof(IntPtr) }); + if ((constructorInfo == null) || constructorInfo.IsPrivate || !ObservableCollectionHelper.HasCallingConvention(constructorInfo.CallingConvention, CallingConventions.HasThis)) + throw new InvalidOperationException("Unable to retrieve the Action<>'s constructor."); + + var methodBuilder = typeBuilder.DefineMethod( + ObservableCollectionHelper.GetCollectionChangedMethodName, + MethodAttributes.Public | MethodAttributes.Static, + CallingConventions.Standard, + typeof(Action), + new Type[] { typeof(ObservableCollection) }); + + var body = methodBuilder.GetILGenerator(); + // Load the reference to the ObservableCollection and put it on top of the stack. + body.Emit(OpCodes.Ldarg_0); + // The last loaded reference will be consume in the call to "new Action<>". + // We must duplicate the value since it will be consume by the call that retrieve the + // target method's address. + body.Emit(OpCodes.Dup); + // This operation pops the top ObservableCollection's reference from the stack + // and pushes the ObservableCollection<>.OnCollectionChanged method's address. + body.Emit(OpCodes.Ldvirtftn, methodInfo); + // Create an Action<> delegate from the first ObservableCollection's reference we + // have put on the stack and the target method's address. + body.Emit(OpCodes.Newobj, constructorInfo); + // The resulting delegate should be on top of the stack. We simply leave it there + // so it will be retrieved by the method's caller. + body.Emit(OpCodes.Ret); + } + + private static bool HasCallingConvention(CallingConventions source, CallingConventions value) + { + return ((source & value) == value); + } + } - private static class ObservableCollectionHelper - { - private const string AssemblyName = "Xceed.Wpf.DataGrid.CollectionViewGroupExtractor"; - private const string GetItemsMethodName = "GetItems"; - private const string GetCollectionChangedMethodName = "GetCollectionChanged"; - - private static readonly Func, IList> s_getItems; - private static readonly Func, Action> s_collectionChanged; - - static ObservableCollectionHelper() - { - var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly( new AssemblyName( ObservableCollectionHelper.AssemblyName ), AssemblyBuilderAccess.RunAndCollect ); - var moduleBuilder = assemblyBuilder.DefineDynamicModule( ObservableCollectionHelper.AssemblyName ); - - var typeBuilder = moduleBuilder.DefineType( "ObservableCollectionExtractor", TypeAttributes.Class | TypeAttributes.NotPublic | TypeAttributes.AutoLayout, typeof( ObservableCollection ) ); - - ObservableCollectionHelper.DefineGetItemsMethod( typeBuilder ); - ObservableCollectionHelper.DefineGetCollectionChangedMethod( typeBuilder ); - - var targetType = typeBuilder.CreateType(); - - s_getItems = ( Func, IList> )Delegate.CreateDelegate( typeof( Func, IList> ), targetType.GetMethod( ObservableCollectionHelper.GetItemsMethodName, BindingFlags.Public | BindingFlags.Static ) ); - s_collectionChanged = ( Func, Action> )Delegate.CreateDelegate( typeof( Func, Action> ), targetType.GetMethod( ObservableCollectionHelper.GetCollectionChangedMethodName, BindingFlags.Public | BindingFlags.Static ) ); - } - - internal static IList GetItems( ObservableCollection source ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - var storage = ( s_getItems != null ) ? s_getItems.Invoke( source ) : null; - if( storage == null ) - throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>'s items storage." ); - - return storage; - } - - internal static Action GetCollectionChanged( ObservableCollection source ) - { - if( source == null ) - throw new ArgumentNullException( "source" ); - - var collectionChanged = ( s_collectionChanged != null ) ? s_collectionChanged.Invoke( source ) : null; - if( collectionChanged == null ) - throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>'s collection change method." ); - - return collectionChanged; - } - - private static void DefineGetItemsMethod( TypeBuilder typeBuilder ) - { - var propertyInfo = typeof( ObservableCollection ).GetProperty( "Items", BindingFlags.Instance | BindingFlags.NonPublic, null, typeof( IList ), new Type[ 0 ], null ); - if( ( propertyInfo == null ) || !propertyInfo.CanRead ) - throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>.Items property." ); - - var methodInfo = propertyInfo.GetGetMethod( true ); - if( ( methodInfo == null ) || !ObservableCollectionHelper.HasCallingConvention( methodInfo.CallingConvention, CallingConventions.HasThis ) ) - throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>.Items property." ); - - var methodBuilder = typeBuilder.DefineMethod( - ObservableCollectionHelper.GetItemsMethodName, - MethodAttributes.Public | MethodAttributes.Static, - CallingConventions.Standard, - typeof( IList ), - new Type[] { typeof( ObservableCollection ) } ); - - var body = methodBuilder.GetILGenerator(); - // Load the reference to the ObservableCollection and put it on top of the stack. - body.Emit( OpCodes.Ldarg_0 ); - // Invoke the property getter of the reference. This operation pops the reference - // from the stack and pushes the result of the property getter. - body.Emit( OpCodes.Callvirt, methodInfo ); - // Since the result of the propery getter will be retrieved by the method's caller, - // we may leave it on the stack and simply return. - body.Emit( OpCodes.Ret ); - } - - private static void DefineGetCollectionChangedMethod( TypeBuilder typeBuilder ) - { - var methodInfo = typeof( ObservableCollection ).GetMethod( "OnCollectionChanged", BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[] { typeof( NotifyCollectionChangedEventArgs ) }, null ); - if( ( methodInfo == null ) || methodInfo.IsPrivate || !ObservableCollectionHelper.HasCallingConvention( methodInfo.CallingConvention, CallingConventions.HasThis ) ) - throw new InvalidOperationException( "Unable to retrieve the ObservableCollection<>.OnCollectionChanged method." ); - - var constructorInfo = typeof( Action ).GetConstructor( new Type[] { typeof( object ), typeof( IntPtr ) } ); - if( ( constructorInfo == null ) || constructorInfo.IsPrivate || !ObservableCollectionHelper.HasCallingConvention( constructorInfo.CallingConvention, CallingConventions.HasThis ) ) - throw new InvalidOperationException( "Unable to retrieve the Action<>'s constructor." ); - - var methodBuilder = typeBuilder.DefineMethod( - ObservableCollectionHelper.GetCollectionChangedMethodName, - MethodAttributes.Public | MethodAttributes.Static, - CallingConventions.Standard, - typeof( Action ), - new Type[] { typeof( ObservableCollection ) } ); - - var body = methodBuilder.GetILGenerator(); - // Load the reference to the ObservableCollection and put it on top of the stack. - body.Emit( OpCodes.Ldarg_0 ); - // The last loaded reference will be consume in the call to "new Action<>". - // We must duplicate the value since it will be consume by the call that retrieve the - // target method's address. - body.Emit( OpCodes.Dup ); - // This operation pops the top ObservableCollection's reference from the stack - // and pushes the ObservableCollection<>.OnCollectionChanged method's address. - body.Emit( OpCodes.Ldvirtftn, methodInfo ); - // Create an Action<> delegate from the first ObservableCollection's reference we - // have put on the stack and the target method's address. - body.Emit( OpCodes.Newobj, constructorInfo ); - // The resulting delegate should be on top of the stack. We simply leave it there - // so it will be retrieved by the method's caller. - body.Emit( OpCodes.Ret ); - } - - private static bool HasCallingConvention( CallingConventions source, CallingConventions value ) - { - return ( ( source & value ) == value ); - } + #endregion } - - #endregion - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs index da4dc938..07cff6b0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/EntityDetailDescription.cs @@ -17,91 +17,91 @@ using System; using System.Collections; using System.ComponentModel; -using System.Data.Objects.DataClasses; +using System.Data.Entity.Core.Objects.DataClasses; using System.Reflection; namespace Xceed.Wpf.DataGrid { - internal class EntityDetailDescription : DataGridDetailDescription - { - public EntityDetailDescription() + internal class EntityDetailDescription : DataGridDetailDescription { - } - - public EntityDetailDescription( string propertyName ) - : this() - { - if( string.IsNullOrEmpty( propertyName ) ) - throw new ArgumentException( "The specified property name is null or empty", "propertyName" ); + public EntityDetailDescription() + { + } - this.RelationName = propertyName; - } + public EntityDetailDescription(string propertyName) + : this() + { + if (string.IsNullOrEmpty(propertyName)) + throw new ArgumentException("The specified property name is null or empty", "propertyName"); - #region QueryDetails Event + this.RelationName = propertyName; + } - public event EventHandler QueryDetails; + #region QueryDetails Event - protected virtual void OnQueryDetails( QueryEntityDetailsEventArgs e ) - { - var handler = this.QueryDetails; - if( handler == null ) - return; + public event EventHandler QueryDetails; - handler.Invoke( this, e ); - } + protected virtual void OnQueryDetails(QueryEntityDetailsEventArgs e) + { + var handler = this.QueryDetails; + if (handler == null) + return; - #endregion + handler.Invoke(this, e); + } - protected internal override IEnumerable GetDetailsForParentItem( DataGridCollectionViewBase parentCollectionView, object parentItem ) - { - EntityObject entityObject = parentItem as EntityObject; + #endregion - if( entityObject == null ) - return null; + protected internal override IEnumerable GetDetailsForParentItem(DataGridCollectionViewBase parentCollectionView, object parentItem) + { + EntityObject entityObject = parentItem as EntityObject; - // Even if EntityObject is not in a loadable state, we must still return the IList - // so that the ItemProperties can be extracted based on the elements type. - bool entityObjectLoadable = ItemsSourceHelper.IsEntityObjectLoadable( entityObject ); + if (entityObject == null) + return null; - // We let the user take charge of handling the details. - QueryEntityDetailsEventArgs args = new QueryEntityDetailsEventArgs( entityObject ); + // Even if EntityObject is not in a loadable state, we must still return the IList + // so that the ItemProperties can be extracted based on the elements type. + bool entityObjectLoadable = ItemsSourceHelper.IsEntityObjectLoadable(entityObject); - if( entityObjectLoadable ) - this.OnQueryDetails( args ); + // We let the user take charge of handling the details. + QueryEntityDetailsEventArgs args = new QueryEntityDetailsEventArgs(entityObject); - // The parentItem must implement IEntityWithRelationships - Type parentItemType = parentItem.GetType(); - if( typeof( IEntityWithRelationships ).IsAssignableFrom( parentItemType ) ) - { - // Since the relationship was based on the the property - // name, we must find that property using reflection. - PropertyInfo propertyInfo = parentItemType.GetProperty( this.RelationName ); + if (entityObjectLoadable) + this.OnQueryDetails(args); - if( propertyInfo != null ) - { - RelatedEnd relatedEnd = propertyInfo.GetValue( parentItem, null ) as RelatedEnd; - - if( relatedEnd != null ) - { - // Make sure that the details are loaded - // except if the user already handled it. - if( !relatedEnd.IsLoaded - && !args.Handled - && entityObjectLoadable ) + // The parentItem must implement IEntityWithRelationships + Type parentItemType = parentItem.GetType(); + if (typeof(IEntityWithRelationships).IsAssignableFrom(parentItemType)) { - relatedEnd.Load(); + // Since the relationship was based on the the property + // name, we must find that property using reflection. + PropertyInfo propertyInfo = parentItemType.GetProperty(this.RelationName); + + if (propertyInfo != null) + { + RelatedEnd relatedEnd = propertyInfo.GetValue(parentItem, null) as RelatedEnd; + + if (relatedEnd != null) + { + // Make sure that the details are loaded + // except if the user already handled it. + if (!relatedEnd.IsLoaded + && !args.Handled + && entityObjectLoadable) + { + relatedEnd.Load(); + } + + IListSource listSource = relatedEnd as IListSource; + + // Returns an IList to have proper change notification events. + if (listSource != null) + return listSource.GetList(); + } + } } - IListSource listSource = relatedEnd as IListSource; - - // Returns an IList to have proper change notification events. - if( listSource != null ) - return listSource.GetList(); - } + return null; } - } - - return null; } - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryEntityDetailsEventArgs.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryEntityDetailsEventArgs.cs index 1ecf2f1b..0b4deeea 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryEntityDetailsEventArgs.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/(CollectionView)/QueryEntityDetailsEventArgs.cs @@ -15,47 +15,43 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Windows; -using System.Data.Objects.DataClasses; +using System.Data.Entity.Core.Objects.DataClasses; namespace Xceed.Wpf.DataGrid { - public class QueryEntityDetailsEventArgs : EventArgs - { - #region CONSTRUCTORS - - internal QueryEntityDetailsEventArgs( EntityObject parentItem ) - : base() + public class QueryEntityDetailsEventArgs : EventArgs { - if( parentItem == null ) - throw new ArgumentNullException( "parentItem" ); + #region CONSTRUCTORS - this.ParentItem = parentItem; - } + internal QueryEntityDetailsEventArgs(EntityObject parentItem) + : base() + { + if (parentItem == null) + throw new ArgumentNullException("parentItem"); - #endregion CONSTRUCTORS + this.ParentItem = parentItem; + } - #region ParentItem Property + #endregion CONSTRUCTORS - public EntityObject ParentItem - { - get; - private set; - } + #region ParentItem Property - #endregion ParentItem Property + public EntityObject ParentItem + { + get; + private set; + } - #region Handled Property + #endregion ParentItem Property - public bool Handled - { - get; - set; - } + #region Handled Property - #endregion Handled Property - } + public bool Handled + { + get; + set; + } + + #endregion Handled Property + } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs index b5ca1722..819c4664 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/AssemblyVersionInfo.cs @@ -14,28 +14,86 @@ ***********************************************************************************/ -[assembly: System.Reflection.AssemblyVersion( _XceedVersionInfo.Version )] +#region Using directives + +using System; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Security; +using System.Windows; +using System.Windows.Markup; + +#endregion + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Xceed Toolkit for WPF - DataGrid")] +[assembly: AssemblyDescription("This assembly implements the Xceed.Wpf.DataGrid namespace, a data grid control for the Windows Presentation Framework.")] + +[assembly: AssemblyCompany("Xceed Software Inc.")] +[assembly: AssemblyProduct("Xceed Toolkit for WPF - DataGrid")] +[assembly: AssemblyCopyright("Copyright (C) Xceed Software Inc. 2007-2017")] + + +[assembly: CLSCompliant(true)] +[assembly: ComVisible(false)] + +[assembly: XmlnsPrefix("http://schemas.xceed.com/wpf/xaml/datagrid", "xcdg")] +[assembly: XmlnsDefinition("http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid")] +[assembly: XmlnsDefinition("http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.Converters")] +[assembly: XmlnsDefinition("http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.Markup")] +[assembly: XmlnsDefinition("http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.Views")] +[assembly: XmlnsDefinition("http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.ValidationRules")] + + +[assembly: SecurityRules(SecurityRuleSet.Level1)] +[assembly: AllowPartiallyTrustedCallers] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + +[assembly: ThemeInfo( + ResourceDictionaryLocation.SourceAssembly, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + +#pragma warning disable 1699 +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile(@"sn.snk")] +[assembly: AssemblyKeyName("")] +#pragma warning restore 1699 internal static class _XceedVersionInfo { - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string BaseVersion = "3.4"; - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string Version = BaseVersion + ".0.0"; - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string PublicKeyToken = "ba83ff368b7563c6"; - - public const string FrameworkVersion = "4.0.0.0"; - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string DesignFullName = - "Xceed.Wpf.DataGrid,Version=" + - Version + - ",Culture=neutral,PublicKeyToken=" + PublicKeyToken; - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields" )] - public const string CurrentAssemblyPackUri = - "pack://application:,,,/Xceed.Wpf.DataGrid,Version=" + Version; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public const string BaseVersion = "3.4"; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public const string Version = BaseVersion + ".0.0"; + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public const string PublicKeyToken = "ba83ff368b7563c6"; + + public const string FrameworkVersion = "4.0.0.0"; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public const string DesignFullName = + "Xceed.Wpf.DataGrid,Version=" + + Version + + ",Culture=neutral,PublicKeyToken=" + PublicKeyToken; + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1823:AvoidUnusedPrivateFields")] + public const string CurrentAssemblyPackUri = + "pack://application:,,,/Xceed.Wpf.DataGrid,Version=" + Version; } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/ImageConverter.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/ImageConverter.cs index b0e12d71..84727d24 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/ImageConverter.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Converters/ImageConverter.cs @@ -15,96 +15,92 @@ ***********************************************************************************/ using System; -using System.Collections.Generic; -using System.Text; +using System.ComponentModel; +using System.Windows; using System.Windows.Data; -using System.Windows.Controls; using System.Windows.Media; -using System.Windows.Media.Imaging; -using System.Windows; -using System.ComponentModel; namespace Xceed.Wpf.DataGrid.Converters { - [EditorBrowsable( EditorBrowsableState.Never )] - [ValueConversion( typeof( object ), typeof( ImageSource ) )] - public class ImageConverter : IValueConverter - { - #region IValueConverter Members - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Performance", "CA1800:DoNotCastUnnecessarily" )] - public object Convert( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) + [EditorBrowsable(EditorBrowsableState.Never)] + [ValueConversion(typeof(object), typeof(ImageSource))] + public class ImageConverter : IValueConverter { - if( !targetType.IsAssignableFrom( typeof( ImageSource ) ) ) - return DependencyProperty.UnsetValue; + #region IValueConverter Members + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily")] + public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + if (!targetType.IsAssignableFrom(typeof(ImageSource))) + return DependencyProperty.UnsetValue; - if( ( value == null ) || ( value is ImageSource ) ) - return value; + if ((value == null) || (value is ImageSource)) + return value; - ImageSource imageSource = null; + ImageSource imageSource = null; - System.Drawing.Image image = value as System.Drawing.Image; + //System.Drawing.Image image = value as System.Drawing.Image; - if( image != null ) - { - imageSource = ImageConverter.ConvertFromWinFormsImage( image ); - } - else - { - byte[] byteArray = value as byte[]; + //if (image != null) + //{ + // imageSource = ImageConverter.ConvertFromWinFormsImage(image); + //} + //else + //{ + byte[] byteArray = value as byte[]; - if( byteArray != null ) - { - imageSource = ImageConverter.ConvertFromByteArray( byteArray ); + if (byteArray != null) + { + imageSource = ImageConverter.ConvertFromByteArray(byteArray); + } + //} + + return imageSource; } - } - return imageSource; - } + public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) + { + return Binding.DoNothing; + } - public object ConvertBack( object value, Type targetType, object parameter, System.Globalization.CultureInfo culture ) - { - return Binding.DoNothing; - } + #endregion - #endregion + #region PRIVATE METHODS - #region PRIVATE METHODS + //private static ImageSource ConvertFromWinFormsImage(System.Drawing.Image image) + //{ + // ImageSource imageSource = null; - private static ImageSource ConvertFromWinFormsImage( System.Drawing.Image image ) - { - ImageSource imageSource = null; + // try + // { + // System.Drawing.ImageConverter imageConverter = new System.Drawing.ImageConverter(); - try - { - System.Drawing.ImageConverter imageConverter = new System.Drawing.ImageConverter(); + // byte[] imageBytes = (byte[])imageConverter.ConvertTo(image, typeof(byte[])); - byte[] imageBytes = ( byte[] )imageConverter.ConvertTo( image, typeof( byte[] ) ); + // if (imageBytes != null) + // imageSource = ImageConverter.ConvertFromByteArray(imageBytes); + // } + // catch { } - if( imageBytes != null ) - imageSource = ImageConverter.ConvertFromByteArray( imageBytes ); - } - catch {} + // return imageSource; + //} - return imageSource; - } + private static ImageSource ConvertFromByteArray(byte[] imageBytes) + { + ImageSource imageSource = null; + + try + { + ImageSourceConverter imageSourceConverter = new ImageSourceConverter(); + imageSource = imageSourceConverter.ConvertFrom(imageBytes) as ImageSource; + } + catch + { + } + + return imageSource; + } - private static ImageSource ConvertFromByteArray( byte[] imageBytes ) - { - ImageSource imageSource = null; - - try - { - ImageSourceConverter imageSourceConverter = new ImageSourceConverter(); - imageSource = imageSourceConverter.ConvertFrom( imageBytes ) as ImageSource; - } - catch - { - } - - return imageSource; + #endregion PRIVATE METHODS } - - #endregion PRIVATE METHODS - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs index ab48b471..d5cdbd17 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/DataGridContext.cs @@ -25,7 +25,6 @@ using System.Globalization; using System.Linq; using System.Threading; using System.Windows; -using System.Windows.Automation.Peers; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; @@ -35,4285 +34,4284 @@ using Xceed.Wpf.DataGrid.Views; namespace Xceed.Wpf.DataGrid { - public sealed class DataGridContext : DependencyObject, INotifyPropertyChanged, IWeakEventListener, IDataGridContextVisitable, ICustomTypeDescriptor - { - internal DataGridContext( - DataGridContext parentDataGridContext, - DataGridControl dataGridControl, - object parentItem, - CollectionView collectionView, - DetailConfiguration detailConfiguration ) - { - if( dataGridControl == null ) - throw new ArgumentNullException( "dataGridControl" ); - - if( collectionView == null ) - throw new ArgumentNullException( "collectionView" ); - - // ParentItem cannot be null except when dealing with the root DataGridContext. - if( ( parentDataGridContext != null ) && ( parentItem == null ) ) - throw new ArgumentNullException( "parentItem" ); - - m_parentDataGridContext = parentDataGridContext; //voluntarily not validating if not null... this will be null for master level. - m_dataGridControl = dataGridControl; - m_dataGridControlItemsSource = m_dataGridControl.ItemsSource; - m_parentItem = parentItem; - m_items = collectionView; - m_detailConfig = detailConfiguration; //voluntarily not validating if not null... this will be null for master level. - - m_currencyManager = new CurrencyManager( this, m_items ); - - m_selectedItemsStore = new SelectedItemsStorage( this ); - m_selectedCellsStore = new SelectedCellsStorage( this ); - m_selectedItemsRanges = new SelectionItemRangeCollection( m_selectedItemsStore ); - m_selectedCellRanges = new SelectionCellRangeCollection( m_selectedCellsStore ); - m_selectedItems = new SelectionItemCollection( m_selectedItemsStore ); - - CollectionChangedEventManager.AddListener( m_items, this ); - - var dataGridCollectionViewBase = m_items as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - { - PreBatchCollectionChangedEventManager.AddListener( dataGridCollectionViewBase, this ); - PostBatchCollectionChangedEventManager.AddListener( dataGridCollectionViewBase, this ); - } - - //if this is a DataGridCollectionView - var dataGridCollectionView = m_items as DataGridCollectionView; - if( dataGridCollectionView != null ) - { - //Set its dataGridContext so it can propagate a DeferRefresh to details' DataGridCollectionView's - dataGridCollectionView.PrepareRootContextForDeferRefresh( this ); - } - - //If the detailConfiguration is null then we are in the master... - if( m_detailConfig == null ) - { - var columns = new ColumnCollection( dataGridControl, null ); - - m_columnManager = new ColumnHierarchyManager( columns ); - m_itemsSourcePropertyDescriptions = dataGridControl.ItemsSourcePropertyDescriptions; - m_itemPropertyMap = dataGridControl.ItemPropertyMap; - m_groupLevelDescriptions = new GroupLevelDescriptionCollection(); - - //in this particular case, I need to create a SortDescriptionsSyncContext to ensure I will be able to synchronize access to the sort descriptions collection. - m_sortDescriptionsSyncContext = new SortDescriptionsSyncContext(); - - //Register to the Columns Collection's CollectionChanged event to manage the Removal of the CurrentColumn. - CollectionChangedEventManager.AddListener( m_columnManager.Columns, this ); - - // Register to the VisibleColumnsChanged to update, if need be, the columns desired width when column stretching is active and there's a column reordering. - CollectionChangedEventManager.AddListener( m_columnManager.VisibleColumns, this ); - - CollectionChangedEventManager.AddListener( m_items.SortDescriptions, this ); - CollectionChangedEventManager.AddListener( m_items.GroupDescriptions, this ); - - GroupConfigurationSelectorChangedEventManager.AddListener( m_dataGridControl, this ); - AllowDetailToggleChangedEventManager.AddListener( m_dataGridControl, this ); - MaxGroupLevelsChangedEventManager.AddListener( m_dataGridControl, this ); - MaxSortLevelsChangedEventManager.AddListener( m_dataGridControl, this ); - ItemsSourceChangeCompletedEventManager.AddListener( m_dataGridControl, this ); - - this.HookToItemPropertiesChanged(); - } - //Detail DataGridContext - else - { - m_detailConfig.AddDataGridContext( this ); - - m_columnManager = m_detailConfig.ColumnManager; - m_itemsSourcePropertyDescriptions = m_detailConfig.ItemsSourcePropertyDescriptions; - m_itemPropertyMap = m_detailConfig.ItemPropertyMap; - - //only listen to the detail grid config current column changed if the detail grid config is synchronized. - CurrentColumnChangedEventManager.AddListener( m_detailConfig, this ); - - GroupConfigurationSelectorChangedEventManager.AddListener( m_detailConfig, this ); - AllowDetailToggleChangedEventManager.AddListener( m_detailConfig, this ); - - // Register to the VisibleColumnsChanged to update, if need be, the columns desired width - // when column stretching is active and there's a column reordering. - CollectionChangedEventManager.AddListener( m_detailConfig.VisibleColumns, this ); - - MaxGroupLevelsChangedEventManager.AddListener( m_detailConfig, this ); - MaxSortLevelsChangedEventManager.AddListener( m_detailConfig, this ); - - m_detailConfig.DetailConfigurations.DataGridControl = dataGridControl; - } - - Debug.Assert( m_columnManager != null ); - Debug.Assert( m_itemsSourcePropertyDescriptions != null ); - Debug.Assert( m_itemPropertyMap != null ); - - ColumnsLayoutChangingEventManager.AddListener( m_columnManager, this ); - ColumnsLayoutChangedEventManager.AddListener( m_columnManager, this ); - DetailVisibilityChangedEventManager.AddListener( this.DetailConfigurations, this ); - RealizedContainersRequestedEventManager.AddListener( this.Columns, this ); - DistinctValuesRequestedEventManager.AddListener( this.Columns, this ); - - this.SetupViewProperties(); - this.InitializeViewProperties(); - - ViewChangedEventManager.AddListener( m_dataGridControl, this ); - - GroupLevelDescriptionCollection groupLevelDescriptions = this.GroupLevelDescriptions; - ObservableCollection groupDescriptions = m_items.GroupDescriptions; - if( groupLevelDescriptions.Count != groupDescriptions.Count ) - { - DataGridContext.UpdateGroupLevelDescriptions( groupLevelDescriptions, new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Reset ), groupDescriptions, this.Columns ); - } - - // Set the value of DetailLevel property - DataGridContext tempDataGridContext = this.ParentDataGridContext; - while( tempDataGridContext != null ) - { - this.DetailLevel++; - tempDataGridContext = tempDataGridContext.ParentDataGridContext; - } - } - - private void Items_CollectionChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - if( m_deferSelectionChangedOnItemsCollectionChanged != null ) - { - m_deferSelectionChangedOnItemsCollectionChanged.Queue( e ); - } - else - { - this.UpdateSelectionAfterSourceCollectionChanged( e ); - } - } - - private void UpdateSelectionAfterSourceCollectionChanged( NotifyCollectionChangedEventArgs e ) - { - if( m_dataGridControl.SelectedIndexPropertyNeedCoerce ) - { - m_dataGridControl.CoerceValue( DataGridControl.SelectedIndexProperty ); - } + public sealed class DataGridContext : DependencyObject, INotifyPropertyChanged, IWeakEventListener, IDataGridContextVisitable, ICustomTypeDescriptor + { + internal DataGridContext( + DataGridContext parentDataGridContext, + DataGridControl dataGridControl, + object parentItem, + CollectionView collectionView, + DetailConfiguration detailConfiguration) + { + if (dataGridControl == null) + throw new ArgumentNullException("dataGridControl"); - if( m_dataGridControl.SelectedItemPropertyNeedCoerce ) - { - m_dataGridControl.CoerceValue( DataGridControl.SelectedItemProperty ); - } + if (collectionView == null) + throw new ArgumentNullException("collectionView"); - m_dataGridControl.SelectionChangerManager.UpdateSelectionAfterSourceCollectionChanged( this, e ); + // ParentItem cannot be null except when dealing with the root DataGridContext. + if ((parentDataGridContext != null) && (parentItem == null)) + throw new ArgumentNullException("parentItem"); - } + m_parentDataGridContext = parentDataGridContext; //voluntarily not validating if not null... this will be null for master level. + m_dataGridControl = dataGridControl; + m_dataGridControlItemsSource = m_dataGridControl.ItemsSource; + m_parentItem = parentItem; + m_items = collectionView; + m_detailConfig = detailConfiguration; //voluntarily not validating if not null... this will be null for master level. - internal void CleanDataGridContext() - { - m_currencyManager.CleanManager(); - - if( m_items != null ) - { - CollectionChangedEventManager.RemoveListener( m_items, this ); - - var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - { - dataGridCollectionViewBase.Dispose(); - } - } - - if( m_detailConfig == null ) - { - GroupConfigurationSelectorChangedEventManager.RemoveListener( m_dataGridControl, this ); - AllowDetailToggleChangedEventManager.RemoveListener( m_dataGridControl, this ); - MaxGroupLevelsChangedEventManager.RemoveListener( m_dataGridControl, this ); - MaxSortLevelsChangedEventManager.RemoveListener( m_dataGridControl, this ); - ItemsSourceChangeCompletedEventManager.RemoveListener( m_dataGridControl, this ); - - CollectionChangedEventManager.RemoveListener( m_items.SortDescriptions, this ); - CollectionChangedEventManager.RemoveListener( m_items.GroupDescriptions, this ); - - this.UnhookToItemPropertiesChanged( m_dataGridControlItemsSource as DataGridCollectionViewBase ); - } - else - { - CurrentColumnChangedEventManager.RemoveListener( m_detailConfig, this ); - GroupConfigurationSelectorChangedEventManager.RemoveListener( m_detailConfig, this ); - AllowDetailToggleChangedEventManager.RemoveListener( m_detailConfig, this ); - CollectionChangedEventManager.RemoveListener( m_detailConfig.VisibleColumns, this ); - MaxGroupLevelsChangedEventManager.RemoveListener( m_detailConfig, this ); - MaxSortLevelsChangedEventManager.RemoveListener( m_detailConfig, this ); - - m_detailConfig.RemoveDataGridContext( this ); - } - - this.ClearSizeStates(); - - ColumnsLayoutChangingEventManager.RemoveListener( m_columnManager, this ); - ColumnsLayoutChangedEventManager.RemoveListener( m_columnManager, this ); - CollectionChangedEventManager.RemoveListener( this.DetailConfigurations, this ); - DetailVisibilityChangedEventManager.RemoveListener( this.DetailConfigurations, this ); - RealizedContainersRequestedEventManager.RemoveListener( this.Columns, this ); - DistinctValuesRequestedEventManager.RemoveListener( this.Columns, this ); - - ViewChangedEventManager.RemoveListener( m_dataGridControl, this ); - - var columnVirtualizationManager = this.ColumnVirtualizationManager; - if( columnVirtualizationManager != null ) - { - columnVirtualizationManager.CleanManager(); - ColumnVirtualizationManager.ClearColumnVirtualizationManager( this ); - } - - this.ClearViewPropertyBindings(); - - if( m_defaultDetailConfiguration != null ) - { - GroupConfigurationSelectorChangedEventManager.RemoveListener( m_defaultDetailConfiguration, this ); - m_defaultDetailConfiguration = null; - } - } + m_currencyManager = new CurrencyManager(this, m_items); - //---------- PUBLIC PROPERTIES ---------- + m_selectedItemsStore = new SelectedItemsStorage(this); + m_selectedCellsStore = new SelectedCellsStorage(this); + m_selectedItemsRanges = new SelectionItemRangeCollection(m_selectedItemsStore); + m_selectedCellRanges = new SelectionCellRangeCollection(m_selectedCellsStore); + m_selectedItems = new SelectionItemCollection(m_selectedItemsStore); - #region ParentDataGridContext Read-Only Property + CollectionChangedEventManager.AddListener(m_items, this); - public DataGridContext ParentDataGridContext - { - get - { - return m_parentDataGridContext; - } - } + var dataGridCollectionViewBase = m_items as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + { + PreBatchCollectionChangedEventManager.AddListener(dataGridCollectionViewBase, this); + PostBatchCollectionChangedEventManager.AddListener(dataGridCollectionViewBase, this); + } - private readonly DataGridContext m_parentDataGridContext; // = null + //if this is a DataGridCollectionView + var dataGridCollectionView = m_items as DataGridCollectionView; + if (dataGridCollectionView != null) + { + //Set its dataGridContext so it can propagate a DeferRefresh to details' DataGridCollectionView's + dataGridCollectionView.PrepareRootContextForDeferRefresh(this); + } - #endregion + //If the detailConfiguration is null then we are in the master... + if (m_detailConfig == null) + { + var columns = new ColumnCollection(dataGridControl, null); - #region ParentItem Read-Only Property + m_columnManager = new ColumnHierarchyManager(columns); + m_itemsSourcePropertyDescriptions = dataGridControl.ItemsSourcePropertyDescriptions; + m_itemPropertyMap = dataGridControl.ItemPropertyMap; + m_groupLevelDescriptions = new GroupLevelDescriptionCollection(); - public object ParentItem - { - get - { - return m_parentItem; - } - } + //in this particular case, I need to create a SortDescriptionsSyncContext to ensure I will be able to synchronize access to the sort descriptions collection. + m_sortDescriptionsSyncContext = new SortDescriptionsSyncContext(); - private readonly object m_parentItem; + //Register to the Columns Collection's CollectionChanged event to manage the Removal of the CurrentColumn. + CollectionChangedEventManager.AddListener(m_columnManager.Columns, this); - #endregion + // Register to the VisibleColumnsChanged to update, if need be, the columns desired width when column stretching is active and there's a column reordering. + CollectionChangedEventManager.AddListener(m_columnManager.VisibleColumns, this); - #region AllowDetailToggle Property + CollectionChangedEventManager.AddListener(m_items.SortDescriptions, this); + CollectionChangedEventManager.AddListener(m_items.GroupDescriptions, this); - public bool AllowDetailToggle - { - get - { - if( m_detailConfig != null ) - { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.AllowDetailToggle; + GroupConfigurationSelectorChangedEventManager.AddListener(m_dataGridControl, this); + AllowDetailToggleChangedEventManager.AddListener(m_dataGridControl, this); + MaxGroupLevelsChangedEventManager.AddListener(m_dataGridControl, this); + MaxSortLevelsChangedEventManager.AddListener(m_dataGridControl, this); + ItemsSourceChangeCompletedEventManager.AddListener(m_dataGridControl, this); - return m_detailConfig.AllowDetailToggle; - } + this.HookToItemPropertiesChanged(); + } + //Detail DataGridContext + else + { + m_detailConfig.AddDataGridContext(this); - return m_dataGridControl.AllowDetailToggle; - } - } + m_columnManager = m_detailConfig.ColumnManager; + m_itemsSourcePropertyDescriptions = m_detailConfig.ItemsSourcePropertyDescriptions; + m_itemPropertyMap = m_detailConfig.ItemPropertyMap; - #endregion + //only listen to the detail grid config current column changed if the detail grid config is synchronized. + CurrentColumnChangedEventManager.AddListener(m_detailConfig, this); - #region DistinctValues Property + GroupConfigurationSelectorChangedEventManager.AddListener(m_detailConfig, this); + AllowDetailToggleChangedEventManager.AddListener(m_detailConfig, this); - public IDictionary DistinctValues - { - get - { - var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionViewBase == null ) - return null; - - return null; - } - } + // Register to the VisibleColumnsChanged to update, if need be, the columns desired width + // when column stretching is active and there's a column reordering. + CollectionChangedEventManager.AddListener(m_detailConfig.VisibleColumns, this); - #endregion + MaxGroupLevelsChangedEventManager.AddListener(m_detailConfig, this); + MaxSortLevelsChangedEventManager.AddListener(m_detailConfig, this); - #region Columns Read-Only Property + m_detailConfig.DetailConfigurations.DataGridControl = dataGridControl; + } - public ColumnCollection Columns - { - get - { - return m_columnManager.Columns; - } - } + Debug.Assert(m_columnManager != null); + Debug.Assert(m_itemsSourcePropertyDescriptions != null); + Debug.Assert(m_itemPropertyMap != null); - #endregion + ColumnsLayoutChangingEventManager.AddListener(m_columnManager, this); + ColumnsLayoutChangedEventManager.AddListener(m_columnManager, this); + DetailVisibilityChangedEventManager.AddListener(this.DetailConfigurations, this); + RealizedContainersRequestedEventManager.AddListener(this.Columns, this); + DistinctValuesRequestedEventManager.AddListener(this.Columns, this); - #region Items Property + this.SetupViewProperties(); + this.InitializeViewProperties(); - public CollectionView Items - { - get - { - return m_items; - } - } + ViewChangedEventManager.AddListener(m_dataGridControl, this); - private readonly CollectionView m_items; + GroupLevelDescriptionCollection groupLevelDescriptions = this.GroupLevelDescriptions; + ObservableCollection groupDescriptions = m_items.GroupDescriptions; + if (groupLevelDescriptions.Count != groupDescriptions.Count) + { + DataGridContext.UpdateGroupLevelDescriptions(groupLevelDescriptions, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset), groupDescriptions, this.Columns); + } - #endregion + // Set the value of DetailLevel property + DataGridContext tempDataGridContext = this.ParentDataGridContext; + while (tempDataGridContext != null) + { + this.DetailLevel++; + tempDataGridContext = tempDataGridContext.ParentDataGridContext; + } + } - #region OriginalItems Property + private void Items_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + if (m_deferSelectionChangedOnItemsCollectionChanged != null) + { + m_deferSelectionChangedOnItemsCollectionChanged.Queue(e); + } + else + { + this.UpdateSelectionAfterSourceCollectionChanged(e); + } + } - internal IEnumerable ItemsSourceCollection - { - get - { - if( m_parentDataGridContext != null ) - return m_items; + private void UpdateSelectionAfterSourceCollectionChanged(NotifyCollectionChangedEventArgs e) + { + if (m_dataGridControl.SelectedIndexPropertyNeedCoerce) + { + m_dataGridControl.CoerceValue(DataGridControl.SelectedIndexProperty); + } - return m_dataGridControl.ItemsSource; - } - } + if (m_dataGridControl.SelectedItemPropertyNeedCoerce) + { + m_dataGridControl.CoerceValue(DataGridControl.SelectedItemProperty); + } - #endregion + m_dataGridControl.SelectionChangerManager.UpdateSelectionAfterSourceCollectionChanged(this, e); - #region CurrentColumn Property + } - public ColumnBase CurrentColumn - { - get - { - if( m_detailConfig != null ) - return m_detailConfig.CurrentColumn; - - return m_currentColumn; - } - set - { - if( m_currentColumn == value ) - return; - - this.SetCurrentColumnCore( value, true, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentColumnChanged ); - } - } + internal void CleanDataGridContext() + { + m_currencyManager.CleanManager(); - internal void SetCurrentColumnCore( ColumnBase column, bool isCancelable, bool synchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers trigger ) - { - this.SetCurrent( this.InternalCurrentItem, null, null, column, false, isCancelable, synchronizeSelectionWithCurrent, trigger ); - } + if (m_items != null) + { + CollectionChangedEventManager.RemoveListener(m_items, this); - private ColumnBase m_currentColumn; // = null + var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + { + dataGridCollectionViewBase.Dispose(); + } + } - private void SetCurrentColumnHelper( ColumnBase value ) - { - if( m_detailConfig != null ) - { - m_detailConfig.CurrentColumn = value; - } - else - { - m_currentColumn = value; - } - } + if (m_detailConfig == null) + { + GroupConfigurationSelectorChangedEventManager.RemoveListener(m_dataGridControl, this); + AllowDetailToggleChangedEventManager.RemoveListener(m_dataGridControl, this); + MaxGroupLevelsChangedEventManager.RemoveListener(m_dataGridControl, this); + MaxSortLevelsChangedEventManager.RemoveListener(m_dataGridControl, this); + ItemsSourceChangeCompletedEventManager.RemoveListener(m_dataGridControl, this); - #endregion + CollectionChangedEventManager.RemoveListener(m_items.SortDescriptions, this); + CollectionChangedEventManager.RemoveListener(m_items.GroupDescriptions, this); - #region CurrentItem Properties + this.UnhookToItemPropertiesChanged(m_dataGridControlItemsSource as DataGridCollectionViewBase); + } + else + { + CurrentColumnChangedEventManager.RemoveListener(m_detailConfig, this); + GroupConfigurationSelectorChangedEventManager.RemoveListener(m_detailConfig, this); + AllowDetailToggleChangedEventManager.RemoveListener(m_detailConfig, this); + CollectionChangedEventManager.RemoveListener(m_detailConfig.VisibleColumns, this); + MaxGroupLevelsChangedEventManager.RemoveListener(m_detailConfig, this); + MaxSortLevelsChangedEventManager.RemoveListener(m_detailConfig, this); + + m_detailConfig.RemoveDataGridContext(this); + } - public object CurrentItem - { - get - { - return m_currentItem; - } - set - { - if( value == m_currentItem ) - return; - - this.SetCurrentItemCore( value, true, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentItemChanged ); - } - } + this.ClearSizeStates(); - internal void SetCurrentItemCore( object item, bool isCancelable, bool synchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers trigger ) - { - this.SetCurrent( item, null, null, this.CurrentColumn, false, isCancelable, synchronizeSelectionWithCurrent, trigger ); - } + ColumnsLayoutChangingEventManager.RemoveListener(m_columnManager, this); + ColumnsLayoutChangedEventManager.RemoveListener(m_columnManager, this); + CollectionChangedEventManager.RemoveListener(this.DetailConfigurations, this); + DetailVisibilityChangedEventManager.RemoveListener(this.DetailConfigurations, this); + RealizedContainersRequestedEventManager.RemoveListener(this.Columns, this); + DistinctValuesRequestedEventManager.RemoveListener(this.Columns, this); - public int CurrentItemIndex - { - get - { - return m_currentItemIndex; - } - set - { - if( value == m_currentItemIndex ) - return; - - this.SetCurrentItemIndexCore( value, true, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentItemChanged ); - } - } + ViewChangedEventManager.RemoveListener(m_dataGridControl, this); - internal void SetCurrentItemIndexCore( int index, bool isCancelable, bool synchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers trigger ) - { - this.SetCurrent( this.Items.GetItemAt( index ), null, index, this.CurrentColumn, false, isCancelable, synchronizeSelectionWithCurrent, trigger ); - } + var columnVirtualizationManager = this.ColumnVirtualizationManager; + if (columnVirtualizationManager != null) + { + columnVirtualizationManager.CleanManager(); + ColumnVirtualizationManager.ClearColumnVirtualizationManager(this); + } - private void SetCurrentItem( object dataItem, int sourceDataItemIndex ) - { - // This is called only for DataItem - if( ( m_currentItem == dataItem ) && ( m_currentItemIndex == sourceDataItemIndex ) ) - return; + this.ClearViewPropertyBindings(); - m_currentItem = dataItem; - m_currentItemIndex = sourceDataItemIndex; - this.OnCurrentItemChanged(); - } + if (m_defaultDetailConfiguration != null) + { + GroupConfigurationSelectorChangedEventManager.RemoveListener(m_defaultDetailConfiguration, this); + m_defaultDetailConfiguration = null; + } + } - internal event EventHandler CurrentItemChanged; + //---------- PUBLIC PROPERTIES ---------- - private void OnCurrentItemChanged() - { - var handler = this.CurrentItemChanged; - if( handler == null ) - return; + #region ParentDataGridContext Read-Only Property - handler.Invoke( this, EventArgs.Empty ); - } + public DataGridContext ParentDataGridContext + { + get + { + return m_parentDataGridContext; + } + } - private object m_currentItem; // = null - private int m_currentItemIndex = -1; + private readonly DataGridContext m_parentDataGridContext; // = null - #endregion + #endregion - #region DefaultGroupConfiguration Read-Only Property + #region ParentItem Read-Only Property - public GroupConfiguration DefaultGroupConfiguration - { - get - { - if( m_detailConfig != null ) + public object ParentItem { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.DefaultGroupConfiguration; - - return m_detailConfig.DefaultGroupConfiguration; + get + { + return m_parentItem; + } } - return m_dataGridControl.DefaultGroupConfiguration; - } - } + private readonly object m_parentItem; - #endregion + #endregion - #region DetailConfigurations Read-Only Property + #region AllowDetailToggle Property - internal DetailConfigurationCollection DetailConfigurations - { - get - { - if( m_detailConfig != null ) - return m_detailConfig.DetailConfigurations; + public bool AllowDetailToggle + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.AllowDetailToggle; - return null; - } - } + return m_detailConfig.AllowDetailToggle; + } + + return m_dataGridControl.AllowDetailToggle; + } + } - #endregion + #endregion - #region Footers Read-Only Property + #region DistinctValues Property - public ObservableCollection Footers - { - get - { - if( m_detailConfig != null ) + public IDictionary DistinctValues { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.Footers; + get + { + var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionViewBase == null) + return null; - return m_detailConfig.Footers; + return null; + } } - var view = m_dataGridControl.GetView(); - if( view == null ) - return new ObservableCollection(); + #endregion - return view.Footers; - } - } + #region Columns Read-Only Property - #endregion + public ColumnCollection Columns + { + get + { + return m_columnManager.Columns; + } + } - #region GroupLevelDescriptions Read-Only Property + #endregion - public GroupLevelDescriptionCollection GroupLevelDescriptions - { - get - { - if( m_detailConfig != null ) - return m_detailConfig.GroupLevelDescriptions; + #region Items Property - return m_groupLevelDescriptions; - } - } + public CollectionView Items + { + get + { + return m_items; + } + } - private readonly GroupLevelDescriptionCollection m_groupLevelDescriptions; //null + private readonly CollectionView m_items; - #endregion + #endregion - #region GroupConfigurationSelector Property + #region OriginalItems Property - public GroupConfigurationSelector GroupConfigurationSelector - { - get - { - if( m_detailConfig != null ) + internal IEnumerable ItemsSourceCollection { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.GroupConfigurationSelector; + get + { + if (m_parentDataGridContext != null) + return m_items; - return m_detailConfig.GroupConfigurationSelector; + return m_dataGridControl.ItemsSource; + } } - return m_dataGridControl.GroupConfigurationSelector; - } - } + #endregion - private void OnGroupConfigurationSelectorChanged() - { - var handler = this.GroupConfigurationSelectorChanged; - if( handler == null ) - return; + #region CurrentColumn Property - handler.Invoke( this, EventArgs.Empty ); - } + public ColumnBase CurrentColumn + { + get + { + if (m_detailConfig != null) + return m_detailConfig.CurrentColumn; + + return m_currentColumn; + } + set + { + if (m_currentColumn == value) + return; - internal event EventHandler GroupConfigurationSelectorChanged; + this.SetCurrentColumnCore(value, true, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentColumnChanged); + } + } - #endregion + internal void SetCurrentColumnCore(ColumnBase column, bool isCancelable, bool synchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers trigger) + { + this.SetCurrent(this.InternalCurrentItem, null, null, column, false, isCancelable, synchronizeSelectionWithCurrent, trigger); + } - #region HasDetails Read-Only Property + private ColumnBase m_currentColumn; // = null - public bool HasDetails - { - get - { - return false; - } - } + private void SetCurrentColumnHelper(ColumnBase value) + { + if (m_detailConfig != null) + { + m_detailConfig.CurrentColumn = value; + } + else + { + m_currentColumn = value; + } + } - #endregion + #endregion - #region Headers Read-Only property + #region CurrentItem Properties - public ObservableCollection Headers - { - get - { - if( m_detailConfig != null ) + public object CurrentItem { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.Headers; + get + { + return m_currentItem; + } + set + { + if (value == m_currentItem) + return; - return m_detailConfig.Headers; + this.SetCurrentItemCore(value, true, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentItemChanged); + } } - var view = m_dataGridControl.GetView(); - if( view == null ) - return new ObservableCollection(); - - return view.Headers; - } - } + internal void SetCurrentItemCore(object item, bool isCancelable, bool synchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers trigger) + { + this.SetCurrent(item, null, null, this.CurrentColumn, false, isCancelable, synchronizeSelectionWithCurrent, trigger); + } - #endregion + public int CurrentItemIndex + { + get + { + return m_currentItemIndex; + } + set + { + if (value == m_currentItemIndex) + return; - #region IsCurrent Read-Only Property + this.SetCurrentItemIndexCore(value, true, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.CurrentItemChanged); + } + } - public bool IsCurrent - { - get - { - return m_flags[ ( int )DataGridContextFlags.IsCurrent ]; - } - } + internal void SetCurrentItemIndexCore(int index, bool isCancelable, bool synchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers trigger) + { + this.SetCurrent(this.Items.GetItemAt(index), null, index, this.CurrentColumn, false, isCancelable, synchronizeSelectionWithCurrent, trigger); + } - internal void SetIsCurrent( bool value ) - { - m_flags[ ( int )DataGridContextFlags.IsCurrent ] = value; - } + private void SetCurrentItem(object dataItem, int sourceDataItemIndex) + { + // This is called only for DataItem + if ((m_currentItem == dataItem) && (m_currentItemIndex == sourceDataItemIndex)) + return; - #endregion + m_currentItem = dataItem; + m_currentItemIndex = sourceDataItemIndex; + this.OnCurrentItemChanged(); + } - #region ItemContainerStyle + internal event EventHandler CurrentItemChanged; - public Style ItemContainerStyle - { - get - { - if( m_detailConfig != null ) + private void OnCurrentItemChanged() { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.ItemContainerStyle; + var handler = this.CurrentItemChanged; + if (handler == null) + return; - return m_detailConfig.ItemContainerStyle; + handler.Invoke(this, EventArgs.Empty); } - return m_dataGridControl.ItemContainerStyle; - } - } + private object m_currentItem; // = null + private int m_currentItemIndex = -1; - #endregion + #endregion - #region ItemContainerStyleSelector + #region DefaultGroupConfiguration Read-Only Property - public StyleSelector ItemContainerStyleSelector - { - get - { - if( m_detailConfig != null ) + public GroupConfiguration DefaultGroupConfiguration { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.ItemContainerStyleSelector; + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.DefaultGroupConfiguration; + + return m_detailConfig.DefaultGroupConfiguration; + } - return m_detailConfig.ItemContainerStyleSelector; + return m_dataGridControl.DefaultGroupConfiguration; + } } - return m_dataGridControl.ItemContainerStyleSelector; - } - } + #endregion - #endregion + #region DetailConfigurations Read-Only Property - #region DataGridControl Read-Only Property + internal DetailConfigurationCollection DetailConfigurations + { + get + { + if (m_detailConfig != null) + return m_detailConfig.DetailConfigurations; - public DataGridControl DataGridControl - { - get - { - return m_dataGridControl; - } - } + return null; + } + } - private readonly DataGridControl m_dataGridControl; + #endregion - #endregion + #region Footers Read-Only Property - #region SelectedItems Read-Only Property + public ObservableCollection Footers + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.Footers; - public IList SelectedItems - { - get - { - return m_selectedItems; - } - } + return m_detailConfig.Footers; + } - private readonly SelectionItemCollection m_selectedItems; + var view = m_dataGridControl.GetView(); + if (view == null) + return new ObservableCollection(); - #endregion + return view.Footers; + } + } - #region SelectedItemRanges Read-Only Property + #endregion - public IList SelectedItemRanges - { - get - { - return m_selectedItemsRanges; - } - } + #region GroupLevelDescriptions Read-Only Property - private readonly SelectionItemRangeCollection m_selectedItemsRanges; + public GroupLevelDescriptionCollection GroupLevelDescriptions + { + get + { + if (m_detailConfig != null) + return m_detailConfig.GroupLevelDescriptions; - #endregion + return m_groupLevelDescriptions; + } + } - #region SelectedCellRanges Read-Only Property + private readonly GroupLevelDescriptionCollection m_groupLevelDescriptions; //null - public IList SelectedCellRanges - { - get - { - return m_selectedCellRanges; - } - } + #endregion - private readonly SelectionCellRangeCollection m_selectedCellRanges; + #region GroupConfigurationSelector Property - #endregion + public GroupConfigurationSelector GroupConfigurationSelector + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.GroupConfigurationSelector; - #region SourceDetailConfiguration Read-Only Property + return m_detailConfig.GroupConfigurationSelector; + } - internal DetailConfiguration SourceDetailConfiguration - { - get - { - return m_detailConfig; - } - } + return m_dataGridControl.GroupConfigurationSelector; + } + } - private readonly DetailConfiguration m_detailConfig; + private void OnGroupConfigurationSelectorChanged() + { + var handler = this.GroupConfigurationSelectorChanged; + if (handler == null) + return; - #endregion + handler.Invoke(this, EventArgs.Empty); + } - #region VisibleColumns Read-Only Property + internal event EventHandler GroupConfigurationSelectorChanged; - public ReadOnlyObservableCollection VisibleColumns - { - get - { - return m_columnManager.VisibleColumns; - } - } + #endregion - #endregion + #region HasDetails Read-Only Property - #region AutoCreateForeignKeyConfigurations Internal Property + public bool HasDetails + { + get + { + return false; + } + } - internal bool AutoCreateForeignKeyConfigurations - { - get - { - if( m_detailConfig != null ) - return m_detailConfig.AutoCreateForeignKeyConfigurations; + #endregion - return m_dataGridControl.AutoCreateForeignKeyConfigurations; - } - } + #region Headers Read-Only property - #endregion + public ObservableCollection Headers + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.Headers; - #region MaxSortLevels Property + return m_detailConfig.Headers; + } - public int MaxSortLevels - { - get - { - if( m_detailConfig != null ) - { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.MaxSortLevels; + var view = m_dataGridControl.GetView(); + if (view == null) + return new ObservableCollection(); - return m_detailConfig.MaxSortLevels; + return view.Headers; + } } - return m_dataGridControl.MaxSortLevels; - } - } - - #endregion + #endregion - #region MaxGroupLevels Property + #region IsCurrent Read-Only Property - public int MaxGroupLevels - { - get - { - if( m_detailConfig != null ) + public bool IsCurrent { - var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - return defaultDetailConfig.MaxGroupLevels; - - return m_detailConfig.MaxGroupLevels; + get + { + return m_flags[(int)DataGridContextFlags.IsCurrent]; + } } - return m_dataGridControl.MaxGroupLevels; - } - } - - #endregion + internal void SetIsCurrent(bool value) + { + m_flags[(int)DataGridContextFlags.IsCurrent] = value; + } - //--------- INTERNAL PROPERTIES --------- + #endregion - #region RootDataGridContext Read-Only Property + #region ItemContainerStyle - internal DataGridContext RootDataGridContext - { - get - { - return this.DataGridControl.DataGridContext; - } - } + public Style ItemContainerStyle + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.ItemContainerStyle; - #endregion + return m_detailConfig.ItemContainerStyle; + } - #region SelectedItemsStore Read-Only Property + return m_dataGridControl.ItemContainerStyle; + } + } - internal SelectedItemsStorage SelectedItemsStore - { - get - { - return m_selectedItemsStore; - } - } + #endregion - private readonly SelectedItemsStorage m_selectedItemsStore; + #region ItemContainerStyleSelector - #endregion + public StyleSelector ItemContainerStyleSelector + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.ItemContainerStyleSelector; - #region SelectedItemsStore Read-Only Property + return m_detailConfig.ItemContainerStyleSelector; + } - internal SelectedCellsStorage SelectedCellsStore - { - get - { - return m_selectedCellsStore; - } - } + return m_dataGridControl.ItemContainerStyleSelector; + } + } - private readonly SelectedCellsStorage m_selectedCellsStore; + #endregion - #endregion + #region DataGridControl Read-Only Property - #region ColumnsByVisiblePosition Read-Only Property + public DataGridControl DataGridControl + { + get + { + return m_dataGridControl; + } + } - internal HashedLinkedList ColumnsByVisiblePosition - { - get - { - return m_columnManager.ColumnsByVisiblePosition; - } - } + private readonly DataGridControl m_dataGridControl; - #endregion + #endregion - #region ColumnStretchingManager Property + #region SelectedItems Read-Only Property - internal ColumnStretchingManager ColumnStretchingManager - { - get - { - if( m_columnStretchingManager == null ) + public IList SelectedItems { - m_columnStretchingManager = new ColumnStretchingManager( this ); + get + { + return m_selectedItems; + } } - return m_columnStretchingManager; - } - } - - private ColumnStretchingManager m_columnStretchingManager; - - #endregion - - #region CurrentCell Read-Only Property - - internal Cell CurrentCell - { - get - { - var currentRow = this.CurrentRow; - if( currentRow == null ) - return null; - - return currentRow.Cells[ this.CurrentColumn ]; - } - } + private readonly SelectionItemCollection m_selectedItems; - #endregion + #endregion - #region CurrentRow Read-Only Property + #region SelectedItemRanges Read-Only Property - internal Row CurrentRow - { - get - { - if( this.InternalCurrentItem == null ) - return null; + public IList SelectedItemRanges + { + get + { + return m_selectedItemsRanges; + } + } - return Row.FromContainer( this.GetContainerFromItem( this.InternalCurrentItem ) ); - } - } + private readonly SelectionItemRangeCollection m_selectedItemsRanges; - #endregion + #endregion - #region CustomItemContainerGenerator Read-Only Property + #region SelectedCellRanges Read-Only Property - internal CustomItemContainerGenerator CustomItemContainerGenerator - { - get - { - return m_generator; - } - } + public IList SelectedCellRanges + { + get + { + return m_selectedCellRanges; + } + } - internal void SetGenerator( CustomItemContainerGenerator generator ) - { - if( m_generator != null ) - throw new InvalidOperationException( "An attempt was made to reset the generator after it has already been set." ); + private readonly SelectionCellRangeCollection m_selectedCellRanges; - if( generator == null ) - throw new ArgumentNullException( "generator" ); + #endregion - m_generator = generator; - } + #region SourceDetailConfiguration Read-Only Property - private CustomItemContainerGenerator m_generator; + internal DetailConfiguration SourceDetailConfiguration + { + get + { + return m_detailConfig; + } + } - #endregion + private readonly DetailConfiguration m_detailConfig; - #region InternalCurrentItem Read-Only Property + #endregion - internal object InternalCurrentItem - { - get - { - return m_internalCurrentItem; - } - } + #region VisibleColumns Read-Only Property - private void SetInternalCurrentItem( object value ) - { - m_internalCurrentItem = value; - } + public ReadOnlyObservableCollection VisibleColumns + { + get + { + return m_columnManager.VisibleColumns; + } + } - private object m_internalCurrentItem; //null + #endregion - #endregion + #region AutoCreateForeignKeyConfigurations Internal Property - #region ItemsSourcePropertyDescriptions Property + internal bool AutoCreateForeignKeyConfigurations + { + get + { + if (m_detailConfig != null) + return m_detailConfig.AutoCreateForeignKeyConfigurations; - internal PropertyDescriptionRouteDictionary ItemsSourcePropertyDescriptions - { - get - { - return m_itemsSourcePropertyDescriptions; - } - } + return m_dataGridControl.AutoCreateForeignKeyConfigurations; + } + } - private readonly PropertyDescriptionRouteDictionary m_itemsSourcePropertyDescriptions; + #endregion - #endregion + #region MaxSortLevels Property - #region ItemPropertyMap Internal Property + public int MaxSortLevels + { + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.MaxSortLevels; - internal DataGridItemPropertyMap ItemPropertyMap - { - get - { - return m_itemPropertyMap; - } - } + return m_detailConfig.MaxSortLevels; + } - private readonly DataGridItemPropertyMap m_itemPropertyMap; + return m_dataGridControl.MaxSortLevels; + } + } - #endregion + #endregion - #region ToggleColumnSortCommand Internal Property + #region MaxGroupLevels Property - internal ToggleColumnSortCommand ToggleColumnSortCommand - { - get - { - if( m_toggleColumnSortCommand == null ) + public int MaxGroupLevels { - m_toggleColumnSortCommand = new DataGridContextToggleColumnSortCommand( this ); - } + get + { + if (m_detailConfig != null) + { + var defaultDetailConfig = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + return defaultDetailConfig.MaxGroupLevels; - Debug.Assert( m_toggleColumnSortCommand != null ); + return m_detailConfig.MaxGroupLevels; + } - return m_toggleColumnSortCommand; - } - } + return m_dataGridControl.MaxGroupLevels; + } + } - private ToggleColumnSortCommand m_toggleColumnSortCommand; + #endregion - #endregion + //--------- INTERNAL PROPERTIES --------- - #region UpdateColumnSortCommand Internal Property + #region RootDataGridContext Read-Only Property - internal UpdateColumnSortCommand UpdateColumnSortCommand - { - get - { - if( m_updateColumnSortCommand == null ) + internal DataGridContext RootDataGridContext { - m_updateColumnSortCommand = new DataGridContextUpdateColumnSortCommand( this ); + get + { + return this.DataGridControl.DataGridContext; + } } - Debug.Assert( m_updateColumnSortCommand != null ); + #endregion - return m_updateColumnSortCommand; - } - } + #region SelectedItemsStore Read-Only Property + + internal SelectedItemsStorage SelectedItemsStore + { + get + { + return m_selectedItemsStore; + } + } - private UpdateColumnSortCommand m_updateColumnSortCommand; + private readonly SelectedItemsStorage m_selectedItemsStore; - #endregion + #endregion - #region AddGroupCommand Internal Property + #region SelectedItemsStore Read-Only Property - internal ColumnAddGroupCommand AddGroupCommand - { - get - { - if( m_addGroupCommand == null ) + internal SelectedCellsStorage SelectedCellsStore { - m_addGroupCommand = new DataGridContextAddGroupCommand( this ); + get + { + return m_selectedCellsStore; + } } - Debug.Assert( m_addGroupCommand != null ); - - return m_addGroupCommand; - } - } - - private ColumnAddGroupCommand m_addGroupCommand; + private readonly SelectedCellsStorage m_selectedCellsStore; - #endregion + #endregion - #region SortDescriptionsSyncContext Read-Only Property + #region ColumnsByVisiblePosition Read-Only Property - internal SortDescriptionsSyncContext SortDescriptionsSyncContext - { - get - { - var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - return dataGridCollectionViewBase.DataGridSortDescriptions.SyncContext; - - Debug.Assert( m_sortDescriptionsSyncContext != null ); - return m_sortDescriptionsSyncContext; - } - } + internal HashedLinkedList ColumnsByVisiblePosition + { + get + { + return m_columnManager.ColumnsByVisiblePosition; + } + } - private readonly SortDescriptionsSyncContext m_sortDescriptionsSyncContext; //null + #endregion - #endregion + #region ColumnStretchingManager Property - #region DefaultDetailConfiguration Property + internal ColumnStretchingManager ColumnStretchingManager + { + get + { + if (m_columnStretchingManager == null) + { + m_columnStretchingManager = new ColumnStretchingManager(this); + } - internal DefaultDetailConfiguration DefaultDetailConfiguration - { - get - { - if( m_detailConfig != null ) - return m_detailConfig.DefaultDetailConfiguration; + return m_columnStretchingManager; + } + } - return m_dataGridControl.DefaultDetailConfiguration; - } - } + private ColumnStretchingManager m_columnStretchingManager; - #endregion + #endregion - #region ColumnVirtualizationManager Property + #region CurrentCell Read-Only Property - internal ColumnVirtualizationManager ColumnVirtualizationManager - { - get - { - var columnVirtualizationManager = this.GetColumnVirtualizationManagerOrNull(); - if( columnVirtualizationManager == null ) + internal Cell CurrentCell { - columnVirtualizationManager = this.DataGridControl.GetView().CreateColumnVirtualizationManager( this ); + get + { + var currentRow = this.CurrentRow; + if (currentRow == null) + return null; + + return currentRow.Cells[this.CurrentColumn]; + } } - // We must ensure the manager is up to date before using it - columnVirtualizationManager.Update(); + #endregion - return columnVirtualizationManager; - } - } + #region CurrentRow Read-Only Property - internal ColumnVirtualizationManager GetColumnVirtualizationManagerOrNull() - { - return ColumnVirtualizationManager.GetColumnVirtualizationManager( this ); - } + internal Row CurrentRow + { + get + { + if (this.InternalCurrentItem == null) + return null; - #endregion + return Row.FromContainer(this.GetContainerFromItem(this.InternalCurrentItem)); + } + } - #region ColumnManagerRowConfiguration Read-Only Internal Property + #endregion - internal ColumnManagerRowConfiguration ColumnManagerRowConfiguration - { - get - { - if( m_detailConfig != null ) - return m_detailConfig.ColumnManagerRowConfiguration; + #region CustomItemContainerGenerator Read-Only Property - return this.DataGridControl.ColumnManagerRowConfiguration; - } - } + internal CustomItemContainerGenerator CustomItemContainerGenerator + { + get + { + return m_generator; + } + } - #endregion + internal void SetGenerator(CustomItemContainerGenerator generator) + { + if (m_generator != null) + throw new InvalidOperationException("An attempt was made to reset the generator after it has already been set."); - #region FixedHeaderFooterViewPortSize Property + if (generator == null) + throw new ArgumentNullException("generator"); - internal Size FixedHeaderFooterViewPortSize - { - get - { - return m_fixedHeaderFooterViewPortSize; - } - set - { - if( Size.Equals( value, m_fixedHeaderFooterViewPortSize ) ) - return; - - m_fixedHeaderFooterViewPortSize = value; - - this.OnPropertyChanged( "FixedHeaderFooterViewPortSize" ); - } - } + m_generator = generator; + } - private Size m_fixedHeaderFooterViewPortSize = new Size(); + private CustomItemContainerGenerator m_generator; - #endregion + #endregion - #region IsDeleteCommandEnabled Property + #region InternalCurrentItem Read-Only Property - internal bool IsDeleteCommandEnabled - { - get - { - return this.FindIsDeletedCommandEnabledAmbient( this ); - } - } + internal object InternalCurrentItem + { + get + { + return m_internalCurrentItem; + } + } - private bool FindIsDeletedCommandEnabledAmbient( DataGridContext dataGridContext ) - { - if( dataGridContext == null ) - return false; - - if( dataGridContext.SourceDetailConfiguration == null ) - { - if( dataGridContext.DataGridControl == null ) - return false; - - return dataGridContext.DataGridControl.IsDeleteCommandEnabled; - } - - var defaultDetailConfig = dataGridContext.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfig != null ) - { - if( defaultDetailConfig.ReadLocalValue( DefaultDetailConfiguration.IsDeleteCommandEnabledProperty ) != DependencyProperty.UnsetValue ) - return defaultDetailConfig.IsDeleteCommandEnabled; - } - else - { - if( dataGridContext.SourceDetailConfiguration.ReadLocalValue( DetailConfiguration.IsDeleteCommandEnabledProperty ) != DependencyProperty.UnsetValue ) - return dataGridContext.SourceDetailConfiguration.IsDeleteCommandEnabled; - } - - return this.FindIsDeletedCommandEnabledAmbient( dataGridContext.ParentDataGridContext ); - } + private void SetInternalCurrentItem(object value) + { + m_internalCurrentItem = value; + } - #endregion + private object m_internalCurrentItem; //null - #region SelectionChanged Event + #endregion - internal event EventHandler SelectionChangedInternal; + #region ItemsSourcePropertyDescriptions Property - internal void InvokeSelectionChanged( SelectionInfo selectionInfo ) - { + internal PropertyDescriptionRouteDictionary ItemsSourcePropertyDescriptions + { + get + { + return m_itemsSourcePropertyDescriptions; + } + } - if( this.SelectionChangedInternal != null ) - { - this.SelectionChangedInternal( this, new SelectionChangedInternalEventArgs( selectionInfo ) ); - } + private readonly PropertyDescriptionRouteDictionary m_itemsSourcePropertyDescriptions; - Debug.Assert( selectionInfo.DataGridContext == this ); + #endregion - if( ( selectionInfo.RemovedItems.Count == 0 ) && ( selectionInfo.AddedItems.Count == 0 ) ) - return; + #region ItemPropertyMap Internal Property - } + internal DataGridItemPropertyMap ItemPropertyMap + { + get + { + return m_itemPropertyMap; + } + } - #endregion + private readonly DataGridItemPropertyMap m_itemPropertyMap; - #region DetailLevel Property + #endregion - // Represents the detail level from the master item - internal int DetailLevel - { - get; - private set; - } + #region ToggleColumnSortCommand Internal Property - #endregion + internal ToggleColumnSortCommand ToggleColumnSortCommand + { + get + { + if (m_toggleColumnSortCommand == null) + { + m_toggleColumnSortCommand = new DataGridContextToggleColumnSortCommand(this); + } - #region IsSavingState Property + Debug.Assert(m_toggleColumnSortCommand != null); - internal bool IsSavingState - { - get - { - return m_flags[ ( int )DataGridContextFlags.IsSavingState ]; - } - set - { - m_flags[ ( int )DataGridContextFlags.IsSavingState ] = value; - } - } + return m_toggleColumnSortCommand; + } + } - #endregion + private ToggleColumnSortCommand m_toggleColumnSortCommand; - #region IsRestoringState Property + #endregion - internal bool IsRestoringState - { - get - { - return m_flags[ ( int )DataGridContextFlags.IsRestoringState ]; - } - set - { - m_flags[ ( int )DataGridContextFlags.IsRestoringState ] = value; - } - } + #region UpdateColumnSortCommand Internal Property - #endregion + internal UpdateColumnSortCommand UpdateColumnSortCommand + { + get + { + if (m_updateColumnSortCommand == null) + { + m_updateColumnSortCommand = new DataGridContextUpdateColumnSortCommand(this); + } - #region IsDeferRestoringState Internal Property + Debug.Assert(m_updateColumnSortCommand != null); - internal bool IsDeferRestoringState - { - get - { - return ( m_deferRestoreStateCount > 0 ); - } - } + return m_updateColumnSortCommand; + } + } - #endregion + private UpdateColumnSortCommand m_updateColumnSortCommand; - #region IsAFlattenDetail Internal Property + #endregion - internal bool IsAFlattenDetail - { - get - { - return ( m_detailConfig != null ) - && ( this.AreDetailsFlatten ); - } - } + #region AddGroupCommand Internal Property - #endregion + internal ColumnAddGroupCommand AddGroupCommand + { + get + { + if (m_addGroupCommand == null) + { + m_addGroupCommand = new DataGridContextAddGroupCommand(this); + } - #region AreDetailsFlatten Internal Property + Debug.Assert(m_addGroupCommand != null); - internal bool AreDetailsFlatten - { - get - { - return this.DataGridControl.AreDetailsFlatten; - } - } + return m_addGroupCommand; + } + } - #endregion + private ColumnAddGroupCommand m_addGroupCommand; - #region AlreadySearchedForDefaultDetailConfig Private Property + #endregion - private bool AlreadySearchedForDefaultDetailConfig - { - get - { - return m_flags[ ( int )DataGridContextFlags.AlreadySearchedForDetailConfig ]; - } - set - { - m_flags[ ( int )DataGridContextFlags.AlreadySearchedForDetailConfig ] = value; - } - } + #region SortDescriptionsSyncContext Read-Only Property - #endregion + internal SortDescriptionsSyncContext SortDescriptionsSyncContext + { + get + { + var dataGridCollectionViewBase = this.ItemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + return dataGridCollectionViewBase.DataGridSortDescriptions.SyncContext; - #region DefaultImageColumnDetermined Private Property + Debug.Assert(m_sortDescriptionsSyncContext != null); + return m_sortDescriptionsSyncContext; + } + } - private bool DefaultImageColumnDetermined - { - get - { - return m_flags[ ( int )DataGridContextFlags.DefaultImageColumnDetermined ]; - } - set - { - m_flags[ ( int )DataGridContextFlags.DefaultImageColumnDetermined ] = value; - } - } + private readonly SortDescriptionsSyncContext m_sortDescriptionsSyncContext; //null - #endregion + #endregion - #region ColumnManager Internal Property + #region DefaultDetailConfiguration Property - internal ColumnHierarchyManager ColumnManager - { - get - { - return m_columnManager; - } - } + internal DefaultDetailConfiguration DefaultDetailConfiguration + { + get + { + if (m_detailConfig != null) + return m_detailConfig.DefaultDetailConfiguration; - private readonly ColumnHierarchyManager m_columnManager; + return m_dataGridControl.DefaultDetailConfiguration; + } + } - #endregion + #endregion - #region CanIncreaseColumnWidth Property + #region ColumnVirtualizationManager Property - internal bool CanIncreaseColumnWidth - { - get - { - return m_canIncreaseColumnWidth; - } - set - { - m_canIncreaseColumnWidth = value; - } - } + internal ColumnVirtualizationManager ColumnVirtualizationManager + { + get + { + var columnVirtualizationManager = this.GetColumnVirtualizationManagerOrNull(); + if (columnVirtualizationManager == null) + { + columnVirtualizationManager = this.DataGridControl.GetView().CreateColumnVirtualizationManager(this); + } - private bool m_canIncreaseColumnWidth = true; + // We must ensure the manager is up to date before using it + columnVirtualizationManager.Update(); - #endregion + return columnVirtualizationManager; + } + } - internal void SetCurrentColumnAndChangeSelection( ColumnBase newCurrentColumn ) - { - // Since SetCurrentColumnCore can be aborted, we do it before changing the selection. - this.SetCurrentColumnCore( newCurrentColumn, true, false, AutoScrollCurrentItemSourceTriggers.Navigation ); + internal ColumnVirtualizationManager GetColumnVirtualizationManagerOrNull() + { + return ColumnVirtualizationManager.GetColumnVirtualizationManager(this); + } - if( m_dataGridControl != null ) - { - Row row = this.CurrentRow; - object item = this.InternalCurrentItem; + #endregion - int dataRowIndex; - bool rowIsBeingEdited; + #region ColumnManagerRowConfiguration Read-Only Internal Property - if( row == null ) - { - dataRowIndex = -1; - rowIsBeingEdited = false; - } - else + internal ColumnManagerRowConfiguration ColumnManagerRowConfiguration { - dataRowIndex = DataGridVirtualizingPanel.GetItemIndex( row ); - rowIsBeingEdited = row.IsBeingEdited; + get + { + if (m_detailConfig != null) + return m_detailConfig.ColumnManagerRowConfiguration; + + return this.DataGridControl.ColumnManagerRowConfiguration; + } } - var oldPosition = SelectionRangePoint.TryCreateFromCurrent( this ); - var newPosition = SelectionRangePoint.TryCreateRangePoint( this, item, dataRowIndex, newCurrentColumn.VisiblePosition ); + #endregion - m_dataGridControl.SelectionChangerManager.UpdateSelection( oldPosition, newPosition, true, rowIsBeingEdited, SelectionManager.UpdateSelectionSource.Navigation ); - } - } + #region FixedHeaderFooterViewPortSize Property - //---------- PUBLIC METHODS ---------- + internal Size FixedHeaderFooterViewPortSize + { + get + { + return m_fixedHeaderFooterViewPortSize; + } + set + { + if (Size.Equals(value, m_fixedHeaderFooterViewPortSize)) + return; - public void BeginEdit() - { - this.BeginEdit( this.InternalCurrentItem ); - } + m_fixedHeaderFooterViewPortSize = value; - public void BeginEdit( object item ) - { - DataGridControl.BeginEditHelper( this, item ); - } + this.OnPropertyChanged("FixedHeaderFooterViewPortSize"); + } + } - public void EndEdit() - { - DataGridControl.EndEditHelper( this ); - } + private Size m_fixedHeaderFooterViewPortSize = new Size(); - public void CancelEdit() - { - DataGridControl.CancelEditHelper( this ); - } + #endregion - internal bool IsContainingItem( object item ) - { - DataTemplate itemTemplate = item as DataTemplate; + #region IsDeleteCommandEnabled Property - if( ( this.ParentItem == null ) && ( itemTemplate != null ) ) - { - if( m_dataGridControl.View.FixedHeaders.Contains( itemTemplate ) - || m_dataGridControl.View.FixedFooters.Contains( itemTemplate ) ) + internal bool IsDeleteCommandEnabled { - return true; + get + { + return this.FindIsDeletedCommandEnabledAmbient(this); + } } - } - - return m_generator.Contains( item ); - } - public bool IsGroupExpanded( CollectionViewGroup group ) - { - return ( this.CustomItemContainerGenerator.IsGroupExpanded( group ) == true ); - } - - internal bool? IsGroupExpanded( CollectionViewGroup group, bool recurseDetails ) - { - return this.CustomItemContainerGenerator.IsGroupExpanded( group, recurseDetails ); - } + private bool FindIsDeletedCommandEnabledAmbient(DataGridContext dataGridContext) + { + if (dataGridContext == null) + return false; - public bool ToggleGroupExpansion( CollectionViewGroup group ) - { - return this.CustomItemContainerGenerator.ToggleGroupExpansion( group ); - } + if (dataGridContext.SourceDetailConfiguration == null) + { + if (dataGridContext.DataGridControl == null) + return false; - public bool ExpandGroup( CollectionViewGroup group ) - { - return this.CustomItemContainerGenerator.ExpandGroup( group ); - } + return dataGridContext.DataGridControl.IsDeleteCommandEnabled; + } - internal bool ExpandGroup( CollectionViewGroup group, bool recurseDetails ) - { - return this.CustomItemContainerGenerator.ExpandGroup( group, recurseDetails ); - } + var defaultDetailConfig = dataGridContext.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfig != null) + { + if (defaultDetailConfig.ReadLocalValue(DefaultDetailConfiguration.IsDeleteCommandEnabledProperty) != DependencyProperty.UnsetValue) + return defaultDetailConfig.IsDeleteCommandEnabled; + } + else + { + if (dataGridContext.SourceDetailConfiguration.ReadLocalValue(DetailConfiguration.IsDeleteCommandEnabledProperty) != DependencyProperty.UnsetValue) + return dataGridContext.SourceDetailConfiguration.IsDeleteCommandEnabled; + } - public bool CollapseGroup( CollectionViewGroup group ) - { - return this.CustomItemContainerGenerator.CollapseGroup( group ); - } + return this.FindIsDeletedCommandEnabledAmbient(dataGridContext.ParentDataGridContext); + } - internal bool CollapseGroup( CollectionViewGroup group, bool recurseDetails ) - { - return this.CustomItemContainerGenerator.CollapseGroup( group, recurseDetails ); - } + #endregion - public bool AreDetailsExpanded( object dataItem ) - { - return this.CustomItemContainerGenerator.AreDetailsExpanded( dataItem ); - } + #region SelectionChanged Event - public Group GetGroupFromCollectionViewGroup( CollectionViewGroup collectionViewGroup ) - { - if( collectionViewGroup == null ) - return null; + internal event EventHandler SelectionChangedInternal; - Group group = this.CustomItemContainerGenerator.GetGroupFromCollectionViewGroup( collectionViewGroup ); + internal void InvokeSelectionChanged(SelectionInfo selectionInfo) + { - return group; - } + if (this.SelectionChangedInternal != null) + { + this.SelectionChangedInternal(this, new SelectionChangedInternalEventArgs(selectionInfo)); + } - public DependencyObject GetContainerFromItem( object item ) - { - if( item == null ) - return null; + Debug.Assert(selectionInfo.DataGridContext == this); - var container = default( DependencyObject ); + if ((selectionInfo.RemovedItems.Count == 0) && (selectionInfo.AddedItems.Count == 0)) + return; - if( ( m_detailConfig == null ) && ( item is DataTemplate ) ) - { - //If the container was not found in the DataGridContext's Generator and the DataGridContext does not have a source DetailConfig ( master context ) - //then check in the DataGridControl's Fixed Items - container = m_dataGridControl.GetContainerForFixedItem( item ); - } + } - if( container == null ) - { - container = this.CustomItemContainerGenerator.ContainerFromItem( item ); - } + #endregion - return container; - } + #region DetailLevel Property - public object GetItemFromContainer( DependencyObject container ) - { - object item = null; + // Represents the detail level from the master item + internal int DetailLevel + { + get; + private set; + } - if( m_detailConfig == null ) - { - //If the item was not found in the DataGridContext's Generator and the DataGridContext does not have a source DetailConfig ( master context ) - //then check in the DataGridControl's Fixed Items - item = DataGridControl.GetFixedItemFromContainer( container ); - } + #endregion - if( item == null ) - { - item = this.CustomItemContainerGenerator.ItemFromContainer( container ); - } + #region IsSavingState Property - return item; - } + internal bool IsSavingState + { + get + { + return m_flags[(int)DataGridContextFlags.IsSavingState]; + } + set + { + m_flags[(int)DataGridContextFlags.IsSavingState] = value; + } + } - [EditorBrowsable( EditorBrowsableState.Never )] - public DependencyObject GetContainerFromIndex( int index ) - { - return this.CustomItemContainerGenerator.GetRealizedContainerForIndex( index ); - } + #endregion - [EditorBrowsable( EditorBrowsableState.Never )] - public int GetIndexFromContainer( DependencyObject container ) - { - return this.CustomItemContainerGenerator.GetRealizedIndexForContainer( container ); - } + #region IsRestoringState Property - public CollectionViewGroup GetParentGroupFromItem( object item ) - { - return this.GetParentGroupFromItemCore( item, false ); - } - - internal CollectionViewGroup GetParentGroupFromItemCore( object item, bool recurseDetails ) - { - CollectionViewGroup retval = null; - - DataTemplate dataTemplate = item as DataTemplate; - - //For the master level, before interrogating the Generator, I need to check for the items presence in the Fixed regions. - if( ( m_detailConfig == null ) && ( dataTemplate != null ) ) - { - Views.ViewBase view = m_dataGridControl.GetView(); - - //Fixed header cannot have a Parent Group. - if( view.FixedHeaders.Contains( dataTemplate ) == true ) - return null; - - //Fixed header cannot have a Parent Group. - if( view.FixedFooters.Contains( dataTemplate ) == true ) - return null; - } - - if( this.CustomItemContainerGenerator.IsInUse == true ) - { - retval = this.CustomItemContainerGenerator.GetParentGroupFromItem( item, recurseDetails ); - } - - return retval; - } - - internal DataGridContext GetChildContext( object parentItem, DetailConfiguration detailConfiguration ) - { - if( detailConfiguration == null ) - throw new ArgumentNullException( "detailConfiguration" ); - - return this.GetChildContext( parentItem, detailConfiguration.RelationName ); - } - - public DataGridContext GetChildContext( object parentItem, string relationName ) - { - return this.CustomItemContainerGenerator.GetChildContext( parentItem, relationName ); - } - - [System.Diagnostics.CodeAnalysis.SuppressMessage( "Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate" )] - public IEnumerable GetChildContexts() - { - return this.CustomItemContainerGenerator.GetChildContexts(); - } - - internal IEnumerable GetChildContextsCore() - { - return this.CustomItemContainerGenerator.GetChildContextsCore(); - } - - internal BindingPathValueExtractor GetBindingPathExtractorForColumn( Column column, object dataItem ) - { - if( column == null ) - throw new ArgumentNullException( "column" ); - - if( dataItem == null ) - return null; - - if( column == null ) - throw new ArgumentNullException( "column" ); - - var xPath = default( string ); - var propertyPath = default( PropertyPath ); - - // Disable warning for DisplayMemberBinding when internaly used -#pragma warning disable 618 - var displayMemberBinding = column.DisplayMemberBinding as Binding; -#pragma warning restore 618 - - if( displayMemberBinding == null ) - { - displayMemberBinding = ItemsSourceHelper.CreateDefaultBinding( - ItemsSourceHelper.CreateOrGetPropertyDescriptionFromColumn( this, column, dataItem.GetType() ) ); - } - - if( displayMemberBinding == null ) - throw new DataGridInternalException( "DisplayMemberBinding is null.", m_dataGridControl ); - - xPath = displayMemberBinding.XPath; - propertyPath = displayMemberBinding.Path; - - var converter = new Xceed.Wpf.DataGrid.Converters.SourceDataConverter( ItemsSourceHelper.IsItemSupportingDBNull( dataItem ), CultureInfo.InvariantCulture ); - - return new BindingPathValueExtractor( xPath, propertyPath, false, typeof( object ), converter, null, CultureInfo.InvariantCulture ); - } - - public IDisposable DeferColumnsUpdate() - { - return ColumnHierarchyManagerHelper.DeferColumnsUpdate( this ); - } + internal bool IsRestoringState + { + get + { + return m_flags[(int)DataGridContextFlags.IsRestoringState]; + } + set + { + m_flags[(int)DataGridContextFlags.IsRestoringState] = value; + } + } - public bool MoveColumnBefore( ColumnBase current, ColumnBase next ) - { - return ColumnHierarchyManagerHelper.MoveColumnBefore( this, current, next ); - } + #endregion - public bool MoveColumnAfter( ColumnBase current, ColumnBase previous ) - { - return ColumnHierarchyManagerHelper.MoveColumnAfter( this, current, previous ); - } + #region IsDeferRestoringState Internal Property - public bool MoveColumnUnder( ColumnBase current, ColumnBase parent ) - { - return ColumnHierarchyManagerHelper.MoveColumnUnder( this, current, parent ); - } + internal bool IsDeferRestoringState + { + get + { + return (m_deferRestoreStateCount > 0); + } + } - //---------- INTERNAL METHODS ----------- + #endregion - internal IDisposable DeferRestoreState() - { - return new DeferRestoreStateDisposable( this ); - } + #region IsAFlattenDetail Internal Property - internal void UpdatePublicSelectionProperties() - { - if( ( m_selectedItemsStore.Count > 0 ) || ( m_selectedCellsStore.Count > 0 ) ) - { - m_dataGridControl.AddToSelectedContexts( this ); - } - else - { - m_dataGridControl.RemoveFromSelectedContexts( this ); - } + internal bool IsAFlattenDetail + { + get + { + return (m_detailConfig != null) + && (this.AreDetailsFlatten); + } + } + #endregion - if( m_parentItem == null ) - { - // We are the root context ( GridControl ) - int newSelectedItemIndex; - object newSelectedItem; - int newSelectedColumnIndex; - this.GetFirstSelectedItemFromStore( false, out newSelectedItemIndex, out newSelectedItem, out newSelectedColumnIndex ); + #region AreDetailsFlatten Internal Property - if( m_dataGridControl.SelectedIndex != newSelectedItemIndex ) + internal bool AreDetailsFlatten { - m_dataGridControl.SelectedIndex = newSelectedItemIndex; + get + { + return this.DataGridControl.AreDetailsFlatten; + } } - // Calculate the new SelectedItem - if( !object.Equals( m_dataGridControl.SelectedItem, newSelectedItem ) ) - { - m_dataGridControl.SetSkipCoerceSelectedItemCheck( true ); - - try - { - m_dataGridControl.SelectedItem = newSelectedItem; - } - finally - { - m_dataGridControl.SetSkipCoerceSelectedItemCheck( false ); - } - } - } - } + #endregion - internal void GetFirstSelectedItemFromStore( bool checkCellsStore, out int selectedItemIndex, out object selectedItem, out int selectedColumnIndex ) - { - var newSelectedRangeWithItems = ( m_selectedItemsStore.Count == 0 ) ? SelectionRangeWithItems.Empty : m_selectedItemsStore[ 0 ]; + #region AlreadySearchedForDefaultDetailConfig Private Property - try - { - if( newSelectedRangeWithItems.IsEmpty ) + private bool AlreadySearchedForDefaultDetailConfig { - if( checkCellsStore ) - { - var newSelectionCellRangeWithItems = ( m_selectedCellsStore.Count == 0 ) ? SelectionCellRangeWithItems.Empty : m_selectedCellsStore[ 0 ]; - - if( newSelectionCellRangeWithItems.ItemRange.IsEmpty ) + get { - selectedColumnIndex = -1; - selectedItemIndex = -1; - selectedItem = null; + return m_flags[(int)DataGridContextFlags.AlreadySearchedForDetailConfig]; } - else + set { - selectedColumnIndex = newSelectionCellRangeWithItems.ColumnRange.StartIndex; - selectedItemIndex = newSelectionCellRangeWithItems.ItemRange.StartIndex; - selectedItem = newSelectionCellRangeWithItems.ItemRangeWithItems.GetItem( this, 0 ); - } - } - else - { - selectedColumnIndex = -1; - selectedItemIndex = -1; - selectedItem = null; - } - } - else - { - selectedColumnIndex = -1; - selectedItemIndex = newSelectedRangeWithItems.Range.StartIndex; - selectedItem = newSelectedRangeWithItems.GetItem( this, 0 ); - } - } - catch( ArgumentOutOfRangeException ) - { - selectedColumnIndex = -1; - selectedItemIndex = -1; - selectedItem = null; - } - } - - internal ColumnBase GetMatchingColumn( DataGridContext sourceContext, ColumnBase sourceColumn ) - { - if( ( sourceContext == null ) || ( sourceColumn == null ) ) - return null; - - if( sourceContext == this ) - return sourceColumn; + m_flags[(int)DataGridContextFlags.AlreadySearchedForDetailConfig] = value; + } + } - var collectionView = sourceContext.ItemsSourceCollection as DataGridCollectionViewBase; - if( collectionView == null ) - return null; + #endregion - var sourceItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( collectionView.ItemProperties, sourceColumn.FieldName ); - if( sourceItemProperty == null ) - return null; + #region DefaultImageColumnDetermined Private Property - var masterContext = sourceContext.RootDataGridContext; - var masterItemProperty = sourceItemProperty; + private bool DefaultImageColumnDetermined + { + get + { + return m_flags[(int)DataGridContextFlags.DefaultImageColumnDetermined]; + } + set + { + m_flags[(int)DataGridContextFlags.DefaultImageColumnDetermined] = value; + } + } - if( masterContext != sourceContext ) - { - if( !sourceContext.ItemPropertyMap.TryGetMasterItemProperty( sourceItemProperty, out masterItemProperty ) ) - return null; - } + #endregion - Debug.Assert( masterItemProperty != null ); - if( masterItemProperty == null ) - return null; + #region ColumnManager Internal Property - var currentItemProperty = masterItemProperty; - if( masterContext != this ) - { - if( !this.ItemPropertyMap.TryGetDetailItemProperty( masterItemProperty, out currentItemProperty ) ) - return null; - } + internal ColumnHierarchyManager ColumnManager + { + get + { + return m_columnManager; + } + } - Debug.Assert( currentItemProperty != null ); - if( currentItemProperty == null ) - return null; + private readonly ColumnHierarchyManager m_columnManager; - var columnName = PropertyRouteParser.Parse( currentItemProperty ); - if( string.IsNullOrEmpty( columnName ) ) - return null; + #endregion - return this.Columns[ columnName ]; - } + #region CanIncreaseColumnWidth Property - internal ColumnBase GetDefaultImageColumn() - { - if( !this.DefaultImageColumnDetermined ) - { - if( this.Items.Count > 0 ) + internal bool CanIncreaseColumnWidth { - this.DefaultImageColumnDetermined = true; - - var dataItem = this.Items.GetItemAt( 0 ); + get + { + return m_canIncreaseColumnWidth; + } + set + { + m_canIncreaseColumnWidth = value; + } + } - foreach( var column in this.VisibleColumns ) - { - var key = PropertyRouteParser.Parse( column.FieldName ); - if( key == null ) - continue; + private bool m_canIncreaseColumnWidth = true; - var propertyDescriptionRoute = default( PropertyDescriptionRoute ); - if( !m_itemsSourcePropertyDescriptions.TryGetValue( key, out propertyDescriptionRoute ) ) - continue; + #endregion - var propertyDescription = propertyDescriptionRoute.Current; - var dataType = propertyDescription.DataType; + internal void SetCurrentColumnAndChangeSelection(ColumnBase newCurrentColumn) + { + // Since SetCurrentColumnCore can be aborted, we do it before changing the selection. + this.SetCurrentColumnCore(newCurrentColumn, true, false, AutoScrollCurrentItemSourceTriggers.Navigation); - if( typeof( ImageSource ).IsAssignableFrom( dataType ) ) - { - m_defaultImageColumn = column; - break; - } - else if( ( typeof( byte[] ).IsAssignableFrom( dataType ) ) || - ( typeof( System.Drawing.Image ).IsAssignableFrom( dataType ) ) ) + if (m_dataGridControl != null) { - var converter = new Xceed.Wpf.DataGrid.Converters.ImageConverter(); - var convertedValue = default( object ); - var rawValue = default( object ); + Row row = this.CurrentRow; + object item = this.InternalCurrentItem; - try - { - if( propertyDescription.PropertyDescriptor == null ) + int dataRowIndex; + bool rowIsBeingEdited; + + if (row == null) { - var dataRow = dataItem as System.Data.DataRow; - if( dataRow == null ) - { - var dataRowView = dataItem as System.Data.DataRowView; - if( dataRowView != null ) - { - rawValue = dataRowView[ propertyDescription.Name ]; - } - } - else - { - rawValue = dataRow[ propertyDescription.Name ]; - } + dataRowIndex = -1; + rowIsBeingEdited = false; } else { - rawValue = propertyDescription.PropertyDescriptor.GetValue( dataItem ); + dataRowIndex = DataGridVirtualizingPanel.GetItemIndex(row); + rowIsBeingEdited = row.IsBeingEdited; } - if( rawValue != null ) - { - convertedValue = converter.Convert( rawValue, typeof( ImageSource ), null, CultureInfo.CurrentCulture ); - } - } - catch( NotSupportedException ) - { - //suppress the exception, the byte[] is not an image. convertedValue will remain null - } + var oldPosition = SelectionRangePoint.TryCreateFromCurrent(this); + var newPosition = SelectionRangePoint.TryCreateRangePoint(this, item, dataRowIndex, newCurrentColumn.VisiblePosition); - if( convertedValue != null ) - { - m_defaultImageColumn = column; - break; - } + m_dataGridControl.SelectionChangerManager.UpdateSelection(oldPosition, newPosition, true, rowIsBeingEdited, SelectionManager.UpdateSelectionSource.Navigation); } - } } - } - - return m_defaultImageColumn; - } - - internal void EnsureResort() - { - if( ( !ItemsSourceHelper.IsDataView( this.Items ) ) && ( this.Items.SortDescriptions.Count > 0 ) ) - { - SortDescriptionCollection sortDescriptions = this.Items.SortDescriptions; - SortDescription[] sortDescriptionsCopy = new SortDescription[ sortDescriptions.Count ]; - sortDescriptions.CopyTo( sortDescriptionsCopy, 0 ); - sortDescriptions.Clear(); + //---------- PUBLIC METHODS ---------- - foreach( SortDescription sortDescription in sortDescriptionsCopy ) + public void BeginEdit() { - sortDescriptions.Add( sortDescription ); + this.BeginEdit(this.InternalCurrentItem); } - } - } - - internal void EnsureRegroup() - { - if( this.Items.GroupDescriptions.Count > 0 ) - { - ObservableCollection groupDescriptions = this.Items.GroupDescriptions; - GroupDescription[] groupDescriptionsCopy = new GroupDescription[ groupDescriptions.Count ]; - - groupDescriptions.CopyTo( groupDescriptionsCopy, 0 ); - groupDescriptions.Clear(); - - foreach( GroupDescription groupDescription in groupDescriptionsCopy ) + public void BeginEdit(object item) { - groupDescriptions.Add( groupDescription ); + DataGridControl.BeginEditHelper(this, item); } - } - } - internal static string GetColumnNameFromGroupDescription( GroupDescription groupDescription ) - { - PropertyGroupDescription propertyGroupDescription = - groupDescription as PropertyGroupDescription; + public void EndEdit() + { + DataGridControl.EndEditHelper(this); + } - if( propertyGroupDescription != null ) - return propertyGroupDescription.PropertyName; + public void CancelEdit() + { + DataGridControl.CancelEditHelper(this); + } - DataGridGroupDescription dataGridGroupDescription = - groupDescription as DataGridGroupDescription; + internal bool IsContainingItem(object item) + { + DataTemplate itemTemplate = item as DataTemplate; - if( dataGridGroupDescription != null ) - return dataGridGroupDescription.PropertyName; + if ((this.ParentItem == null) && (itemTemplate != null)) + { + if (m_dataGridControl.View.FixedHeaders.Contains(itemTemplate) + || m_dataGridControl.View.FixedFooters.Contains(itemTemplate)) + { + return true; + } + } - throw new NotSupportedException( "Group descriptions other than PropertyGroupDescription or DataGridGroupDescription are not supported." ); - } + return m_generator.Contains(item); + } - internal static ObservableCollection GetGroupDescriptionsHelper( CollectionView collectionView ) - { - ObservableCollection retval = collectionView.GroupDescriptions; + public bool IsGroupExpanded(CollectionViewGroup group) + { + return (this.CustomItemContainerGenerator.IsGroupExpanded(group) == true); + } - ItemCollection itemCollection = collectionView as ItemCollection; + internal bool? IsGroupExpanded(CollectionViewGroup group, bool recurseDetails) + { + return this.CustomItemContainerGenerator.IsGroupExpanded(group, recurseDetails); + } - if( itemCollection != null ) - { - CollectionView sourceCollectionView = itemCollection.SourceCollection as CollectionView; + public bool ToggleGroupExpansion(CollectionViewGroup group) + { + return this.CustomItemContainerGenerator.ToggleGroupExpansion(group); + } - if( sourceCollectionView != null ) + public bool ExpandGroup(CollectionViewGroup group) { - if( sourceCollectionView.GroupDescriptions != null ) - retval = sourceCollectionView.GroupDescriptions; + return this.CustomItemContainerGenerator.ExpandGroup(group); } - else + + internal bool ExpandGroup(CollectionViewGroup group, bool recurseDetails) { - sourceCollectionView = CollectionViewSource.GetDefaultView( itemCollection.SourceCollection ) as CollectionView; + return this.CustomItemContainerGenerator.ExpandGroup(group, recurseDetails); + } - if( ( sourceCollectionView != null ) && ( sourceCollectionView.GroupDescriptions != null ) ) - retval = sourceCollectionView.GroupDescriptions; + public bool CollapseGroup(CollectionViewGroup group) + { + return this.CustomItemContainerGenerator.CollapseGroup(group); } - } - return retval; - } + internal bool CollapseGroup(CollectionViewGroup group, bool recurseDetails) + { + return this.CustomItemContainerGenerator.CollapseGroup(group, recurseDetails); + } - internal Group GetGroupFromItem( object dataItem ) - { - return this.CustomItemContainerGenerator.GetGroupFromItem( dataItem ); - } + public bool AreDetailsExpanded(object dataItem) + { + return this.CustomItemContainerGenerator.AreDetailsExpanded(dataItem); + } - internal IDisposable SetQueueBringIntoViewRestrictions( AutoScrollCurrentItemSourceTriggers trigger ) - { - return m_dataGridControl.SetQueueBringIntoViewRestrictions( trigger ); - } + public Group GetGroupFromCollectionViewGroup(CollectionViewGroup collectionViewGroup) + { + if (collectionViewGroup == null) + return null; - internal IDisposable InhibitQueueBringIntoView() - { - return m_dataGridControl.InhibitQueueBringIntoView(); - } + Group group = this.CustomItemContainerGenerator.GetGroupFromCollectionViewGroup(collectionViewGroup); - internal IDisposable InhibitSetFocus() - { - return m_dataGridControl.InhibitSetFocus(); - } + return group; + } - internal void NotifyItemsSourceChanged() - { - this.OnPropertyChanged( "HasDetails" ); - } + public DependencyObject GetContainerFromItem(object item) + { + if (item == null) + return null; - internal void DelayBringIntoViewAndFocusCurrent( AutoScrollCurrentItemSourceTriggers trigger ) - { - m_dataGridControl.DelayBringIntoViewAndFocusCurrent( trigger ); - } + var container = default(DependencyObject); - internal void ResetViewProperties() - { - //Used only for the Print DataGridControl - this.SetupViewProperties(); - this.InitializeViewProperties(); - } + if ((m_detailConfig == null) && (item is DataTemplate)) + { + //If the container was not found in the DataGridContext's Generator and the DataGridContext does not have a source DetailConfig ( master context ) + //then check in the DataGridControl's Fixed Items + container = m_dataGridControl.GetContainerForFixedItem(item); + } - internal void SetCurrent( - object item, - Row containerRow, - Nullable sourceDataItemIndex, - ColumnBase column, - bool forceFocus, - bool isCancelable, - bool synchronizeSelectionWithCurrent, - AutoScrollCurrentItemSourceTriggers trigger ) - { - // sourceDataItemIndex - // null = item have to be checked if it is a dataItem - // -1 = the item it's not a dataItem - // ? = then index of the item in the source collection. + if (container == null) + { + container = this.CustomItemContainerGenerator.ContainerFromItem(item); + } - //verify that SetCurrent is not called successively caused by actions performed within, this is to prevent - //exceptions caused by the accessing of resources that could be "locked" (e.g., ItemsControl.Items.DeferRefresh) - if( m_dataGridControl.IsSetCurrentInProgress ) - throw new DataGridException( "SetCurrent cannot be invoked while another SetCurrent is in progress.", m_dataGridControl ); + return container; + } - try - { - //set the flag that indicates that we are already processing a SetCurrent - m_dataGridControl.IsSetCurrentInProgress = true; + public object GetItemFromContainer(DependencyObject container) + { + object item = null; - var oldCurrentContext = m_dataGridControl.CurrentContext; - var newCurrentContext = this; + if (m_detailConfig == null) + { + //If the item was not found in the DataGridContext's Generator and the DataGridContext does not have a source DetailConfig ( master context ) + //then check in the DataGridControl's Fixed Items + item = DataGridControl.GetFixedItemFromContainer(container); + } - //store the previous public current item, so I can detect a change and lift the PropertyChanged for this properties - var oldCurrentItem = oldCurrentContext.InternalCurrentItem; - var oldPublicCurrentItem = oldCurrentContext.CurrentItem; - var oldCurrentColumn = oldCurrentContext.CurrentColumn; - var oldCurrentRow = oldCurrentContext.CurrentRow; + if (item == null) + { + item = this.CustomItemContainerGenerator.ItemFromContainer(container); + } - //if item is not realized or if the item passed is not a Data Item (header, footer or group), then the old current cell will be null - var oldCurrentCell = ( oldCurrentRow == null ) ? null : oldCurrentRow.Cells[ oldCurrentColumn ]; + return item; + } - var newCurrentRow = ( containerRow != null ) ? containerRow : Row.FromContainer( this.GetContainerFromItem( item ) ); - var newCurrentCell = default( Cell ); + [EditorBrowsable(EditorBrowsableState.Never)] + public DependencyObject GetContainerFromIndex(int index) + { + return this.CustomItemContainerGenerator.GetRealizedContainerForIndex(index); + } - //verify that set Current is not called on a column that cannot be current - if( newCurrentRow != null ) + [EditorBrowsable(EditorBrowsableState.Never)] + public int GetIndexFromContainer(DependencyObject container) { - newCurrentCell = newCurrentRow.Cells[ column ]; - if( ( column != null ) && column.ReadOnly && ( newCurrentCell != null ) && !newCurrentCell.GetCalculatedCanBeCurrent() ) - throw new DataGridException( "SetCurrent cannot be invoked if the column cannot be current.", m_dataGridControl ); + return this.CustomItemContainerGenerator.GetRealizedIndexForContainer(container); } - var currentCellChanged = ( newCurrentCell != oldCurrentCell ); + public CollectionViewGroup GetParentGroupFromItem(object item) + { + return this.GetParentGroupFromItemCore(item, false); + } - if( ( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) && ( oldCurrentRow != null ) ) + internal CollectionViewGroup GetParentGroupFromItemCore(object item, bool recurseDetails) { - if( Row.IsCellEditorDisplayConditionsSet( oldCurrentRow, CellEditorDisplayConditions.RowIsCurrent ) ) - { - oldCurrentRow.RemoveDisplayEditorMatchingCondition( CellEditorDisplayConditions.RowIsCurrent ); - } + CollectionViewGroup retval = null; + + DataTemplate dataTemplate = item as DataTemplate; - oldCurrentRow.SetIsCurrent( false ); + //For the master level, before interrogating the Generator, I need to check for the items presence in the Fixed regions. + if ((m_detailConfig == null) && (dataTemplate != null)) + { + Views.ViewBase view = m_dataGridControl.GetView(); + + //Fixed header cannot have a Parent Group. + if (view.FixedHeaders.Contains(dataTemplate) == true) + return null; + + //Fixed header cannot have a Parent Group. + if (view.FixedFooters.Contains(dataTemplate) == true) + return null; + } - try - { - oldCurrentRow.EndEdit(); - } - //an error occurred in the end edit - catch( DataGridException ) - { - //restore the Cell and the Row's IsCurrent Flag - if( oldCurrentCell != null ) + if (this.CustomItemContainerGenerator.IsInUse == true) { - oldCurrentCell.SetIsCurrent( true ); + retval = this.CustomItemContainerGenerator.GetParentGroupFromItem(item, recurseDetails); } - oldCurrentRow.SetIsCurrent( true ); - throw; - } + return retval; } - //For this if, the assumption is that current item hasn't changed, but current column has... (previous if will have caught the case where current item changed). + internal DataGridContext GetChildContext(object parentItem, DetailConfiguration detailConfiguration) + { + if (detailConfiguration == null) + throw new ArgumentNullException("detailConfiguration"); + + return this.GetChildContext(parentItem, detailConfiguration.RelationName); + } - //if the currentCell has changed and the old current cell still exists. - if( ( currentCellChanged ) && ( oldCurrentCell != null ) ) + public DataGridContext GetChildContext(object parentItem, string relationName) { - //clear the CellIsCurrent editor display conditions - if( Cell.IsCellEditorDisplayConditionsSet( oldCurrentCell, CellEditorDisplayConditions.CellIsCurrent ) ) - { - oldCurrentCell.RemoveDisplayEditorMatchingCondition( CellEditorDisplayConditions.CellIsCurrent ); - } + return this.CustomItemContainerGenerator.GetChildContext(parentItem, relationName); + } - oldCurrentCell.SetIsCurrent( false ); + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate")] + public IEnumerable GetChildContexts() + { + return this.CustomItemContainerGenerator.GetChildContexts(); + } - try - { - //cancel any ongoing editing on the cell. (this has no effect if row or cell is not being edited. This line can throw but no action is to be done. - oldCurrentCell.EndEdit(); - } - catch( DataGridException ) - { - oldCurrentCell.SetIsCurrent( true ); - throw; - } + internal IEnumerable GetChildContextsCore() + { + return this.CustomItemContainerGenerator.GetChildContextsCore(); } - if( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) + internal BindingPathValueExtractor GetBindingPathExtractorForColumn(Column column, object dataItem) { - var currentChangingEventArgs = new DataGridCurrentChangingEventArgs( oldCurrentContext, oldCurrentItem, newCurrentContext, item, isCancelable ); - m_dataGridControl.RaiseCurrentChanging( currentChangingEventArgs ); + if (column == null) + throw new ArgumentNullException("column"); - if( isCancelable && currentChangingEventArgs.Cancel ) - { - // We restore the currentness on the previous row and cell. - if( oldCurrentRow != null ) - { - if( oldCurrentCell != null ) - { - oldCurrentCell.SetIsCurrent( true ); - } + if (dataItem == null) + return null; + + if (column == null) + throw new ArgumentNullException("column"); + + var xPath = default(string); + var propertyPath = default(PropertyPath); + + // Disable warning for DisplayMemberBinding when internaly used +#pragma warning disable 618 + var displayMemberBinding = column.DisplayMemberBinding as Binding; +#pragma warning restore 618 - oldCurrentRow.SetIsCurrent( true ); + if (displayMemberBinding == null) + { + displayMemberBinding = ItemsSourceHelper.CreateDefaultBinding( + ItemsSourceHelper.CreateOrGetPropertyDescriptionFromColumn(this, column, dataItem.GetType())); } - throw new DataGridException( "The operation has been canceled.", m_dataGridControl ); - } - } + if (displayMemberBinding == null) + throw new DataGridInternalException("DisplayMemberBinding is null.", m_dataGridControl); - //If they are different, clean the previously current DataGridContext - if( oldCurrentContext != newCurrentContext ) - { - oldCurrentContext.SetCurrentItem( null, -1 ); - oldCurrentContext.SetInternalCurrentItem( null ); - //preserve current column on the old DataGridContext + xPath = displayMemberBinding.XPath; + propertyPath = displayMemberBinding.Path; - oldCurrentContext.SetIsCurrent( false ); + var converter = new Xceed.Wpf.DataGrid.Converters.SourceDataConverter(ItemsSourceHelper.IsItemSupportingDBNull(dataItem), CultureInfo.InvariantCulture); + + return new BindingPathValueExtractor(xPath, propertyPath, false, typeof(object), converter, null, CultureInfo.InvariantCulture); } - if( !sourceDataItemIndex.HasValue ) + public IDisposable DeferColumnsUpdate() { - sourceDataItemIndex = this.Items.IndexOf( item ); + return ColumnHierarchyManagerHelper.DeferColumnsUpdate(this); } - // All the stuff that can throw is done - newCurrentContext.SetInternalCurrentItem( item ); - newCurrentContext.SetIsCurrent( true ); - - // change the CurrentRow and CurentColumn - if( ( item != null ) && ( sourceDataItemIndex.Value != -1 ) ) + public bool MoveColumnBefore(ColumnBase current, ColumnBase next) { - newCurrentContext.SetCurrentItem( item, sourceDataItemIndex.Value ); + return ColumnHierarchyManagerHelper.MoveColumnBefore(this, current, next); } - else + + public bool MoveColumnAfter(ColumnBase current, ColumnBase previous) { - newCurrentContext.SetCurrentItem( null, -1 ); + return ColumnHierarchyManagerHelper.MoveColumnAfter(this, current, previous); } - newCurrentContext.SetCurrentColumnHelper( column ); - m_dataGridControl.SetCurrentDataGridContextHelper( this ); - - // We must refetch the container for the current item in case EndEdit triggers a reset on the - // CustomItemContainerGenerator and remap this item to a container other than the one previously fetched - newCurrentRow = Row.FromContainer( newCurrentContext.GetContainerFromItem( item ) ); - newCurrentCell = ( newCurrentRow == null ) ? null : newCurrentRow.Cells[ column ]; - - bool currentRowChanged = ( newCurrentRow != oldCurrentRow ); - - //If there is a container for the new Row. - if( newCurrentRow != null ) + public bool MoveColumnUnder(ColumnBase current, ColumnBase parent) { - Debug.Assert( newCurrentRow.IsContainerPrepared, "The container must be prepared to be set as current and call BeginEdit." ); - - //update the RowIsCurrent display condition - if( Row.IsCellEditorDisplayConditionsSet( newCurrentRow, CellEditorDisplayConditions.RowIsCurrent ) ) - { - newCurrentRow.SetDisplayEditorMatchingCondition( CellEditorDisplayConditions.RowIsCurrent ); - } - - //Update the IsCurrent flag - newCurrentRow.SetIsCurrent( true ); + return ColumnHierarchyManagerHelper.MoveColumnUnder(this, current, parent); + } - //if the current row changed, make sure to check the appropriate edition triggers. - if( currentRowChanged == true ) - { - //if EditTriggers tells to enter editing mode AND no current cell is set on the new current row - if( ( newCurrentRow.IsEditTriggerSet( EditTriggers.RowIsCurrent ) ) && ( newCurrentCell == null ) ) - { - //To prevent re-entrancy of the SetCurrent fonction (since Row.BeginEdit will call Cell.BeginEdit which will call SetCurrent if not current already) - if( this.VisibleColumns.Count > 0 ) - { - var firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableColumnIndex( this, newCurrentRow ); - if( firstFocusableColumn < 0 ) - throw new DataGridException( "Trying to edit while no cell is focusable. ", m_dataGridControl ); + //---------- INTERNAL METHODS ----------- - this.SetCurrentColumnHelper( this.VisibleColumns[ firstFocusableColumn ] ); - newCurrentCell = newCurrentRow.Cells[ m_currentColumn ]; - currentCellChanged = true; - } - } - } + internal IDisposable DeferRestoreState() + { + return new DeferRestoreStateDisposable(this); } - //If current cell exists. - if( newCurrentCell != null ) + internal void UpdatePublicSelectionProperties() { - //update the CellIsCurrent display condition - if( Cell.IsCellEditorDisplayConditionsSet( newCurrentCell, CellEditorDisplayConditions.CellIsCurrent ) ) - { - newCurrentCell.SetDisplayEditorMatchingCondition( CellEditorDisplayConditions.CellIsCurrent ); - } + if ((m_selectedItemsStore.Count > 0) || (m_selectedCellsStore.Count > 0)) + { + m_dataGridControl.AddToSelectedContexts(this); + } + else + { + m_dataGridControl.RemoveFromSelectedContexts(this); + } - newCurrentCell.SetIsCurrent( true ); - //Then, if the Current Cell has changed or not currently in edition, process the edition conditions. - if( currentCellChanged || !newCurrentCell.IsBeingEdited ) - { - //if the EditTriggers dictate that we should enter edition, do it. - if( ( newCurrentRow.IsEditTriggerSet( EditTriggers.CellIsCurrent ) ) - || ( ( newCurrentRow.IsEditTriggerSet( EditTriggers.RowIsCurrent ) ) && ( currentRowChanged ) ) ) + if (m_parentItem == null) { - try - { - newCurrentCell.BeginEdit(); - } - catch( DataGridException ) - { - // We swallow the exception if it occurs because the Cell was read-only. + // We are the root context ( GridControl ) + int newSelectedItemIndex; + object newSelectedItem; + int newSelectedColumnIndex; + this.GetFirstSelectedItemFromStore(false, out newSelectedItemIndex, out newSelectedItem, out newSelectedColumnIndex); - // Try to begin edit only on the row - try + if (m_dataGridControl.SelectedIndex != newSelectedItemIndex) { - newCurrentRow.BeginEdit(); + m_dataGridControl.SelectedIndex = newSelectedItemIndex; } - catch( DataGridException ) + + // Calculate the new SelectedItem + if (!object.Equals(m_dataGridControl.SelectedItem, newSelectedItem)) { - // We swallow the exception if it occurs because the Row was read-only. + m_dataGridControl.SetSkipCoerceSelectedItemCheck(true); + + try + { + m_dataGridControl.SelectedItem = newSelectedItem; + } + finally + { + m_dataGridControl.SetSkipCoerceSelectedItemCheck(false); + } } - } } - } } - //if there is a new CurrentItem - if( item != null ) + internal void GetFirstSelectedItemFromStore(bool checkCellsStore, out int selectedItemIndex, out object selectedItem, out int selectedColumnIndex) { - //if the container from the new Current item is realized - if( newCurrentRow != null ) - { - if( m_dataGridControl.IsBringIntoViewAllowed( trigger ) ) + var newSelectedRangeWithItems = (m_selectedItemsStore.Count == 0) ? SelectionRangeWithItems.Empty : m_selectedItemsStore[0]; + + try { - if( !m_dataGridControl.IsBringIntoViewDelayed ) - { - if( newCurrentCell != null ) + if (newSelectedRangeWithItems.IsEmpty) { - newCurrentCell.BringIntoView(); + if (checkCellsStore) + { + var newSelectionCellRangeWithItems = (m_selectedCellsStore.Count == 0) ? SelectionCellRangeWithItems.Empty : m_selectedCellsStore[0]; + + if (newSelectionCellRangeWithItems.ItemRange.IsEmpty) + { + selectedColumnIndex = -1; + selectedItemIndex = -1; + selectedItem = null; + } + else + { + selectedColumnIndex = newSelectionCellRangeWithItems.ColumnRange.StartIndex; + selectedItemIndex = newSelectionCellRangeWithItems.ItemRange.StartIndex; + selectedItem = newSelectionCellRangeWithItems.ItemRangeWithItems.GetItem(this, 0); + } + } + else + { + selectedColumnIndex = -1; + selectedItemIndex = -1; + selectedItem = null; + } } else { - // Ensure the item is visible visible - newCurrentRow.BringIntoView(); + selectedColumnIndex = -1; + selectedItemIndex = newSelectedRangeWithItems.Range.StartIndex; + selectedItem = newSelectedRangeWithItems.GetItem(this, 0); } - } - else - { - m_dataGridControl.DelayBringIntoViewAndFocusCurrent( trigger ); - } } - - using( m_dataGridControl.SelectionChangerManager.PushUpdateSelectionSource( SelectionManager.UpdateSelectionSource.None ) ) + catch (ArgumentOutOfRangeException) { - // Call this to update the Focus to the correct location - m_dataGridControl.SetFocusHelper( newCurrentRow, column, forceFocus, true ); + selectedColumnIndex = -1; + selectedItemIndex = -1; + selectedItem = null; } - } - else - { - m_dataGridControl.DelayBringIntoViewAndFocusCurrent( trigger ); - } } - //Send notification at the end (as much as possible) to ensure that no code bound on the property changed handler will interrupt this sequence - - if( ( synchronizeSelectionWithCurrent ) && ( !m_dataGridControl.SelectionChangerManager.IsActive ) ) + internal ColumnBase GetMatchingColumn(DataGridContext sourceContext, ColumnBase sourceColumn) { - m_dataGridControl.SelectionChangerManager.Begin(); + if ((sourceContext == null) || (sourceColumn == null)) + return null; + + if (sourceContext == this) + return sourceColumn; + + var collectionView = sourceContext.ItemsSourceCollection as DataGridCollectionViewBase; + if (collectionView == null) + return null; - try - { - if( m_dataGridControl.SelectionUnit == SelectionUnit.Row ) + var sourceItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty(collectionView.ItemProperties, sourceColumn.FieldName); + if (sourceItemProperty == null) + return null; + + var masterContext = sourceContext.RootDataGridContext; + var masterItemProperty = sourceItemProperty; + + if (masterContext != sourceContext) { - if( newCurrentContext.CurrentItemIndex == -1 ) - { - m_dataGridControl.SelectionChangerManager.UnselectAll(); - } - else - { - m_dataGridControl.SelectionChangerManager.SelectJustThisItem( this, newCurrentContext.CurrentItemIndex, newCurrentContext.CurrentItem ); - } + if (!sourceContext.ItemPropertyMap.TryGetMasterItemProperty(sourceItemProperty, out masterItemProperty)) + return null; } - else - { - int currentColumnVisibleIndex = ( newCurrentContext.CurrentColumn == null ) ? -1 : newCurrentContext.CurrentColumn.VisiblePosition; - if( ( currentColumnVisibleIndex == -1 ) || ( newCurrentContext.CurrentItemIndex == -1 ) ) - { - m_dataGridControl.SelectionChangerManager.UnselectAll(); - } - else - { - m_dataGridControl.SelectionChangerManager.SelectJustThisCell( this, newCurrentContext.CurrentItemIndex, newCurrentContext.CurrentItem, currentColumnVisibleIndex ); - } + Debug.Assert(masterItemProperty != null); + if (masterItemProperty == null) + return null; + + var currentItemProperty = masterItemProperty; + if (masterContext != this) + { + if (!this.ItemPropertyMap.TryGetDetailItemProperty(masterItemProperty, out currentItemProperty)) + return null; } - } - finally - { - m_dataGridControl.SelectionChangerManager.End( false, false ); - } - } - if( this.CurrentItem != oldPublicCurrentItem ) - { - this.OnPropertyChanged( "CurrentItem" ); - } + Debug.Assert(currentItemProperty != null); + if (currentItemProperty == null) + return null; - if( column != oldCurrentColumn ) - { - this.OnPropertyChanged( "CurrentColumn" ); - } + var columnName = PropertyRouteParser.Parse(currentItemProperty); + if (string.IsNullOrEmpty(columnName)) + return null; - if( ( item != oldCurrentItem ) || ( oldCurrentContext != newCurrentContext ) ) - { - var currentChangedEventArgs = new DataGridCurrentChangedEventArgs( oldCurrentContext, oldCurrentItem, newCurrentContext, item ); - m_dataGridControl.RaiseCurrentChanged( currentChangedEventArgs ); + return this.Columns[columnName]; } - } - finally - { - m_dataGridControl.IsSetCurrentInProgress = false; - } - } - - internal void SetupTitleBindingForGroupLevelDescriptions() - { - foreach( GroupLevelDescription gld in this.GroupLevelDescriptions ) - { - Binding titleBinding = BindingOperations.GetBinding( gld, GroupLevelDescription.TitleProperty ); - if( titleBinding == null ) + internal ColumnBase GetDefaultImageColumn() { - ColumnBase column = this.Columns[ gld.FieldName ]; - - if( column != null ) - { - DataGridContext.SetupGroupLevelDescriptionBindings( gld, column ); - } - } - } - } + if (!this.DefaultImageColumnDetermined) + { + if (this.Items.Count > 0) + { + this.DefaultImageColumnDetermined = true; - internal static void UpdateGroupLevelDescriptions( GroupLevelDescriptionCollection groupLevelDescriptions, - NotifyCollectionChangedEventArgs e, ObservableCollection groupDescriptions, ColumnCollection columns ) - { - switch( e.Action ) - { - case NotifyCollectionChangedAction.Add: - //add all the items added into the GroupLevelDescriptions collection - for( int i = 0; i < e.NewItems.Count; i++ ) - { - GroupLevelDescription newInfo = DataGridContext.CreateGroupLevelDescription( columns, ( GroupDescription )e.NewItems[ i ] ); + var dataItem = this.Items.GetItemAt(0); - groupLevelDescriptions.Insert( i + e.NewStartingIndex, newInfo ); - } - break; + foreach (var column in this.VisibleColumns) + { + var key = PropertyRouteParser.Parse(column.FieldName); + if (key == null) + continue; + + var propertyDescriptionRoute = default(PropertyDescriptionRoute); + if (!m_itemsSourcePropertyDescriptions.TryGetValue(key, out propertyDescriptionRoute)) + continue; + + var propertyDescription = propertyDescriptionRoute.Current; + var dataType = propertyDescription.DataType; + + if (typeof(ImageSource).IsAssignableFrom(dataType)) + { + m_defaultImageColumn = column; + break; + } + else if ((typeof(byte[]).IsAssignableFrom(dataType)) /*|| (typeof(System.Drawing.Image).IsAssignableFrom(dataType))*/) + { + var converter = new Xceed.Wpf.DataGrid.Converters.ImageConverter(); + var convertedValue = default(object); + var rawValue = default(object); + + try + { + if (propertyDescription.PropertyDescriptor == null) + { + var dataRow = dataItem as System.Data.DataRow; + if (dataRow == null) + { + var dataRowView = dataItem as System.Data.DataRowView; + if (dataRowView != null) + { + rawValue = dataRowView[propertyDescription.Name]; + } + } + else + { + rawValue = dataRow[propertyDescription.Name]; + } + } + else + { + rawValue = propertyDescription.PropertyDescriptor.GetValue(dataItem); + } + + if (rawValue != null) + { + convertedValue = converter.Convert(rawValue, typeof(ImageSource), null, CultureInfo.CurrentCulture); + } + } + catch (NotSupportedException) + { + //suppress the exception, the byte[] is not an image. convertedValue will remain null + } + + if (convertedValue != null) + { + m_defaultImageColumn = column; + break; + } + } + } + } + } - case NotifyCollectionChangedAction.Remove: - foreach( GroupDescription desc in e.OldItems ) - { - GroupLevelDescription oldInfo = DataGridContext.GetGroupLevelDescription( groupLevelDescriptions, desc ); + return m_defaultImageColumn; + } - if( oldInfo != null ) + internal void EnsureResort() + { + if ((!ItemsSourceHelper.IsDataView(this.Items)) && (this.Items.SortDescriptions.Count > 0)) { - groupLevelDescriptions.Remove( oldInfo ); - } - } - break; + SortDescriptionCollection sortDescriptions = this.Items.SortDescriptions; + SortDescription[] sortDescriptionsCopy = new SortDescription[sortDescriptions.Count]; - case NotifyCollectionChangedAction.Reset: + sortDescriptions.CopyTo(sortDescriptionsCopy, 0); + sortDescriptions.Clear(); - groupLevelDescriptions.Clear(); + foreach (SortDescription sortDescription in sortDescriptionsCopy) + { + sortDescriptions.Add(sortDescription); + } + } + } - foreach( GroupDescription desc in groupDescriptions ) - { - GroupLevelDescription newInfo = DataGridContext.CreateGroupLevelDescription( columns, desc ); + internal void EnsureRegroup() + { + + if (this.Items.GroupDescriptions.Count > 0) + { + ObservableCollection groupDescriptions = this.Items.GroupDescriptions; + GroupDescription[] groupDescriptionsCopy = new GroupDescription[groupDescriptions.Count]; - groupLevelDescriptions.Add( newInfo ); - } + groupDescriptions.CopyTo(groupDescriptionsCopy, 0); + groupDescriptions.Clear(); - break; + foreach (GroupDescription groupDescription in groupDescriptionsCopy) + { + groupDescriptions.Add(groupDescription); + } + } + } - case NotifyCollectionChangedAction.Move: + internal static string GetColumnNameFromGroupDescription(GroupDescription groupDescription) + { + PropertyGroupDescription propertyGroupDescription = + groupDescription as PropertyGroupDescription; - GroupLevelDescription movedGroupLevelDescription = groupLevelDescriptions[ e.OldStartingIndex ]; - groupLevelDescriptions.RemoveAt( e.OldStartingIndex ); - groupLevelDescriptions.Insert( e.NewStartingIndex, movedGroupLevelDescription ); + if (propertyGroupDescription != null) + return propertyGroupDescription.PropertyName; - break; + DataGridGroupDescription dataGridGroupDescription = + groupDescription as DataGridGroupDescription; - case NotifyCollectionChangedAction.Replace: + if (dataGridGroupDescription != null) + return dataGridGroupDescription.PropertyName; - groupLevelDescriptions.RemoveAt( e.OldStartingIndex ); - GroupLevelDescription replaceInfo = DataGridContext.CreateGroupLevelDescription( columns, ( GroupDescription )e.NewItems[ 0 ] ); + throw new NotSupportedException("Group descriptions other than PropertyGroupDescription or DataGridGroupDescription are not supported."); + } - groupLevelDescriptions.Insert( e.NewStartingIndex, replaceInfo ); + internal static ObservableCollection GetGroupDescriptionsHelper(CollectionView collectionView) + { + ObservableCollection retval = collectionView.GroupDescriptions; - break; - } - } + ItemCollection itemCollection = collectionView as ItemCollection; - internal static DataGridContext SafeGetDataGridContextForDataGridCollectionView( - DataGridContext rootDataGridContext, - DataGridCollectionViewBase targetDataGridCollectionViewBase ) - { - DataGridContext matchingDataGridContext = null; + if (itemCollection != null) + { + CollectionView sourceCollectionView = itemCollection.SourceCollection as CollectionView; + + if (sourceCollectionView != null) + { + if (sourceCollectionView.GroupDescriptions != null) + retval = sourceCollectionView.GroupDescriptions; + } + else + { + sourceCollectionView = CollectionViewSource.GetDefaultView(itemCollection.SourceCollection) as CollectionView; + + if ((sourceCollectionView != null) && (sourceCollectionView.GroupDescriptions != null)) + retval = sourceCollectionView.GroupDescriptions; + } + } - DataGridCollectionViewBase rootDataGridCollectionViewBase = rootDataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + return retval; + } - if( rootDataGridCollectionViewBase != null ) - { - if( rootDataGridCollectionViewBase == targetDataGridCollectionViewBase ) + internal Group GetGroupFromItem(object dataItem) { - matchingDataGridContext = rootDataGridContext; + return this.CustomItemContainerGenerator.GetGroupFromItem(dataItem); } - else + + internal IDisposable SetQueueBringIntoViewRestrictions(AutoScrollCurrentItemSourceTriggers trigger) { - matchingDataGridContext = DataGridContext.SafeRecursiveGetDataGridContextForDataGridCollectionViewBase( - rootDataGridContext.GetChildContexts(), - targetDataGridCollectionViewBase ); + return m_dataGridControl.SetQueueBringIntoViewRestrictions(trigger); } - } - return matchingDataGridContext; - } + internal IDisposable InhibitQueueBringIntoView() + { + return m_dataGridControl.InhibitQueueBringIntoView(); + } - private static DataGridContext SafeRecursiveGetDataGridContextForDataGridCollectionViewBase( - IEnumerable childDataGridContexts, - DataGridCollectionViewBase targetDataGridCollectionViewBase ) - { - foreach( DataGridContext childDataGridContext in childDataGridContexts ) - { - // Child DataGridContext's Items cannot be anything else than a DataGridCollectionView. - DataGridCollectionViewBase dataGridCollectionViewBase = ( DataGridCollectionViewBase )childDataGridContext.Items; + internal IDisposable InhibitSetFocus() + { + return m_dataGridControl.InhibitSetFocus(); + } - if( dataGridCollectionViewBase == targetDataGridCollectionViewBase ) - return childDataGridContext; + internal void NotifyItemsSourceChanged() + { + this.OnPropertyChanged("HasDetails"); + } - // Deep down. - DataGridContext matchingDataGridContext = DataGridContext.SafeRecursiveGetDataGridContextForDataGridCollectionViewBase( - childDataGridContext.GetChildContexts(), - targetDataGridCollectionViewBase ); + internal void DelayBringIntoViewAndFocusCurrent(AutoScrollCurrentItemSourceTriggers trigger) + { + m_dataGridControl.DelayBringIntoViewAndFocusCurrent(trigger); + } - if( matchingDataGridContext != null ) - return matchingDataGridContext; - } + internal void ResetViewProperties() + { + //Used only for the Print DataGridControl + this.SetupViewProperties(); + this.InitializeViewProperties(); + } - return null; - } + internal void SetCurrent( + object item, + Row containerRow, + Nullable sourceDataItemIndex, + ColumnBase column, + bool forceFocus, + bool isCancelable, + bool synchronizeSelectionWithCurrent, + AutoScrollCurrentItemSourceTriggers trigger) + { + // sourceDataItemIndex + // null = item have to be checked if it is a dataItem + // -1 = the item it's not a dataItem + // ? = then index of the item in the source collection. - private static void UnselectAllCells( DataGridContext dataGridContext ) - { - if( dataGridContext == null ) - return; - - var selectionManager = dataGridContext.DataGridControl.SelectionChangerManager; - selectionManager.Begin(); - - try - { - selectionManager.UnselectAllCells( dataGridContext ); - } - finally - { - selectionManager.End( false, false ); - } - } + //verify that SetCurrent is not called successively caused by actions performed within, this is to prevent + //exceptions caused by the accessing of resources that could be "locked" (e.g., ItemsControl.Items.DeferRefresh) + if (m_dataGridControl.IsSetCurrentInProgress) + throw new DataGridException("SetCurrent cannot be invoked while another SetCurrent is in progress.", m_dataGridControl); - internal void SaveContainerSizeState( object item, FrameworkElement container ) - { - if( item == null ) - return; + try + { + //set the flag that indicates that we are already processing a SetCurrent + m_dataGridControl.IsSetCurrentInProgress = true; - ContainerSizeState containerSizeState = new ContainerSizeState( container ); + var oldCurrentContext = m_dataGridControl.CurrentContext; + var newCurrentContext = this; - if( containerSizeState.IsEmpty() == false ) - { - m_sizeStateDictionary[ item ] = containerSizeState; + //store the previous public current item, so I can detect a change and lift the PropertyChanged for this properties + var oldCurrentItem = oldCurrentContext.InternalCurrentItem; + var oldPublicCurrentItem = oldCurrentContext.CurrentItem; + var oldCurrentColumn = oldCurrentContext.CurrentColumn; + var oldCurrentRow = oldCurrentContext.CurrentRow; - DataGridContext.CleanContainerSizeState( container, containerSizeState ); - } - else - { - m_sizeStateDictionary.Remove( item ); - } - } + //if item is not realized or if the item passed is not a Data Item (header, footer or group), then the old current cell will be null + var oldCurrentCell = (oldCurrentRow == null) ? null : oldCurrentRow.Cells[oldCurrentColumn]; - internal void RestoreContainerSizeState( object item, FrameworkElement container ) - { - if( item == null ) - return; - - ContainerSizeState containerSizeState; - if( m_sizeStateDictionary.TryGetValue( item, out containerSizeState ) == true ) - { - DataGridContext.RestoreContainerSizeWorker( container, containerSizeState ); - } - } + var newCurrentRow = (containerRow != null) ? containerRow : Row.FromContainer(this.GetContainerFromItem(item)); + var newCurrentCell = default(Cell); - internal void ClearSizeStates() - { - m_sizeStateDictionary.Clear(); - } + //verify that set Current is not called on a column that cannot be current + if (newCurrentRow != null) + { + newCurrentCell = newCurrentRow.Cells[column]; + if ((column != null) && column.ReadOnly && (newCurrentCell != null) && !newCurrentCell.GetCalculatedCanBeCurrent()) + throw new DataGridException("SetCurrent cannot be invoked if the column cannot be current.", m_dataGridControl); + } - /// - /// Gets the current View property value for this DataGridContext. It can either come - /// from a local (attached) value or the value on the view (if the property is "routed"). - /// - /// The return value type of the requested property. - /// The property name on the View. - /// The value of the property if found. Will be ignored if the property is not found. - /// Returns true if the returnValue has been set. False otherwise. - internal bool GetViewPropertyValue( string propertyName, ref T returnValue ) - { - object value = null; + var currentCellChanged = (newCurrentCell != oldCurrentCell); - if( m_viewPropertiesDescriptors != null ) - { - PropertyDescriptor descriptor = m_viewPropertiesDescriptors[ propertyName ]; + if (((item != oldCurrentItem) || (oldCurrentContext != newCurrentContext)) && (oldCurrentRow != null)) + { + if (Row.IsCellEditorDisplayConditionsSet(oldCurrentRow, CellEditorDisplayConditions.RowIsCurrent)) + { + oldCurrentRow.RemoveDisplayEditorMatchingCondition(CellEditorDisplayConditions.RowIsCurrent); + } - if( descriptor != null ) - value = descriptor.GetValue( this ); - } + oldCurrentRow.SetIsCurrent(false); - if( value != null ) - { - returnValue = ( T )value; - return true; - } + try + { + oldCurrentRow.EndEdit(); + } + //an error occurred in the end edit + catch (DataGridException) + { + //restore the Cell and the Row's IsCurrent Flag + if (oldCurrentCell != null) + { + oldCurrentCell.SetIsCurrent(true); + } + + oldCurrentRow.SetIsCurrent(true); + throw; + } + } - return false; - } + //For this if, the assumption is that current item hasn't changed, but current column has... (previous if will have caught the case where current item changed). + //if the currentCell has changed and the old current cell still exists. + if ((currentCellChanged) && (oldCurrentCell != null)) + { + //clear the CellIsCurrent editor display conditions + if (Cell.IsCellEditorDisplayConditionsSet(oldCurrentCell, CellEditorDisplayConditions.CellIsCurrent)) + { + oldCurrentCell.RemoveDisplayEditorMatchingCondition(CellEditorDisplayConditions.CellIsCurrent); + } + oldCurrentCell.SetIsCurrent(false); - //---------- PRIVATE METHODS ---------- + try + { + //cancel any ongoing editing on the cell. (this has no effect if row or cell is not being edited. This line can throw but no action is to be done. + oldCurrentCell.EndEdit(); + } + catch (DataGridException) + { + oldCurrentCell.SetIsCurrent(true); + throw; + } + } - private void ClearViewPropertyBindings() - { - foreach( Views.ViewBase.ViewPropertyStruct viewProperty in m_viewProperties ) - { - BindingOperations.ClearBinding( this, viewProperty.DependencyProperty ); - this.ClearValue( viewProperty.DependencyProperty ); - } - - m_viewProperties.Clear(); - - //Empty the list of ViewBindingPropertyDescriptor as well. - if( m_viewPropertiesDescriptors != null ) - { - m_viewPropertiesDescriptors.Clear(); - m_viewPropertiesDescriptors = null; - } - } + if ((item != oldCurrentItem) || (oldCurrentContext != newCurrentContext)) + { + var currentChangingEventArgs = new DataGridCurrentChangingEventArgs(oldCurrentContext, oldCurrentItem, newCurrentContext, item, isCancelable); + m_dataGridControl.RaiseCurrentChanging(currentChangingEventArgs); - private static GroupLevelDescription CreateGroupLevelDescription( ColumnCollection columns, GroupDescription group ) - { - GroupLevelDescription retval = null; - string columnName = DataGridContext.GetColumnNameFromGroupDescription( group ); + if (isCancelable && currentChangingEventArgs.Cancel) + { + // We restore the currentness on the previous row and cell. + if (oldCurrentRow != null) + { + if (oldCurrentCell != null) + { + oldCurrentCell.SetIsCurrent(true); + } + + oldCurrentRow.SetIsCurrent(true); + } + + throw new DataGridException("The operation has been canceled.", m_dataGridControl); + } + } - if( !string.IsNullOrEmpty( columnName ) ) - { - retval = new GroupLevelDescription( group, columnName ); + //If they are different, clean the previously current DataGridContext + if (oldCurrentContext != newCurrentContext) + { + oldCurrentContext.SetCurrentItem(null, -1); + oldCurrentContext.SetInternalCurrentItem(null); + //preserve current column on the old DataGridContext - //find the column for that property name - ColumnBase column = columns[ columnName ]; + oldCurrentContext.SetIsCurrent(false); + } - if( column != null ) - { - DataGridContext.SetupGroupLevelDescriptionBindings( retval, column ); - } - else - { - //if no column exists for that name, then use the name as the Title for the GroupLevelDescription - retval.SetTitle( columnName ); - } - } + if (!sourceDataItemIndex.HasValue) + { + sourceDataItemIndex = this.Items.IndexOf(item); + } - return retval; - } + // All the stuff that can throw is done + newCurrentContext.SetInternalCurrentItem(item); + newCurrentContext.SetIsCurrent(true); - private Binding CreateViewPropertyBinding( Views.ViewBase view, Views.ViewBase.ViewPropertyStruct viewProperty ) - { - var dependencyProperty = viewProperty.DependencyProperty; + // change the CurrentRow and CurentColumn + if ((item != null) && (sourceDataItemIndex.Value != -1)) + { + newCurrentContext.SetCurrentItem(item, sourceDataItemIndex.Value); + } + else + { + newCurrentContext.SetCurrentItem(null, -1); + } - if( this.IsAFlattenDetail ) - { - switch( viewProperty.FlattenDetailBindingMode ) - { - case FlattenDetailBindingMode.None: - return null; + newCurrentContext.SetCurrentColumnHelper(column); + m_dataGridControl.SetCurrentDataGridContextHelper(this); - case FlattenDetailBindingMode.MasterOneWay: - { - var rootDataGridContext = this.RootDataGridContext; - Debug.Assert( ( rootDataGridContext != null ) && ( this != rootDataGridContext ) ); - return DataGridContext.CreateViewPropertyBindingForSource( rootDataGridContext, dependencyProperty, BindingMode.OneWay ); - } + // We must refetch the container for the current item in case EndEdit triggers a reset on the + // CustomItemContainerGenerator and remap this item to a container other than the one previously fetched + newCurrentRow = Row.FromContainer(newCurrentContext.GetContainerFromItem(item)); + newCurrentCell = (newCurrentRow == null) ? null : newCurrentRow.Cells[column]; - default: - break; - } - } + bool currentRowChanged = (newCurrentRow != oldCurrentRow); - if( viewProperty.ViewPropertyMode == ViewPropertyMode.ViewOnly ) - return DataGridContext.CreateViewPropertyBindingForSource( view, dependencyProperty ); + //If there is a container for the new Row. + if (newCurrentRow != null) + { + Debug.Assert(newCurrentRow.IsContainerPrepared, "The container must be prepared to be set as current and call BeginEdit."); - var detailConfiguration = this.SourceDetailConfiguration; - if( detailConfiguration != null ) - { - var defaultDetailConfiguration = this.GetDefaultDetailConfigurationForContext(); - if( defaultDetailConfiguration != null ) - return DataGridContext.CreateViewPropertyBindingForSource( defaultDetailConfiguration, dependencyProperty ); + //update the RowIsCurrent display condition + if (Row.IsCellEditorDisplayConditionsSet(newCurrentRow, CellEditorDisplayConditions.RowIsCurrent)) + { + newCurrentRow.SetDisplayEditorMatchingCondition(CellEditorDisplayConditions.RowIsCurrent); + } - return DataGridContext.CreateViewPropertyBindingForSource( detailConfiguration, dependencyProperty ); - } + //Update the IsCurrent flag + newCurrentRow.SetIsCurrent(true); - return DataGridContext.CreateViewPropertyBindingForSource( view, dependencyProperty ); - } + //if the current row changed, make sure to check the appropriate edition triggers. + if (currentRowChanged == true) + { + //if EditTriggers tells to enter editing mode AND no current cell is set on the new current row + if ((newCurrentRow.IsEditTriggerSet(EditTriggers.RowIsCurrent)) && (newCurrentCell == null)) + { + //To prevent re-entrancy of the SetCurrent fonction (since Row.BeginEdit will call Cell.BeginEdit which will call SetCurrent if not current already) + if (this.VisibleColumns.Count > 0) + { + var firstFocusableColumn = NavigationHelper.GetFirstVisibleFocusableColumnIndex(this, newCurrentRow); + if (firstFocusableColumn < 0) + throw new DataGridException("Trying to edit while no cell is focusable. ", m_dataGridControl); + + this.SetCurrentColumnHelper(this.VisibleColumns[firstFocusableColumn]); + newCurrentCell = newCurrentRow.Cells[m_currentColumn]; + currentCellChanged = true; + } + } + } + } - private static Binding CreateViewPropertyBindingForSource( object source, DependencyProperty property ) - { - return DataGridContext.CreateViewPropertyBindingForSource( source, property, BindingMode.TwoWay ); - } + //If current cell exists. + if (newCurrentCell != null) + { + //update the CellIsCurrent display condition + if (Cell.IsCellEditorDisplayConditionsSet(newCurrentCell, CellEditorDisplayConditions.CellIsCurrent)) + { + newCurrentCell.SetDisplayEditorMatchingCondition(CellEditorDisplayConditions.CellIsCurrent); + } - private static Binding CreateViewPropertyBindingForSource( object source, DependencyProperty property, BindingMode bindingMode ) - { - Binding binding = new Binding(); - binding.Source = source; - binding.Path = new PropertyPath( property ); - binding.Mode = bindingMode; + newCurrentCell.SetIsCurrent(true); - return binding; - } + //Then, if the Current Cell has changed or not currently in edition, process the edition conditions. + if (currentCellChanged || !newCurrentCell.IsBeingEdited) + { + //if the EditTriggers dictate that we should enter edition, do it. + if ((newCurrentRow.IsEditTriggerSet(EditTriggers.CellIsCurrent)) + || ((newCurrentRow.IsEditTriggerSet(EditTriggers.RowIsCurrent)) && (currentRowChanged))) + { + try + { + newCurrentCell.BeginEdit(); + } + catch (DataGridException) + { + // We swallow the exception if it occurs because the Cell was read-only. + + // Try to begin edit only on the row + try + { + newCurrentRow.BeginEdit(); + } + catch (DataGridException) + { + // We swallow the exception if it occurs because the Row was read-only. + } + } + } + } + } - private static GroupLevelDescription GetGroupLevelDescription( GroupLevelDescriptionCollection groupLevelDescriptions, GroupDescription group ) - { - GroupLevelDescription retval = null; - string columnName = DataGridContext.GetColumnNameFromGroupDescription( group ); + //if there is a new CurrentItem + if (item != null) + { + //if the container from the new Current item is realized + if (newCurrentRow != null) + { + if (m_dataGridControl.IsBringIntoViewAllowed(trigger)) + { + if (!m_dataGridControl.IsBringIntoViewDelayed) + { + if (newCurrentCell != null) + { + newCurrentCell.BringIntoView(); + } + else + { + // Ensure the item is visible visible + newCurrentRow.BringIntoView(); + } + } + else + { + m_dataGridControl.DelayBringIntoViewAndFocusCurrent(trigger); + } + } + + using (m_dataGridControl.SelectionChangerManager.PushUpdateSelectionSource(SelectionManager.UpdateSelectionSource.None)) + { + // Call this to update the Focus to the correct location + m_dataGridControl.SetFocusHelper(newCurrentRow, column, forceFocus, true); + } + } + else + { + m_dataGridControl.DelayBringIntoViewAndFocusCurrent(trigger); + } + } - if( string.IsNullOrEmpty( columnName ) == false ) - { - foreach( GroupLevelDescription info in groupLevelDescriptions ) - { - if( info.FieldName == columnName ) - { - retval = info; - break; - } - } - } + //Send notification at the end (as much as possible) to ensure that no code bound on the property changed handler will interrupt this sequence - return retval; - } + if ((synchronizeSelectionWithCurrent) && (!m_dataGridControl.SelectionChangerManager.IsActive)) + { + m_dataGridControl.SelectionChangerManager.Begin(); - internal DefaultDetailConfiguration GetDefaultDetailConfigurationForContext() - { - if( this.AlreadySearchedForDefaultDetailConfig ) - return m_defaultDetailConfiguration; + try + { + if (m_dataGridControl.SelectionUnit == SelectionUnit.Row) + { + if (newCurrentContext.CurrentItemIndex == -1) + { + m_dataGridControl.SelectionChangerManager.UnselectAll(); + } + else + { + m_dataGridControl.SelectionChangerManager.SelectJustThisItem(this, newCurrentContext.CurrentItemIndex, newCurrentContext.CurrentItem); + } + } + else + { + int currentColumnVisibleIndex = (newCurrentContext.CurrentColumn == null) ? -1 : newCurrentContext.CurrentColumn.VisiblePosition; + + if ((currentColumnVisibleIndex == -1) || (newCurrentContext.CurrentItemIndex == -1)) + { + m_dataGridControl.SelectionChangerManager.UnselectAll(); + } + else + { + m_dataGridControl.SelectionChangerManager.SelectJustThisCell(this, newCurrentContext.CurrentItemIndex, newCurrentContext.CurrentItem, currentColumnVisibleIndex); + } + } + } + finally + { + m_dataGridControl.SelectionChangerManager.End(false, false); + } + } + + if (this.CurrentItem != oldPublicCurrentItem) + { + this.OnPropertyChanged("CurrentItem"); + } + + if (column != oldCurrentColumn) + { + this.OnPropertyChanged("CurrentColumn"); + } - m_defaultDetailConfiguration = null; - //start the loop with the current instance. - if( ( this.SourceDetailConfiguration != null ) && ( this.SourceDetailConfiguration.IsAutoCreated == true ) ) - { - DataGridContext currentContext = this; + if ((item != oldCurrentItem) || (oldCurrentContext != newCurrentContext)) + { + var currentChangedEventArgs = new DataGridCurrentChangedEventArgs(oldCurrentContext, oldCurrentItem, newCurrentContext, item); + m_dataGridControl.RaiseCurrentChanged(currentChangedEventArgs); + } + } + finally + { + m_dataGridControl.IsSetCurrentInProgress = false; + } + } - do + internal void SetupTitleBindingForGroupLevelDescriptions() { - DefaultDetailConfiguration defaultDetailConfig = currentContext.DefaultDetailConfiguration; - if( defaultDetailConfig != null ) - { - m_defaultDetailConfiguration = defaultDetailConfig; - break; - } + foreach (GroupLevelDescription gld in this.GroupLevelDescriptions) + { + Binding titleBinding = BindingOperations.GetBinding(gld, GroupLevelDescription.TitleProperty); - currentContext = currentContext.ParentDataGridContext; + if (titleBinding == null) + { + ColumnBase column = this.Columns[gld.FieldName]; + + if (column != null) + { + DataGridContext.SetupGroupLevelDescriptionBindings(gld, column); + } + } + } } - while( currentContext != null ); - } - this.AlreadySearchedForDefaultDetailConfig = true; - return m_defaultDetailConfiguration; - } + internal static void UpdateGroupLevelDescriptions(GroupLevelDescriptionCollection groupLevelDescriptions, + NotifyCollectionChangedEventArgs e, ObservableCollection groupDescriptions, ColumnCollection columns) + { + switch (e.Action) + { + case NotifyCollectionChangedAction.Add: + //add all the items added into the GroupLevelDescriptions collection + for (int i = 0; i < e.NewItems.Count; i++) + { + GroupLevelDescription newInfo = DataGridContext.CreateGroupLevelDescription(columns, (GroupDescription)e.NewItems[i]); - internal void GetRealizedItems( List containers ) - { - lock( containers ) - { - //obtain the IItemContainerGenerator interface of the ItemContainerGenerator (since called many places and it's bothering to always cast). - IItemContainerGenerator generator = this.CustomItemContainerGenerator; - //exception case, I wan to ask for the Generator Interface + groupLevelDescriptions.Insert(i + e.NewStartingIndex, newInfo); + } + break; - //obtain the GeneratorPosition from the last item in the items collection of the Itemscontrol, this will give me the number of items that are realized. - int itemCount = this.CustomItemContainerGenerator.ItemCount; + case NotifyCollectionChangedAction.Remove: + foreach (GroupDescription desc in e.OldItems) + { + GroupLevelDescription oldInfo = DataGridContext.GetGroupLevelDescription(groupLevelDescriptions, desc); - GeneratorPosition lastItemGenPos = generator.GeneratorPositionFromIndex( itemCount - 1 ); + if (oldInfo != null) + { + groupLevelDescriptions.Remove(oldInfo); + } + } + break; - //the index of the generator position of the last item will indicate the number of realized items. - for( int i = 0; i <= lastItemGenPos.Index; i++ ) - { - //To obtain the Container from the Generator, I need and Index, I can obtain an index from a GeneratorPosition - GeneratorPosition itemGenPos = new GeneratorPosition( i, 0 ); //items with offset == 0 are "realized items" - int itemIndex = generator.IndexFromGeneratorPosition( itemGenPos ); + case NotifyCollectionChangedAction.Reset: - object item = this.CustomItemContainerGenerator.ContainerFromIndex( itemIndex ); + groupLevelDescriptions.Clear(); - //add the container the the enumerable collection - containers.Add( item ); - } + foreach (GroupDescription desc in groupDescriptions) + { + GroupLevelDescription newInfo = DataGridContext.CreateGroupLevelDescription(columns, desc); - //exception case for the master DataGridContext, take the Fixed regions as well - if( m_detailConfig == null ) - { - Panel fixedPanel = m_dataGridControl.FixedHeadersHostPanel; - if( fixedPanel != null ) - { - foreach( object container in fixedPanel.Children ) - { - containers.Add( container ); - } - } + groupLevelDescriptions.Add(newInfo); + } - fixedPanel = m_dataGridControl.FixedFootersHostPanel; - if( fixedPanel != null ) - { - foreach( object container in fixedPanel.Children ) - { - containers.Add( container ); - } - } - } //end if Master DataGridContext + break; - } - } + case NotifyCollectionChangedAction.Move: - internal static void InsertColumnByVisiblePosition( HashedLinkedList linkedList, ColumnBase columnToInsert ) - { - int requestedPosition = columnToInsert.VisiblePosition; - LinkedListNode columnNode = linkedList.First; + GroupLevelDescription movedGroupLevelDescription = groupLevelDescriptions[e.OldStartingIndex]; + groupLevelDescriptions.RemoveAt(e.OldStartingIndex); + groupLevelDescriptions.Insert(e.NewStartingIndex, movedGroupLevelDescription); + + break; + + case NotifyCollectionChangedAction.Replace: + + groupLevelDescriptions.RemoveAt(e.OldStartingIndex); + GroupLevelDescription replaceInfo = DataGridContext.CreateGroupLevelDescription(columns, (GroupDescription)e.NewItems[0]); - LinkedListNode insertBeforeNode = null; - ColumnBase column = null; + groupLevelDescriptions.Insert(e.NewStartingIndex, replaceInfo); - // Append columns which VisiblePosition haven't explicitly set - if( columnToInsert.VisiblePosition == int.MaxValue ) - { - linkedList.AddLast( columnToInsert ); - return; - } + break; + } + } - if( linkedList.Count == 0 ) - { - linkedList.AddFirst( columnToInsert ); - } - else - { - while( columnNode != null ) + internal static DataGridContext SafeGetDataGridContextForDataGridCollectionView( + DataGridContext rootDataGridContext, + DataGridCollectionViewBase targetDataGridCollectionViewBase) { - column = columnNode.Value; + DataGridContext matchingDataGridContext = null; - if( column != null ) - { - if( column.VisiblePosition > requestedPosition ) + DataGridCollectionViewBase rootDataGridCollectionViewBase = rootDataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + + if (rootDataGridCollectionViewBase != null) { - // Insertion point found - insertBeforeNode = columnNode; - break; + if (rootDataGridCollectionViewBase == targetDataGridCollectionViewBase) + { + matchingDataGridContext = rootDataGridContext; + } + else + { + matchingDataGridContext = DataGridContext.SafeRecursiveGetDataGridContextForDataGridCollectionViewBase( + rootDataGridContext.GetChildContexts(), + targetDataGridCollectionViewBase); + } } - columnNode = columnNode.Next; - } + return matchingDataGridContext; } - if( insertBeforeNode != null ) + private static DataGridContext SafeRecursiveGetDataGridContextForDataGridCollectionViewBase( + IEnumerable childDataGridContexts, + DataGridCollectionViewBase targetDataGridCollectionViewBase) { - linkedList.AddBefore( insertBeforeNode, columnToInsert ); - insertBeforeNode = null; - } - else - { - linkedList.AddLast( columnToInsert ); - } - } - } + foreach (DataGridContext childDataGridContext in childDataGridContexts) + { + // Child DataGridContext's Items cannot be anything else than a DataGridCollectionView. + DataGridCollectionViewBase dataGridCollectionViewBase = (DataGridCollectionViewBase)childDataGridContext.Items; - private void MergeDistinctValues( DistinctValuesRequestedEventArgs args ) - { - Debug.Assert( this.Columns[ args.AutoFilterColumnFieldName ] != null ); + if (dataGridCollectionViewBase == targetDataGridCollectionViewBase) + return childDataGridContext; - var distinctValues = this.DistinctValues; - if( distinctValues == null ) - return; + // Deep down. + DataGridContext matchingDataGridContext = DataGridContext.SafeRecursiveGetDataGridContextForDataGridCollectionViewBase( + childDataGridContext.GetChildContexts(), + targetDataGridCollectionViewBase); - var readOnlyObservableHashList = default( ReadOnlyObservableHashList ); + if (matchingDataGridContext != null) + return matchingDataGridContext; + } - // We force the creation of DistinctValues for this field in every DataGridCollectionView - if( distinctValues.TryGetValue( args.AutoFilterColumnFieldName, out readOnlyObservableHashList ) ) - { - foreach( var item in readOnlyObservableHashList ) - { - args.DistinctValues.Add( item ); + return null; } - } - } - - private void OnGroupDescriptionsChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - this.DelayBringIntoViewAndFocusCurrent( AutoScrollCurrentItemSourceTriggers.GroupChanged ); - DataGridContext.UpdateGroupLevelDescriptions( this.GroupLevelDescriptions, e, this.Items.GroupDescriptions, this.Columns ); - } + private static void UnselectAllCells(DataGridContext dataGridContext) + { + if (dataGridContext == null) + return; - private void OnSortDescriptionsChanged( object sender, NotifyCollectionChangedEventArgs e ) - { - this.DelayBringIntoViewAndFocusCurrent( AutoScrollCurrentItemSourceTriggers.SortChanged ); + var selectionManager = dataGridContext.DataGridControl.SelectionChangerManager; + selectionManager.Begin(); - var updateColumnSortCommand = this.UpdateColumnSortCommand; - if( updateColumnSortCommand.CanExecute() ) - { - updateColumnSortCommand.Execute(); - } - } + try + { + selectionManager.UnselectAllCells(dataGridContext); + } + finally + { + selectionManager.End(false, false); + } + } - private static void SetupGroupLevelDescriptionBindings( GroupLevelDescription groupLevelDescription, ColumnBase column ) - { - //Bind the column title to the GroupLevelDescription title - Binding titleBinding = new Binding(); - titleBinding.Path = new PropertyPath( ColumnBase.TitleProperty ); - titleBinding.Source = column; - titleBinding.Mode = BindingMode.OneWay; - - //Bind the column title template to the GroupLevelDescription title template - Binding titleTemplateBinding = new Binding(); - titleTemplateBinding.Path = - new PropertyPath( ColumnBase.TitleTemplateProperty ); - titleTemplateBinding.Source = column; - titleTemplateBinding.Mode = BindingMode.OneWay; - - //Bind the column title template selector to the GroupLevelDescription title template selector - Binding titleTemplateSelectorBinding = new Binding(); - titleTemplateSelectorBinding.Path = - new PropertyPath( ColumnBase.TitleTemplateSelectorProperty ); - titleTemplateSelectorBinding.Source = column; - titleTemplateSelectorBinding.Mode = BindingMode.OneWay; - - Binding valueTemplateBinding = null; - Binding valueTemplateSelectorBinding = null; - Binding valueStringFormatBinding = null; - Binding valueStringFormatCultureBinding = null; - - Column dataColumn = column as Column; - - // If we have a Column and a ForeignKey is defined - if( ( dataColumn != null ) && ( dataColumn.ForeignKeyConfiguration != null ) ) - { - //Bind the column GroupValueTemplate to the GroupLevelDescription value template - valueTemplateBinding = new Binding(); - valueTemplateBinding.Source = dataColumn; - valueTemplateBinding.Path = new PropertyPath( "(0).(1)", - Column.ForeignKeyConfigurationProperty, - ForeignKeyConfiguration.DefaultGroupValueTemplateProperty ); - valueTemplateBinding.Mode = BindingMode.OneWay; - } - else - { - //Bind the column GroupValueTemplate to the GroupLevelDescription value template - valueTemplateBinding = new Binding(); - valueTemplateBinding.Path = new PropertyPath( ColumnBase.GroupValueTemplateProperty ); - valueTemplateBinding.Source = column; - valueTemplateBinding.Mode = BindingMode.OneWay; - - //Bind the column GroupValueTemplateSelector to the GroupLevelDescription value template selector - valueTemplateSelectorBinding = new Binding(); - valueTemplateSelectorBinding.Path = new PropertyPath( ColumnBase.GroupValueTemplateSelectorProperty ); - valueTemplateSelectorBinding.Source = column; - valueTemplateSelectorBinding.Mode = BindingMode.OneWay; - - //Bind the column GroupValueStringFormat to the GroupLevelDescription string format - valueStringFormatBinding = new Binding(); - valueStringFormatBinding.Path = new PropertyPath( ColumnBase.GroupValueStringFormatProperty ); - valueStringFormatBinding.Source = column; - valueStringFormatBinding.Mode = BindingMode.OneWay; - - //Bind the column DefaultCulture to the GroupLevelDescription string format culture - valueStringFormatCultureBinding = new Binding(); - valueStringFormatCultureBinding.Path = new PropertyPath( ColumnBase.DefaultCultureProperty ); - valueStringFormatCultureBinding.Source = column; - valueStringFormatCultureBinding.Mode = BindingMode.OneWay; - valueStringFormatCultureBinding.TargetNullValue = CultureInfo.CurrentCulture; - } - - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.TitleProperty, titleBinding ); - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.TitleTemplateProperty, titleTemplateBinding ); - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.TitleTemplateSelectorProperty, titleTemplateSelectorBinding ); - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.ValueTemplateProperty, valueTemplateBinding ); - - if( valueStringFormatBinding != null ) - { - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.ValueStringFormatProperty, valueStringFormatBinding ); - } - - if( valueStringFormatCultureBinding != null ) - { - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.ValueStringFormatCultureProperty, valueStringFormatCultureBinding ); - } - - if( valueTemplateSelectorBinding != null ) - { - BindingOperations.SetBinding( groupLevelDescription, GroupLevelDescription.ValueTemplateSelectorProperty, valueTemplateSelectorBinding ); - } - } + internal void SaveContainerSizeState(object item, FrameworkElement container) + { + if (item == null) + return; - private void HandleMasterColumnsCollectionChanged( NotifyCollectionChangedEventArgs e ) - { - var removeCurrentColumn = false; - var needGeneratorHardReset = false; - var currentColumn = this.CurrentColumn; + ContainerSizeState containerSizeState = new ContainerSizeState(container); - //If( e.Action == Add ), there is nothing to do. + if (containerSizeState.IsEmpty() == false) + { + m_sizeStateDictionary[item] = containerSizeState; - if( e.Action == NotifyCollectionChangedAction.Reset ) - { - var columns = this.Columns; + DataGridContext.CleanContainerSizeState(container, containerSizeState); + } + else + { + m_sizeStateDictionary.Remove(item); + } + } - removeCurrentColumn = ( columns == null ) || ( !columns.Contains( currentColumn ) ); - needGeneratorHardReset = true; - } - else if( e.Action == NotifyCollectionChangedAction.Remove ) - { - //Remove of at least the current column - if( e.OldItems.Contains( currentColumn ) ) + internal void RestoreContainerSizeState(object item, FrameworkElement container) { - removeCurrentColumn = true; - needGeneratorHardReset = true; + if (item == null) + return; + + ContainerSizeState containerSizeState; + if (m_sizeStateDictionary.TryGetValue(item, out containerSizeState) == true) + { + DataGridContext.RestoreContainerSizeWorker(container, containerSizeState); + } } - } - else if( e.Action == NotifyCollectionChangedAction.Replace ) - { - //Replace in which at least the current column was "replaced" by another (current column not present in new items ) - if( ( e.OldItems.Contains( currentColumn ) ) && ( !e.NewItems.Contains( currentColumn ) ) ) + + internal void ClearSizeStates() { - removeCurrentColumn = true; - needGeneratorHardReset = true; + m_sizeStateDictionary.Clear(); } - } - //Nothing to do because the way to change the visible position of a column is through its VisiblePosition property. - else if( e.Action == NotifyCollectionChangedAction.Move ) - { - return; - } - var closestColumn = default( ColumnBase ); + /// + /// Gets the current View property value for this DataGridContext. It can either come + /// from a local (attached) value or the value on the view (if the property is "routed"). + /// + /// The return value type of the requested property. + /// The property name on the View. + /// The value of the property if found. Will be ignored if the property is not found. + /// Returns true if the returnValue has been set. False otherwise. + internal bool GetViewPropertyValue(string propertyName, ref T returnValue) + { + object value = null; + + if (m_viewPropertiesDescriptors != null) + { + PropertyDescriptor descriptor = m_viewPropertiesDescriptors[propertyName]; - //Select the current column's closest visible column while its possible - if( removeCurrentColumn ) - { - closestColumn = DataGridContext.GetClosestColumn( currentColumn, this.ColumnsByVisiblePosition ); - } + if (descriptor != null) + value = descriptor.GetValue(this); + } - // When a column is removed, we need to clear the Generator from every container to avoid problems - // if the column is added again, but using a different instance (i.e. a new column with the same fieldname). - if( needGeneratorHardReset ) - { - // We only reset the fixed region if the column is part of the master context - if( this.SourceDetailConfiguration == null ) - { - this.DataGridControl.ResetFixedRegions(); + if (value != null) + { + returnValue = (T)value; + return true; + } + + return false; } - this.DataGridControl.CustomItemContainerGenerator.RemoveAllAndNotify(); - } - this.DefaultImageColumnDetermined = false; - var updateColumnSortCommand = this.UpdateColumnSortCommand; - if( updateColumnSortCommand.CanExecute() ) - { - this.UpdateColumnSortCommand.Execute(); - } + //---------- PRIVATE METHODS ---------- - if( removeCurrentColumn ) - { - // Now that the columns collections have been updated, it is time to set the new current column if necessary. - // The new current column that was identified earlier may have been removed from the visible columns after the collections update. - if( ( closestColumn != null ) && !this.Columns.Contains( closestColumn ) ) + private void ClearViewPropertyBindings() { - closestColumn = null; - } + foreach (Views.ViewBase.ViewPropertyStruct viewProperty in m_viewProperties) + { + BindingOperations.ClearBinding(this, viewProperty.DependencyProperty); + this.ClearValue(viewProperty.DependencyProperty); + } - this.SetCurrentColumnCore( closestColumn, false, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ColumnsCollectionChanged ); - } + m_viewProperties.Clear(); - ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurations( this.Columns, - this.ItemsSourceCollection, - m_itemsSourcePropertyDescriptions, - this.AutoCreateForeignKeyConfigurations ); - } + //Empty the list of ViewBindingPropertyDescriptor as well. + if (m_viewPropertiesDescriptors != null) + { + m_viewPropertiesDescriptors.Clear(); + m_viewPropertiesDescriptors = null; + } + } - internal static ColumnBase GetClosestColumn( ColumnBase reference, HashedLinkedList columnsByVisiblePosition ) - { - LinkedListNode oldColumnNode = columnsByVisiblePosition.Find( reference ); + private static GroupLevelDescription CreateGroupLevelDescription(ColumnCollection columns, GroupDescription group) + { + GroupLevelDescription retval = null; + string columnName = DataGridContext.GetColumnNameFromGroupDescription(group); - ColumnBase newColumn = null; + if (!string.IsNullOrEmpty(columnName)) + { + retval = new GroupLevelDescription(group, columnName); - if( oldColumnNode != null ) - { - LinkedListNode newColumnNode = oldColumnNode.Previous; + //find the column for that property name + ColumnBase column = columns[columnName]; - if( newColumnNode == null ) - { - newColumnNode = oldColumnNode.Next; + if (column != null) + { + DataGridContext.SetupGroupLevelDescriptionBindings(retval, column); + } + else + { + //if no column exists for that name, then use the name as the Title for the GroupLevelDescription + retval.SetTitle(columnName); + } + } + + return retval; } - if( newColumnNode != null ) + private Binding CreateViewPropertyBinding(Views.ViewBase view, Views.ViewBase.ViewPropertyStruct viewProperty) { - newColumn = newColumnNode.Value; - } - } + var dependencyProperty = viewProperty.DependencyProperty; - return newColumn; - } + if (this.IsAFlattenDetail) + { + switch (viewProperty.FlattenDetailBindingMode) + { + case FlattenDetailBindingMode.None: + return null; + + case FlattenDetailBindingMode.MasterOneWay: + { + var rootDataGridContext = this.RootDataGridContext; + Debug.Assert((rootDataGridContext != null) && (this != rootDataGridContext)); + return DataGridContext.CreateViewPropertyBindingForSource(rootDataGridContext, dependencyProperty, BindingMode.OneWay); + } + + default: + break; + } + } - private void SetupViewProperties() - { - this.ClearViewPropertyBindings(); + if (viewProperty.ViewPropertyMode == ViewPropertyMode.ViewOnly) + return DataGridContext.CreateViewPropertyBindingForSource(view, dependencyProperty); - Views.ViewBase view = m_dataGridControl.GetView(); - if( view == null ) - return; + var detailConfiguration = this.SourceDetailConfiguration; + if (detailConfiguration != null) + { + var defaultDetailConfiguration = this.GetDefaultDetailConfigurationForContext(); + if (defaultDetailConfiguration != null) + return DataGridContext.CreateViewPropertyBindingForSource(defaultDetailConfiguration, dependencyProperty); - var viewProperties = view.GetViewProperties() - .Concat( view.GetSharedProperties() ) - .Concat( view.GetSharedNoFallbackProperties() ); + return DataGridContext.CreateViewPropertyBindingForSource(detailConfiguration, dependencyProperty); + } - foreach( var viewProperty in viewProperties ) - { - var dependencyProperty = viewProperty.DependencyProperty; - Debug.Assert( !dependencyProperty.ReadOnly ); + return DataGridContext.CreateViewPropertyBindingForSource(view, dependencyProperty); + } - Binding binding = this.CreateViewPropertyBinding( view, viewProperty ); - if( binding != null ) + private static Binding CreateViewPropertyBindingForSource(object source, DependencyProperty property) { - BindingOperations.SetBinding( this, dependencyProperty, binding ); + return DataGridContext.CreateViewPropertyBindingForSource(source, property, BindingMode.TwoWay); } - //Note: we place the shared and non-shared properties in the same pool (makes no differences beyond this point ). - m_viewProperties.Add( viewProperty ); + private static Binding CreateViewPropertyBindingForSource(object source, DependencyProperty property, BindingMode bindingMode) + { + Binding binding = new Binding(); + binding.Source = source; + binding.Path = new PropertyPath(property); + binding.Mode = bindingMode; - this.OnPropertyChanged( dependencyProperty.Name ); - } - } + return binding; + } - private void InitializeViewProperties() - { - if( !this.IsAFlattenDetail ) - { - TableflowView.SetFixedColumnSplitterTranslation( this, new TranslateTransform() ); - } - } + private static GroupLevelDescription GetGroupLevelDescription(GroupLevelDescriptionCollection groupLevelDescriptions, GroupDescription group) + { + GroupLevelDescription retval = null; + string columnName = DataGridContext.GetColumnNameFromGroupDescription(group); - private void HookToItemPropertiesChanged() - { - var collectionView = this.ItemsSourceCollection as DataGridCollectionViewBase; - if( collectionView == null ) - return; + if (string.IsNullOrEmpty(columnName) == false) + { + foreach (GroupLevelDescription info in groupLevelDescriptions) + { + if (info.FieldName == columnName) + { + retval = info; + break; + } + } + } - this.RegisterItemProperties( collectionView.ItemProperties ); - } + return retval; + } - private void UnhookToItemPropertiesChanged( DataGridCollectionViewBase collectionView ) - { - if( collectionView == null ) - return; + internal DefaultDetailConfiguration GetDefaultDetailConfigurationForContext() + { + if (this.AlreadySearchedForDefaultDetailConfig) + return m_defaultDetailConfiguration; - this.UnregisterItemProperties( collectionView.ItemProperties ); - } + m_defaultDetailConfiguration = null; + //start the loop with the current instance. + if ((this.SourceDetailConfiguration != null) && (this.SourceDetailConfiguration.IsAutoCreated == true)) + { + DataGridContext currentContext = this; - private void UpdateColumns() - { - Debug.Assert( m_detailConfig == null ); + do + { + DefaultDetailConfiguration defaultDetailConfig = currentContext.DefaultDetailConfiguration; + if (defaultDetailConfig != null) + { + m_defaultDetailConfiguration = defaultDetailConfig; + break; + } - ItemsSourceHelper.ResetPropertyDescriptions( m_itemsSourcePropertyDescriptions, m_itemPropertyMap, m_dataGridControl, m_dataGridControlItemsSource ); + currentContext = currentContext.ParentDataGridContext; + } + while (currentContext != null); + } - if( m_dataGridControl.AutoCreateColumns ) - { - ItemsSourceHelper.UpdateColumnsFromPropertyDescriptions( m_columnManager, m_dataGridControl.DefaultCellEditors, m_itemsSourcePropertyDescriptions, this.AutoCreateForeignKeyConfigurations ); - } - } + this.AlreadySearchedForDefaultDetailConfig = true; + return m_defaultDetailConfiguration; + } - private void RegisterItemProperties( DataGridItemPropertyCollection itemProperties ) - { - if( itemProperties == null ) - return; + internal void GetRealizedItems(List containers) + { + lock (containers) + { + //obtain the IItemContainerGenerator interface of the ItemContainerGenerator (since called many places and it's bothering to always cast). + IItemContainerGenerator generator = this.CustomItemContainerGenerator; + //exception case, I wan to ask for the Generator Interface - CollectionChangedEventManager.AddListener( itemProperties, this ); + //obtain the GeneratorPosition from the last item in the items collection of the Itemscontrol, this will give me the number of items that are realized. + int itemCount = this.CustomItemContainerGenerator.ItemCount; - foreach( var itemProperty in itemProperties ) - { - this.RegisterItemProperty( itemProperty ); - } - } + GeneratorPosition lastItemGenPos = generator.GeneratorPositionFromIndex(itemCount - 1); - private void UnregisterItemProperties( DataGridItemPropertyCollection itemProperties ) - { - if( itemProperties == null ) - return; + //the index of the generator position of the last item will indicate the number of realized items. + for (int i = 0; i <= lastItemGenPos.Index; i++) + { + //To obtain the Container from the Generator, I need and Index, I can obtain an index from a GeneratorPosition + GeneratorPosition itemGenPos = new GeneratorPosition(i, 0); //items with offset == 0 are "realized items" + int itemIndex = generator.IndexFromGeneratorPosition(itemGenPos); - foreach( var itemProperty in itemProperties ) - { - this.UnregisterItemProperty( itemProperty ); - } + object item = this.CustomItemContainerGenerator.ContainerFromIndex(itemIndex); - CollectionChangedEventManager.RemoveListener( itemProperties, this ); - } + //add the container the the enumerable collection + containers.Add(item); + } - private void RegisterItemProperty( DataGridItemPropertyBase itemProperty ) - { - if( itemProperty == null ) - return; + //exception case for the master DataGridContext, take the Fixed regions as well + if (m_detailConfig == null) + { + Panel fixedPanel = m_dataGridControl.FixedHeadersHostPanel; + if (fixedPanel != null) + { + foreach (object container in fixedPanel.Children) + { + containers.Add(container); + } + } - PropertyChangedEventManager.AddListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); - this.RegisterItemProperties( itemProperty.ItemPropertiesInternal ); - } + fixedPanel = m_dataGridControl.FixedFootersHostPanel; + if (fixedPanel != null) + { + foreach (object container in fixedPanel.Children) + { + containers.Add(container); + } + } + } //end if Master DataGridContext - private void UnregisterItemProperty( DataGridItemPropertyBase itemProperty ) - { - if( itemProperty == null ) - return; + } + } - this.UnregisterItemProperties( itemProperty.ItemPropertiesInternal ); - PropertyChangedEventManager.RemoveListener( itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ); - } + internal static void InsertColumnByVisiblePosition(HashedLinkedList linkedList, ColumnBase columnToInsert) + { + int requestedPosition = columnToInsert.VisiblePosition; + LinkedListNode columnNode = linkedList.First; - private void OnItemPropertiesCollectionChanged( DataGridItemPropertyCollection collection, NotifyCollectionChangedEventArgs e ) - { - Debug.Assert( m_detailConfig == null ); + LinkedListNode insertBeforeNode = null; + ColumnBase column = null; + + // Append columns which VisiblePosition haven't explicitly set + if (columnToInsert.VisiblePosition == int.MaxValue) + { + linkedList.AddLast(columnToInsert); + return; + } + + if (linkedList.Count == 0) + { + linkedList.AddFirst(columnToInsert); + } + else + { + while (columnNode != null) + { + column = columnNode.Value; + + if (column != null) + { + if (column.VisiblePosition > requestedPosition) + { + // Insertion point found + insertBeforeNode = columnNode; + break; + } + + columnNode = columnNode.Next; + } + } + + if (insertBeforeNode != null) + { + linkedList.AddBefore(insertBeforeNode, columnToInsert); + insertBeforeNode = null; + } + else + { + linkedList.AddLast(columnToInsert); + } + } + } - var rootCollection = ItemsSourceHelper.GetRootCollection( collection ); - if( rootCollection == null ) - return; + private void MergeDistinctValues(DistinctValuesRequestedEventArgs args) + { + Debug.Assert(this.Columns[args.AutoFilterColumnFieldName] != null); - if( rootCollection == ( ( DataGridCollectionViewBase )m_dataGridControlItemsSource ).ItemProperties ) - { - if( e.Action == NotifyCollectionChangedAction.Reset ) - throw new NotSupportedException(); + var distinctValues = this.DistinctValues; + if (distinctValues == null) + return; - if( e.Action == NotifyCollectionChangedAction.Move ) - return; + var readOnlyObservableHashList = default(ReadOnlyObservableHashList); - if( e.OldItems != null ) + // We force the creation of DistinctValues for this field in every DataGridCollectionView + if (distinctValues.TryGetValue(args.AutoFilterColumnFieldName, out readOnlyObservableHashList)) + { + foreach (var item in readOnlyObservableHashList) + { + args.DistinctValues.Add(item); + } + } + } + + private void OnGroupDescriptionsChanged(object sender, NotifyCollectionChangedEventArgs e) { - foreach( DataGridItemPropertyBase itemProperty in e.OldItems ) - { - this.UnregisterItemProperty( itemProperty ); - } + this.DelayBringIntoViewAndFocusCurrent(AutoScrollCurrentItemSourceTriggers.GroupChanged); + + DataGridContext.UpdateGroupLevelDescriptions(this.GroupLevelDescriptions, e, this.Items.GroupDescriptions, this.Columns); } - if( e.NewItems != null ) + private void OnSortDescriptionsChanged(object sender, NotifyCollectionChangedEventArgs e) { - foreach( DataGridItemPropertyBase itemProperty in e.NewItems ) - { - this.RegisterItemProperty( itemProperty ); - } + this.DelayBringIntoViewAndFocusCurrent(AutoScrollCurrentItemSourceTriggers.SortChanged); + + var updateColumnSortCommand = this.UpdateColumnSortCommand; + if (updateColumnSortCommand.CanExecute()) + { + updateColumnSortCommand.Execute(); + } } - this.UpdateColumns(); - } - else - { - Debug.Fail( "The collection is not linked to the collection view's item properties." ); - this.UnregisterItemProperties( collection ); - } - } + private static void SetupGroupLevelDescriptionBindings(GroupLevelDescription groupLevelDescription, ColumnBase column) + { + //Bind the column title to the GroupLevelDescription title + Binding titleBinding = new Binding(); + titleBinding.Path = new PropertyPath(ColumnBase.TitleProperty); + titleBinding.Source = column; + titleBinding.Mode = BindingMode.OneWay; + + //Bind the column title template to the GroupLevelDescription title template + Binding titleTemplateBinding = new Binding(); + titleTemplateBinding.Path = + new PropertyPath(ColumnBase.TitleTemplateProperty); + titleTemplateBinding.Source = column; + titleTemplateBinding.Mode = BindingMode.OneWay; + + //Bind the column title template selector to the GroupLevelDescription title template selector + Binding titleTemplateSelectorBinding = new Binding(); + titleTemplateSelectorBinding.Path = + new PropertyPath(ColumnBase.TitleTemplateSelectorProperty); + titleTemplateSelectorBinding.Source = column; + titleTemplateSelectorBinding.Mode = BindingMode.OneWay; + + Binding valueTemplateBinding = null; + Binding valueTemplateSelectorBinding = null; + Binding valueStringFormatBinding = null; + Binding valueStringFormatCultureBinding = null; + + Column dataColumn = column as Column; + + // If we have a Column and a ForeignKey is defined + if ((dataColumn != null) && (dataColumn.ForeignKeyConfiguration != null)) + { + //Bind the column GroupValueTemplate to the GroupLevelDescription value template + valueTemplateBinding = new Binding(); + valueTemplateBinding.Source = dataColumn; + valueTemplateBinding.Path = new PropertyPath("(0).(1)", + Column.ForeignKeyConfigurationProperty, + ForeignKeyConfiguration.DefaultGroupValueTemplateProperty); + valueTemplateBinding.Mode = BindingMode.OneWay; + } + else + { + //Bind the column GroupValueTemplate to the GroupLevelDescription value template + valueTemplateBinding = new Binding(); + valueTemplateBinding.Path = new PropertyPath(ColumnBase.GroupValueTemplateProperty); + valueTemplateBinding.Source = column; + valueTemplateBinding.Mode = BindingMode.OneWay; + + //Bind the column GroupValueTemplateSelector to the GroupLevelDescription value template selector + valueTemplateSelectorBinding = new Binding(); + valueTemplateSelectorBinding.Path = new PropertyPath(ColumnBase.GroupValueTemplateSelectorProperty); + valueTemplateSelectorBinding.Source = column; + valueTemplateSelectorBinding.Mode = BindingMode.OneWay; + + //Bind the column GroupValueStringFormat to the GroupLevelDescription string format + valueStringFormatBinding = new Binding(); + valueStringFormatBinding.Path = new PropertyPath(ColumnBase.GroupValueStringFormatProperty); + valueStringFormatBinding.Source = column; + valueStringFormatBinding.Mode = BindingMode.OneWay; + + //Bind the column DefaultCulture to the GroupLevelDescription string format culture + valueStringFormatCultureBinding = new Binding(); + valueStringFormatCultureBinding.Path = new PropertyPath(ColumnBase.DefaultCultureProperty); + valueStringFormatCultureBinding.Source = column; + valueStringFormatCultureBinding.Mode = BindingMode.OneWay; + valueStringFormatCultureBinding.TargetNullValue = CultureInfo.CurrentCulture; + } - private void OnItemPropertyPropertyChanged( DataGridItemPropertyBase itemProperty, PropertyChangedEventArgs e ) - { - Debug.Assert( m_detailConfig == null ); + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.TitleProperty, titleBinding); + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.TitleTemplateProperty, titleTemplateBinding); + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.TitleTemplateSelectorProperty, titleTemplateSelectorBinding); + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.ValueTemplateProperty, valueTemplateBinding); - var rootCollection = ItemsSourceHelper.GetRootCollection( itemProperty ); - if( rootCollection == null ) - return; + if (valueStringFormatBinding != null) + { + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.ValueStringFormatProperty, valueStringFormatBinding); + } - if( rootCollection != ( ( DataGridCollectionViewBase )m_dataGridControlItemsSource ).ItemProperties ) - { - Debug.Fail( "The collection is not linked to the detail configuration's item properties." ); - this.UnregisterItemProperty( itemProperty ); - return; - } + if (valueStringFormatCultureBinding != null) + { + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.ValueStringFormatCultureProperty, valueStringFormatCultureBinding); + } - if( string.IsNullOrEmpty( e.PropertyName ) || ( e.PropertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName ) ) - { - var itemProperties = itemProperty.ItemPropertiesInternal; - if( itemProperties != null ) + if (valueTemplateSelectorBinding != null) + { + BindingOperations.SetBinding(groupLevelDescription, GroupLevelDescription.ValueTemplateSelectorProperty, valueTemplateSelectorBinding); + } + } + + private void HandleMasterColumnsCollectionChanged(NotifyCollectionChangedEventArgs e) { - this.UnregisterItemProperties( itemProperties ); - this.RegisterItemProperties( itemProperties ); - this.UpdateColumns(); + var removeCurrentColumn = false; + var needGeneratorHardReset = false; + var currentColumn = this.CurrentColumn; + + //If( e.Action == Add ), there is nothing to do. + + if (e.Action == NotifyCollectionChangedAction.Reset) + { + var columns = this.Columns; + + removeCurrentColumn = (columns == null) || (!columns.Contains(currentColumn)); + needGeneratorHardReset = true; + } + else if (e.Action == NotifyCollectionChangedAction.Remove) + { + //Remove of at least the current column + if (e.OldItems.Contains(currentColumn)) + { + removeCurrentColumn = true; + needGeneratorHardReset = true; + } + } + else if (e.Action == NotifyCollectionChangedAction.Replace) + { + //Replace in which at least the current column was "replaced" by another (current column not present in new items ) + if ((e.OldItems.Contains(currentColumn)) && (!e.NewItems.Contains(currentColumn))) + { + removeCurrentColumn = true; + needGeneratorHardReset = true; + } + } + //Nothing to do because the way to change the visible position of a column is through its VisiblePosition property. + else if (e.Action == NotifyCollectionChangedAction.Move) + { + return; + } + + var closestColumn = default(ColumnBase); + + //Select the current column's closest visible column while its possible + if (removeCurrentColumn) + { + closestColumn = DataGridContext.GetClosestColumn(currentColumn, this.ColumnsByVisiblePosition); + } + + // When a column is removed, we need to clear the Generator from every container to avoid problems + // if the column is added again, but using a different instance (i.e. a new column with the same fieldname). + if (needGeneratorHardReset) + { + // We only reset the fixed region if the column is part of the master context + if (this.SourceDetailConfiguration == null) + { + this.DataGridControl.ResetFixedRegions(); + } + + this.DataGridControl.CustomItemContainerGenerator.RemoveAllAndNotify(); + } + + this.DefaultImageColumnDetermined = false; + + var updateColumnSortCommand = this.UpdateColumnSortCommand; + if (updateColumnSortCommand.CanExecute()) + { + this.UpdateColumnSortCommand.Execute(); + } + + if (removeCurrentColumn) + { + // Now that the columns collections have been updated, it is time to set the new current column if necessary. + // The new current column that was identified earlier may have been removed from the visible columns after the collections update. + if ((closestColumn != null) && !this.Columns.Contains(closestColumn)) + { + closestColumn = null; + } + + this.SetCurrentColumnCore(closestColumn, false, m_dataGridControl.SynchronizeSelectionWithCurrent, AutoScrollCurrentItemSourceTriggers.ColumnsCollectionChanged); + } + + ForeignKeyConfiguration.UpdateColumnsForeignKeyConfigurations(this.Columns, + this.ItemsSourceCollection, + m_itemsSourcePropertyDescriptions, + this.AutoCreateForeignKeyConfigurations); } - } - } - private void OnDetailConfigRequestingDelayBringIntoViewAndFocusCurrent( object sender, RequestingDelayBringIntoViewAndFocusCurrentEventArgs e ) - { - if( !this.IsCurrent ) - return; + internal static ColumnBase GetClosestColumn(ColumnBase reference, HashedLinkedList columnsByVisiblePosition) + { + LinkedListNode oldColumnNode = columnsByVisiblePosition.Find(reference); - this.DelayBringIntoViewAndFocusCurrent( e.Trigger ); - } + ColumnBase newColumn = null; - private static void CleanContainerSizeState( FrameworkElement container, ContainerSizeState containerSizeState ) - { - if( containerSizeState.Height != DependencyProperty.UnsetValue ) - container.ClearValue( FrameworkElement.HeightProperty ); + if (oldColumnNode != null) + { + LinkedListNode newColumnNode = oldColumnNode.Previous; - if( containerSizeState.Width != DependencyProperty.UnsetValue ) - container.ClearValue( FrameworkElement.WidthProperty ); + if (newColumnNode == null) + { + newColumnNode = oldColumnNode.Next; + } - if( containerSizeState.MinHeight != DependencyProperty.UnsetValue ) - container.ClearValue( FrameworkElement.MinHeightProperty ); + if (newColumnNode != null) + { + newColumn = newColumnNode.Value; + } + } - if( containerSizeState.MinWidth != DependencyProperty.UnsetValue ) - container.ClearValue( FrameworkElement.MinWidthProperty ); + return newColumn; + } - if( containerSizeState.MaxHeight != DependencyProperty.UnsetValue ) - container.ClearValue( FrameworkElement.MaxHeightProperty ); + private void SetupViewProperties() + { + this.ClearViewPropertyBindings(); - if( containerSizeState.MaxWidth != DependencyProperty.UnsetValue ) - container.ClearValue( FrameworkElement.MaxWidthProperty ); - } + Views.ViewBase view = m_dataGridControl.GetView(); + if (view == null) + return; - private static void RestoreContainerSizeWorker( FrameworkElement container, ContainerSizeState sizeState ) - { - if( sizeState.Height != DependencyProperty.UnsetValue ) - container.SetValue( FrameworkElement.HeightProperty, sizeState.Height ); + var viewProperties = view.GetViewProperties() + .Concat(view.GetSharedProperties()) + .Concat(view.GetSharedNoFallbackProperties()); - if( sizeState.Width != DependencyProperty.UnsetValue ) - container.SetValue( FrameworkElement.WidthProperty, sizeState.Width ); + foreach (var viewProperty in viewProperties) + { + var dependencyProperty = viewProperty.DependencyProperty; + Debug.Assert(!dependencyProperty.ReadOnly); - if( sizeState.MinHeight != DependencyProperty.UnsetValue ) - container.SetValue( FrameworkElement.MinHeightProperty, sizeState.MinHeight ); + Binding binding = this.CreateViewPropertyBinding(view, viewProperty); + if (binding != null) + { + BindingOperations.SetBinding(this, dependencyProperty, binding); + } - if( sizeState.MinWidth != DependencyProperty.UnsetValue ) - container.SetValue( FrameworkElement.MinWidthProperty, sizeState.MinWidth ); + //Note: we place the shared and non-shared properties in the same pool (makes no differences beyond this point ). + m_viewProperties.Add(viewProperty); - if( sizeState.MaxHeight != DependencyProperty.UnsetValue ) - container.SetValue( FrameworkElement.MaxHeightProperty, sizeState.MaxHeight ); + this.OnPropertyChanged(dependencyProperty.Name); + } + } - if( sizeState.MaxWidth != DependencyProperty.UnsetValue ) - container.SetValue( FrameworkElement.MaxWidthProperty, sizeState.MaxWidth ); - } + private void InitializeViewProperties() + { + if (!this.IsAFlattenDetail) + { + TableflowView.SetFixedColumnSplitterTranslation(this, new TranslateTransform()); + } + } - //---------- OVERRIDES ---------- + private void HookToItemPropertiesChanged() + { + var collectionView = this.ItemsSourceCollection as DataGridCollectionViewBase; + if (collectionView == null) + return; - protected override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) - { - base.OnPropertyChanged( e ); - this.OnPropertyChanged( e.Property.Name ); - } + this.RegisterItemProperties(collectionView.ItemProperties); + } - //---------- INTERFACES ---------- + private void UnhookToItemPropertiesChanged(DataGridCollectionViewBase collectionView) + { + if (collectionView == null) + return; - #region INotifyPropertyChanged Members + this.UnregisterItemProperties(collectionView.ItemProperties); + } - public event PropertyChangedEventHandler PropertyChanged; + private void UpdateColumns() + { + Debug.Assert(m_detailConfig == null); - private void OnPropertyChanged( string propertyName ) - { - var handler = this.PropertyChanged; - if( handler == null ) - return; + ItemsSourceHelper.ResetPropertyDescriptions(m_itemsSourcePropertyDescriptions, m_itemPropertyMap, m_dataGridControl, m_dataGridControlItemsSource); - handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); - } + if (m_dataGridControl.AutoCreateColumns) + { + ItemsSourceHelper.UpdateColumnsFromPropertyDescriptions(m_columnManager, m_dataGridControl.DefaultCellEditors, m_itemsSourcePropertyDescriptions, this.AutoCreateForeignKeyConfigurations); + } + } + + private void RegisterItemProperties(DataGridItemPropertyCollection itemProperties) + { + if (itemProperties == null) + return; - #endregion + CollectionChangedEventManager.AddListener(itemProperties, this); - #region IWeakEventListener Members + foreach (var itemProperty in itemProperties) + { + this.RegisterItemProperty(itemProperty); + } + } - bool IWeakEventListener.ReceiveWeakEvent( Type managerType, object sender, EventArgs e ) - { - return this.OnReceiveWeakEvent( managerType, sender, e ); - } + private void UnregisterItemProperties(DataGridItemPropertyCollection itemProperties) + { + if (itemProperties == null) + return; - private bool OnReceiveWeakEvent( Type managerType, object sender, EventArgs e ) - { - if( managerType == typeof( CollectionChangedEventManager ) ) - { - var eventArgs = ( NotifyCollectionChangedEventArgs )e; + foreach (var itemProperty in itemProperties) + { + this.UnregisterItemProperty(itemProperty); + } - if( sender == m_items ) + CollectionChangedEventManager.RemoveListener(itemProperties, this); + } + + private void RegisterItemProperty(DataGridItemPropertyBase itemProperty) { - var args = eventArgs.GetRangeActionOrSelf(); + if (itemProperty == null) + return; - this.Items_CollectionChanged( sender, args ); + PropertyChangedEventManager.AddListener(itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName); + this.RegisterItemProperties(itemProperty.ItemPropertiesInternal); } - if( sender == this.DetailConfigurations ) + + private void UnregisterItemProperty(DataGridItemPropertyBase itemProperty) { - this.OnPropertyChanged( "HasDetails" ); + if (itemProperty == null) + return; + + this.UnregisterItemProperties(itemProperty.ItemPropertiesInternal); + PropertyChangedEventManager.RemoveListener(itemProperty, this, DataGridItemPropertyBase.ItemPropertiesInternalPropertyName); } - else if( sender == m_columnManager.Columns ) + + private void OnItemPropertiesCollectionChanged(DataGridItemPropertyCollection collection, NotifyCollectionChangedEventArgs e) { - //Master Level columns collection changed - this.HandleMasterColumnsCollectionChanged( eventArgs ); + Debug.Assert(m_detailConfig == null); + + var rootCollection = ItemsSourceHelper.GetRootCollection(collection); + if (rootCollection == null) + return; + + if (rootCollection == ((DataGridCollectionViewBase)m_dataGridControlItemsSource).ItemProperties) + { + if (e.Action == NotifyCollectionChangedAction.Reset) + throw new NotSupportedException(); + + if (e.Action == NotifyCollectionChangedAction.Move) + return; + + if (e.OldItems != null) + { + foreach (DataGridItemPropertyBase itemProperty in e.OldItems) + { + this.UnregisterItemProperty(itemProperty); + } + } + + if (e.NewItems != null) + { + foreach (DataGridItemPropertyBase itemProperty in e.NewItems) + { + this.RegisterItemProperty(itemProperty); + } + } + + this.UpdateColumns(); + } + else + { + Debug.Fail("The collection is not linked to the collection view's item properties."); + this.UnregisterItemProperties(collection); + } } - else if( sender == this.VisibleColumns ) + + private void OnItemPropertyPropertyChanged(DataGridItemPropertyBase itemProperty, PropertyChangedEventArgs e) { - var mode = ColumnStretchMode.None; + Debug.Assert(m_detailConfig == null); - if( this.GetViewPropertyValue( "ColumnStretchMode", ref mode ) ) - { - if( ( mode == ColumnStretchMode.First ) || ( mode == ColumnStretchMode.Last ) ) + var rootCollection = ItemsSourceHelper.GetRootCollection(itemProperty); + if (rootCollection == null) + return; + + if (rootCollection != ((DataGridCollectionViewBase)m_dataGridControlItemsSource).ItemProperties) { - if( eventArgs.NewItems != null ) - { - foreach( ColumnBase column in eventArgs.NewItems ) + Debug.Fail("The collection is not linked to the detail configuration's item properties."); + this.UnregisterItemProperty(itemProperty); + return; + } + + if (string.IsNullOrEmpty(e.PropertyName) || (e.PropertyName == DataGridItemPropertyBase.ItemPropertiesInternalPropertyName)) + { + var itemProperties = itemProperty.ItemPropertiesInternal; + if (itemProperties != null) { - column.ClearValue( ColumnBase.DesiredWidthProperty ); + this.UnregisterItemProperties(itemProperties); + this.RegisterItemProperties(itemProperties); + this.UpdateColumns(); } - } - } - } - } - else if( sender == m_items.SortDescriptions ) - { - this.OnSortDescriptionsChanged( sender, eventArgs ); - } - else if( sender == m_items.GroupDescriptions ) - { - this.OnGroupDescriptionsChanged( sender, eventArgs ); - } - else if( sender is DataGridItemPropertyCollection ) - { - this.OnItemPropertiesCollectionChanged( ( DataGridItemPropertyCollection )sender, eventArgs ); - } - } - else if( managerType == typeof( PropertyChangedEventManager ) ) - { - var eventArgs = ( PropertyChangedEventArgs )e; - - if( sender is DataGridItemPropertyBase ) - { - this.OnItemPropertyPropertyChanged( ( DataGridItemPropertyBase )sender, eventArgs ); - } - } - else if( managerType == typeof( ColumnsLayoutChangingEventManager ) ) - { - DataGridContext.UnselectAllCells( this ); - } - else if( managerType == typeof( ColumnsLayoutChangedEventManager ) ) - { - // Only force a reset if at least one Row has not used an IVirtualizingCellsHost as PART_CellsHost - if( m_dataGridControl.ForceGeneratorReset ) - { - //forces the collection view to refresh (therefore, regenerates all the items ). - this.CustomItemContainerGenerator.RemoveAllAndNotify(); - - if( this.SourceDetailConfiguration == null ) // not linked to a DetailConfiguration (master level) - { - //also notify the DataGridControl so it can clear the fixed regions - m_dataGridControl.ResetFixedRegions(); - } - } - - this.DefaultImageColumnDetermined = false; - } - else if( managerType == typeof( PreBatchCollectionChangedEventManager ) ) - { - Debug.Assert( m_deferSelectionChangedOnItemsCollectionChanged == null ); - - // When using DataGridVirtualizingCollectionViewBase, we should keep the "Replace" action - // in order to call UpdateSelectionAfterSourceCollectionChanged with a Replace instead of a Reset. - if( m_deferSelectionChangedOnItemsCollectionChanged == null && !( sender is DataGridVirtualizingCollectionViewBase ) ) - { - m_deferSelectionChangedOnItemsCollectionChanged = new DeferSelectionChangedOnItemsCollectionChangedDisposable( this ); - } - } - else if( managerType == typeof( PostBatchCollectionChangedEventManager ) ) - { - var disposable = m_deferSelectionChangedOnItemsCollectionChanged; - if( disposable != null ) - { - m_deferSelectionChangedOnItemsCollectionChanged = null; - disposable.Dispose(); - } - } - else if( managerType == typeof( RealizedContainersRequestedEventManager ) ) - { - var eventArgs = ( RealizedContainersRequestedEventArgs )e; - this.GetRealizedItems( eventArgs.RealizedContainers ); - } - else if( managerType == typeof( DistinctValuesRequestedEventManager ) ) - { - var eventArgs = ( DistinctValuesRequestedEventArgs )e; - this.MergeDistinctValues( eventArgs ); - } - else if( managerType == typeof( AllowDetailToggleChangedEventManager ) ) - { - this.OnPropertyChanged( "AllowDetailToggle" ); - } - else if( managerType == typeof( ViewChangedEventManager ) ) - { - this.SetupViewProperties(); - this.InitializeViewProperties(); - } - else if( managerType == typeof( CurrentColumnChangedEventManager ) ) - { - this.OnPropertyChanged( "CurrentColumn" ); - } - else if( managerType == typeof( GroupConfigurationSelectorChangedEventManager ) ) - { - this.OnGroupConfigurationSelectorChanged(); - } - else if( managerType == typeof( DetailVisibilityChangedEventManager ) ) - { - this.OnPropertyChanged( "HasDetails" ); - } - else if( managerType == typeof( MaxGroupLevelsChangedEventManager ) ) - { - this.OnPropertyChanged( "MaxGroupLevels" ); - } - else if( managerType == typeof( MaxSortLevelsChangedEventManager ) ) - { - this.OnPropertyChanged( "MaxSortLevels" ); - } - else if( managerType == typeof( ItemsSourceChangeCompletedEventManager ) ) - { - var dataGridCollectionViewBase = m_dataGridControlItemsSource as DataGridCollectionViewBase; - - // GenerateColumnsFromItemsSourceFields is already done in DataGridControl.ProcessDelayedItemsSourceChanged no need to do it here. - this.UnhookToItemPropertiesChanged( dataGridCollectionViewBase ); - - if( dataGridCollectionViewBase != null ) - { - PreBatchCollectionChangedEventManager.RemoveListener( dataGridCollectionViewBase, this ); - PostBatchCollectionChangedEventManager.RemoveListener( dataGridCollectionViewBase, this ); - } - - m_dataGridControlItemsSource = m_dataGridControl.ItemsSource; - - dataGridCollectionViewBase = m_dataGridControlItemsSource as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - { - PreBatchCollectionChangedEventManager.AddListener( dataGridCollectionViewBase, this ); - PostBatchCollectionChangedEventManager.AddListener( dataGridCollectionViewBase, this ); - } - - this.HookToItemPropertiesChanged(); - - //If this is the master level DataGridContext - if( m_parentDataGridContext == null ) - { - //And if this is a DataGridCollectionView - DataGridCollectionView collectionView = m_dataGridControlItemsSource as DataGridCollectionView; - if( collectionView != null ) - { - //Set its dataGridContext so it can propagate a DeferRefresh to details' DataGridCollectionViews - collectionView.PrepareRootContextForDeferRefresh( this ); - } - } - } - else - { - return false; - } - - return true; - } + } + } - #endregion + private void OnDetailConfigRequestingDelayBringIntoViewAndFocusCurrent(object sender, RequestingDelayBringIntoViewAndFocusCurrentEventArgs e) + { + if (!this.IsCurrent) + return; - #region Private Fields + this.DelayBringIntoViewAndFocusCurrent(e.Trigger); + } - private BitVector32 m_flags = new BitVector32(); - private readonly CurrencyManager m_currencyManager; - private readonly ICollection m_viewProperties = new List(); - private PropertyDescriptorCollection m_viewPropertiesDescriptors; // = null - private DefaultDetailConfiguration m_defaultDetailConfiguration; // = null - private ColumnBase m_defaultImageColumn; // = null - private int m_deferRestoreStateCount; // = 0; - private readonly Dictionary m_sizeStateDictionary = new Dictionary(); - private IEnumerable m_dataGridControlItemsSource; - private DeferSelectionChangedOnItemsCollectionChangedDisposable m_deferSelectionChangedOnItemsCollectionChanged; // = null + private static void CleanContainerSizeState(FrameworkElement container, ContainerSizeState containerSizeState) + { + if (containerSizeState.Height != DependencyProperty.UnsetValue) + container.ClearValue(FrameworkElement.HeightProperty); - #endregion + if (containerSizeState.Width != DependencyProperty.UnsetValue) + container.ClearValue(FrameworkElement.WidthProperty); - #region IDataGridContextVisitable Members + if (containerSizeState.MinHeight != DependencyProperty.UnsetValue) + container.ClearValue(FrameworkElement.MinHeightProperty); - void IDataGridContextVisitable.AcceptVisitor( IDataGridContextVisitor visitor, out bool visitWasStopped ) - { - ( ( IDataGridContextVisitable )this.CustomItemContainerGenerator ).AcceptVisitor( visitor, out visitWasStopped ); - } + if (containerSizeState.MinWidth != DependencyProperty.UnsetValue) + container.ClearValue(FrameworkElement.MinWidthProperty); - void IDataGridContextVisitable.AcceptVisitor( int minIndex, int maxIndex, IDataGridContextVisitor visitor, out bool visitWasStopped ) - { - ( ( IDataGridContextVisitable )this.CustomItemContainerGenerator ).AcceptVisitor( minIndex, maxIndex, visitor, out visitWasStopped ); - } + if (containerSizeState.MaxHeight != DependencyProperty.UnsetValue) + container.ClearValue(FrameworkElement.MaxHeightProperty); - void IDataGridContextVisitable.AcceptVisitor( int minIndex, int maxIndex, IDataGridContextVisitor visitor, DataGridContextVisitorType visitorType, out bool visitWasStopped ) - { - ( ( IDataGridContextVisitable )this.CustomItemContainerGenerator ).AcceptVisitor( minIndex, maxIndex, visitor, visitorType, out visitWasStopped ); - } + if (containerSizeState.MaxWidth != DependencyProperty.UnsetValue) + container.ClearValue(FrameworkElement.MaxWidthProperty); + } - void IDataGridContextVisitable.AcceptVisitor( int minIndex, int maxIndex, IDataGridContextVisitor visitor, DataGridContextVisitorType visitorType, bool visitDetails, out bool visitWasStopped ) - { - ( ( IDataGridContextVisitable )this.CustomItemContainerGenerator ).AcceptVisitor( minIndex, maxIndex, visitor, visitorType, visitDetails, out visitWasStopped ); - } + private static void RestoreContainerSizeWorker(FrameworkElement container, ContainerSizeState sizeState) + { + if (sizeState.Height != DependencyProperty.UnsetValue) + container.SetValue(FrameworkElement.HeightProperty, sizeState.Height); - #endregion + if (sizeState.Width != DependencyProperty.UnsetValue) + container.SetValue(FrameworkElement.WidthProperty, sizeState.Width); - #region ICustomTypeDescriptor Members + if (sizeState.MinHeight != DependencyProperty.UnsetValue) + container.SetValue(FrameworkElement.MinHeightProperty, sizeState.MinHeight); - AttributeCollection ICustomTypeDescriptor.GetAttributes() - { - return AttributeCollection.Empty; - } + if (sizeState.MinWidth != DependencyProperty.UnsetValue) + container.SetValue(FrameworkElement.MinWidthProperty, sizeState.MinWidth); - string ICustomTypeDescriptor.GetClassName() - { - return null; - } + if (sizeState.MaxHeight != DependencyProperty.UnsetValue) + container.SetValue(FrameworkElement.MaxHeightProperty, sizeState.MaxHeight); - string ICustomTypeDescriptor.GetComponentName() - { - return null; - } + if (sizeState.MaxWidth != DependencyProperty.UnsetValue) + container.SetValue(FrameworkElement.MaxWidthProperty, sizeState.MaxWidth); + } - TypeConverter ICustomTypeDescriptor.GetConverter() - { - return null; - } + //---------- OVERRIDES ---------- - EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() - { - return null; - } + protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) + { + base.OnPropertyChanged(e); + this.OnPropertyChanged(e.Property.Name); + } - PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() - { - return null; - } + //---------- INTERFACES ---------- - object ICustomTypeDescriptor.GetEditor( Type editorBaseType ) - { - return null; - } + #region INotifyPropertyChanged Members - EventDescriptorCollection ICustomTypeDescriptor.GetEvents( Attribute[] attributes ) - { - return EventDescriptorCollection.Empty; - } + public event PropertyChangedEventHandler PropertyChanged; - EventDescriptorCollection ICustomTypeDescriptor.GetEvents() - { - return EventDescriptorCollection.Empty; - } + private void OnPropertyChanged(string propertyName) + { + var handler = this.PropertyChanged; + if (handler == null) + return; - PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties( Attribute[] attributes ) - { - if( attributes == null ) - { - // We only cache the full property list. - if( m_viewPropertiesDescriptors == null ) + handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + + #endregion + + #region IWeakEventListener Members + + bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e) + { + return this.OnReceiveWeakEvent(managerType, sender, e); + } + + private bool OnReceiveWeakEvent(Type managerType, object sender, EventArgs e) { - var view = m_dataGridControl.GetView(); - Debug.Assert( view != null ); + if (managerType == typeof(CollectionChangedEventManager)) + { + var eventArgs = (NotifyCollectionChangedEventArgs)e; - if( view == null ) - return PropertyDescriptorCollection.Empty; + if (sender == m_items) + { + var args = eventArgs.GetRangeActionOrSelf(); + + this.Items_CollectionChanged(sender, args); + } + if (sender == this.DetailConfigurations) + { + this.OnPropertyChanged("HasDetails"); + } + else if (sender == m_columnManager.Columns) + { + //Master Level columns collection changed + this.HandleMasterColumnsCollectionChanged(eventArgs); + } + else if (sender == this.VisibleColumns) + { + var mode = ColumnStretchMode.None; - var properties = new ViewBindingPropertyDescriptor[ m_viewProperties.Count ]; - var defaultDetailConfiguration = this.GetDefaultDetailConfigurationForContext(); - var index = 0; + if (this.GetViewPropertyValue("ColumnStretchMode", ref mode)) + { + if ((mode == ColumnStretchMode.First) || (mode == ColumnStretchMode.Last)) + { + if (eventArgs.NewItems != null) + { + foreach (ColumnBase column in eventArgs.NewItems) + { + column.ClearValue(ColumnBase.DesiredWidthProperty); + } + } + } + } + } + else if (sender == m_items.SortDescriptions) + { + this.OnSortDescriptionsChanged(sender, eventArgs); + } + else if (sender == m_items.GroupDescriptions) + { + this.OnGroupDescriptionsChanged(sender, eventArgs); + } + else if (sender is DataGridItemPropertyCollection) + { + this.OnItemPropertiesCollectionChanged((DataGridItemPropertyCollection)sender, eventArgs); + } + } + else if (managerType == typeof(PropertyChangedEventManager)) + { + var eventArgs = (PropertyChangedEventArgs)e; - foreach( var property in m_viewProperties ) - { - properties[ index ] = new ViewBindingPropertyDescriptor( m_detailConfig, defaultDetailConfiguration, view, property.DependencyProperty, property.ViewPropertyMode ); - index++; - } + if (sender is DataGridItemPropertyBase) + { + this.OnItemPropertyPropertyChanged((DataGridItemPropertyBase)sender, eventArgs); + } + } + else if (managerType == typeof(ColumnsLayoutChangingEventManager)) + { + DataGridContext.UnselectAllCells(this); + } + else if (managerType == typeof(ColumnsLayoutChangedEventManager)) + { + // Only force a reset if at least one Row has not used an IVirtualizingCellsHost as PART_CellsHost + if (m_dataGridControl.ForceGeneratorReset) + { + //forces the collection view to refresh (therefore, regenerates all the items ). + this.CustomItemContainerGenerator.RemoveAllAndNotify(); - m_viewPropertiesDescriptors = new PropertyDescriptorCollection( properties ); + if (this.SourceDetailConfiguration == null) // not linked to a DetailConfiguration (master level) + { + //also notify the DataGridControl so it can clear the fixed regions + m_dataGridControl.ResetFixedRegions(); + } + } + + this.DefaultImageColumnDetermined = false; + } + else if (managerType == typeof(PreBatchCollectionChangedEventManager)) + { + Debug.Assert(m_deferSelectionChangedOnItemsCollectionChanged == null); + + // When using DataGridVirtualizingCollectionViewBase, we should keep the "Replace" action + // in order to call UpdateSelectionAfterSourceCollectionChanged with a Replace instead of a Reset. + if (m_deferSelectionChangedOnItemsCollectionChanged == null && !(sender is DataGridVirtualizingCollectionViewBase)) + { + m_deferSelectionChangedOnItemsCollectionChanged = new DeferSelectionChangedOnItemsCollectionChangedDisposable(this); + } + } + else if (managerType == typeof(PostBatchCollectionChangedEventManager)) + { + var disposable = m_deferSelectionChangedOnItemsCollectionChanged; + if (disposable != null) + { + m_deferSelectionChangedOnItemsCollectionChanged = null; + disposable.Dispose(); + } + } + else if (managerType == typeof(RealizedContainersRequestedEventManager)) + { + var eventArgs = (RealizedContainersRequestedEventArgs)e; + this.GetRealizedItems(eventArgs.RealizedContainers); + } + else if (managerType == typeof(DistinctValuesRequestedEventManager)) + { + var eventArgs = (DistinctValuesRequestedEventArgs)e; + this.MergeDistinctValues(eventArgs); + } + else if (managerType == typeof(AllowDetailToggleChangedEventManager)) + { + this.OnPropertyChanged("AllowDetailToggle"); + } + else if (managerType == typeof(ViewChangedEventManager)) + { + this.SetupViewProperties(); + this.InitializeViewProperties(); + } + else if (managerType == typeof(CurrentColumnChangedEventManager)) + { + this.OnPropertyChanged("CurrentColumn"); + } + else if (managerType == typeof(GroupConfigurationSelectorChangedEventManager)) + { + this.OnGroupConfigurationSelectorChanged(); + } + else if (managerType == typeof(DetailVisibilityChangedEventManager)) + { + this.OnPropertyChanged("HasDetails"); + } + else if (managerType == typeof(MaxGroupLevelsChangedEventManager)) + { + this.OnPropertyChanged("MaxGroupLevels"); + } + else if (managerType == typeof(MaxSortLevelsChangedEventManager)) + { + this.OnPropertyChanged("MaxSortLevels"); + } + else if (managerType == typeof(ItemsSourceChangeCompletedEventManager)) + { + var dataGridCollectionViewBase = m_dataGridControlItemsSource as DataGridCollectionViewBase; + + // GenerateColumnsFromItemsSourceFields is already done in DataGridControl.ProcessDelayedItemsSourceChanged no need to do it here. + this.UnhookToItemPropertiesChanged(dataGridCollectionViewBase); + + if (dataGridCollectionViewBase != null) + { + PreBatchCollectionChangedEventManager.RemoveListener(dataGridCollectionViewBase, this); + PostBatchCollectionChangedEventManager.RemoveListener(dataGridCollectionViewBase, this); + } + + m_dataGridControlItemsSource = m_dataGridControl.ItemsSource; + + dataGridCollectionViewBase = m_dataGridControlItemsSource as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + { + PreBatchCollectionChangedEventManager.AddListener(dataGridCollectionViewBase, this); + PostBatchCollectionChangedEventManager.AddListener(dataGridCollectionViewBase, this); + } + + this.HookToItemPropertiesChanged(); + + //If this is the master level DataGridContext + if (m_parentDataGridContext == null) + { + //And if this is a DataGridCollectionView + DataGridCollectionView collectionView = m_dataGridControlItemsSource as DataGridCollectionView; + if (collectionView != null) + { + //Set its dataGridContext so it can propagate a DeferRefresh to details' DataGridCollectionViews + collectionView.PrepareRootContextForDeferRefresh(this); + } + } + } + else + { + return false; + } + + return true; } - return m_viewPropertiesDescriptors; - } + #endregion - return PropertyDescriptorCollection.Empty; - } + #region Private Fields - PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() - { - return ( ( ICustomTypeDescriptor )this ).GetProperties( null ); - } + private BitVector32 m_flags = new BitVector32(); + private readonly CurrencyManager m_currencyManager; + private readonly ICollection m_viewProperties = new List(); + private PropertyDescriptorCollection m_viewPropertiesDescriptors; // = null + private DefaultDetailConfiguration m_defaultDetailConfiguration; // = null + private ColumnBase m_defaultImageColumn; // = null + private int m_deferRestoreStateCount; // = 0; + private readonly Dictionary m_sizeStateDictionary = new Dictionary(); + private IEnumerable m_dataGridControlItemsSource; + private DeferSelectionChangedOnItemsCollectionChangedDisposable m_deferSelectionChangedOnItemsCollectionChanged; // = null - object ICustomTypeDescriptor.GetPropertyOwner( PropertyDescriptor pd ) - { - return this; - } + #endregion + + #region IDataGridContextVisitable Members + + void IDataGridContextVisitable.AcceptVisitor(IDataGridContextVisitor visitor, out bool visitWasStopped) + { + ((IDataGridContextVisitable)this.CustomItemContainerGenerator).AcceptVisitor(visitor, out visitWasStopped); + } + + void IDataGridContextVisitable.AcceptVisitor(int minIndex, int maxIndex, IDataGridContextVisitor visitor, out bool visitWasStopped) + { + ((IDataGridContextVisitable)this.CustomItemContainerGenerator).AcceptVisitor(minIndex, maxIndex, visitor, out visitWasStopped); + } + + void IDataGridContextVisitable.AcceptVisitor(int minIndex, int maxIndex, IDataGridContextVisitor visitor, DataGridContextVisitorType visitorType, out bool visitWasStopped) + { + ((IDataGridContextVisitable)this.CustomItemContainerGenerator).AcceptVisitor(minIndex, maxIndex, visitor, visitorType, out visitWasStopped); + } + + void IDataGridContextVisitable.AcceptVisitor(int minIndex, int maxIndex, IDataGridContextVisitor visitor, DataGridContextVisitorType visitorType, bool visitDetails, out bool visitWasStopped) + { + ((IDataGridContextVisitable)this.CustomItemContainerGenerator).AcceptVisitor(minIndex, maxIndex, visitor, visitorType, visitDetails, out visitWasStopped); + } + + #endregion + + #region ICustomTypeDescriptor Members + + AttributeCollection ICustomTypeDescriptor.GetAttributes() + { + return AttributeCollection.Empty; + } + + string ICustomTypeDescriptor.GetClassName() + { + return null; + } + + string ICustomTypeDescriptor.GetComponentName() + { + return null; + } + + TypeConverter ICustomTypeDescriptor.GetConverter() + { + return null; + } + + EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() + { + return null; + } + + PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() + { + return null; + } + + object ICustomTypeDescriptor.GetEditor(Type editorBaseType) + { + return null; + } + + EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) + { + return EventDescriptorCollection.Empty; + } + + EventDescriptorCollection ICustomTypeDescriptor.GetEvents() + { + return EventDescriptorCollection.Empty; + } + + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) + { + if (attributes == null) + { + // We only cache the full property list. + if (m_viewPropertiesDescriptors == null) + { + var view = m_dataGridControl.GetView(); + Debug.Assert(view != null); + + if (view == null) + return PropertyDescriptorCollection.Empty; + + var properties = new ViewBindingPropertyDescriptor[m_viewProperties.Count]; + var defaultDetailConfiguration = this.GetDefaultDetailConfigurationForContext(); + var index = 0; + + foreach (var property in m_viewProperties) + { + properties[index] = new ViewBindingPropertyDescriptor(m_detailConfig, defaultDetailConfiguration, view, property.DependencyProperty, property.ViewPropertyMode); + index++; + } + + m_viewPropertiesDescriptors = new PropertyDescriptorCollection(properties); + } + + return m_viewPropertiesDescriptors; + } + + return PropertyDescriptorCollection.Empty; + } + + PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() + { + return ((ICustomTypeDescriptor)this).GetProperties(null); + } + + object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) + { + return this; + } + + #endregion - #endregion + //---------- SUB CLASSES ---------- - //---------- SUB CLASSES ---------- + #region DeferRestoreStateDisposable Private Class - #region DeferRestoreStateDisposable Private Class + private sealed class DeferRestoreStateDisposable : IDisposable + { + internal DeferRestoreStateDisposable(DataGridContext dataGridContext) + { + if (dataGridContext == null) + throw new ArgumentNullException("dataGridContext"); - private sealed class DeferRestoreStateDisposable : IDisposable - { - internal DeferRestoreStateDisposable( DataGridContext dataGridContext ) - { - if( dataGridContext == null ) - throw new ArgumentNullException( "dataGridContext" ); + m_dataGridContext = new WeakReference(dataGridContext); - m_dataGridContext = new WeakReference( dataGridContext ); + Interlocked.Increment(ref dataGridContext.m_deferRestoreStateCount); + } - Interlocked.Increment( ref dataGridContext.m_deferRestoreStateCount ); - } + void IDisposable.Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } - void IDisposable.Dispose() - { - this.Dispose( true ); - GC.SuppressFinalize( this ); - } + private void Dispose(bool disposing) + { + var wr = Interlocked.Exchange(ref m_dataGridContext, null); + if (wr == null) + return; - private void Dispose( bool disposing ) - { - var wr = Interlocked.Exchange( ref m_dataGridContext, null ); - if( wr == null ) - return; + var dataGridContext = (DataGridContext)wr.Target; + if (dataGridContext == null) + return; - var dataGridContext = ( DataGridContext )wr.Target; - if( dataGridContext == null ) - return; + if (Interlocked.Decrement(ref dataGridContext.m_deferRestoreStateCount) != 0) + return; - if( Interlocked.Decrement( ref dataGridContext.m_deferRestoreStateCount ) != 0 ) - return; + Debug.Assert(disposing); - Debug.Assert( disposing ); + var dataGridControl = dataGridContext.DataGridControl; + dataGridControl.RestoreDataGridContextState(dataGridContext); + } - var dataGridControl = dataGridContext.DataGridControl; - dataGridControl.RestoreDataGridContextState( dataGridContext ); - } + ~DeferRestoreStateDisposable() + { + this.Dispose(false); + } - ~DeferRestoreStateDisposable() - { - this.Dispose( false ); - } + private WeakReference m_dataGridContext; + } - private WeakReference m_dataGridContext; - } + #endregion - #endregion + #region DeferSelectionChangedOnItemsCollectionChangedDisposable Private Class - #region DeferSelectionChangedOnItemsCollectionChangedDisposable Private Class + private sealed class DeferSelectionChangedOnItemsCollectionChangedDisposable : IDisposable + { + internal DeferSelectionChangedOnItemsCollectionChangedDisposable(DataGridContext dataGridContext) + { + if (dataGridContext == null) + throw new ArgumentNullException("dataGridContext"); - private sealed class DeferSelectionChangedOnItemsCollectionChangedDisposable : IDisposable - { - internal DeferSelectionChangedOnItemsCollectionChangedDisposable( DataGridContext dataGridContext ) - { - if( dataGridContext == null ) - throw new ArgumentNullException( "dataGridContext" ); + m_dataGridContext = new WeakReference(dataGridContext); + } - m_dataGridContext = new WeakReference( dataGridContext ); - } + internal void Queue(NotifyCollectionChangedEventArgs e) + { + if (e == null) + return; - internal void Queue( NotifyCollectionChangedEventArgs e ) - { - if( e == null ) - return; + if (m_eventArgs != null) + { + m_eventArgs = NotifyBatchCollectionChangedEventArgs.Combine(m_eventArgs, e); + } + else + { + m_eventArgs = e; + } + } - if( m_eventArgs != null ) - { - m_eventArgs = NotifyBatchCollectionChangedEventArgs.Combine( m_eventArgs, e ); - } - else - { - m_eventArgs = e; - } - } + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } + + private void Dispose(bool disposing) + { + if (!disposing) + return; - public void Dispose() - { - this.Dispose( true ); - GC.SuppressFinalize( this ); - } + var wr = Interlocked.Exchange(ref m_dataGridContext, null); + if (wr == null) + return; - private void Dispose( bool disposing ) - { - if( !disposing ) - return; + var eventArgs = m_eventArgs; + if (eventArgs == null) + return; - var wr = Interlocked.Exchange( ref m_dataGridContext, null ); - if( wr == null ) - return; + var dataGridContext = (DataGridContext)wr.Target; + if (dataGridContext == null) + return; - var eventArgs = m_eventArgs; - if( eventArgs == null ) - return; + dataGridContext.UpdateSelectionAfterSourceCollectionChanged(eventArgs); + } - var dataGridContext = ( DataGridContext )wr.Target; - if( dataGridContext == null ) - return; + private WeakReference m_dataGridContext; + private NotifyCollectionChangedEventArgs m_eventArgs; //null + } - dataGridContext.UpdateSelectionAfterSourceCollectionChanged( eventArgs ); - } + #endregion - private WeakReference m_dataGridContext; - private NotifyCollectionChangedEventArgs m_eventArgs; //null - } + #region ViewBindingPropertyDescriptor Private Class - #endregion + private class ViewBindingPropertyDescriptor : PropertyDescriptor + { + public ViewBindingPropertyDescriptor(DetailConfiguration detailConfig, DefaultDetailConfiguration defaultDetailConfig, Views.ViewBase view, DependencyProperty dp, ViewPropertyMode viewPropertyMode) + : base(dp.Name, null) + { + if (dp == null) + throw new ArgumentNullException("dp"); - #region ViewBindingPropertyDescriptor Private Class + if (view == null) + throw new ArgumentNullException("view"); - private class ViewBindingPropertyDescriptor : PropertyDescriptor - { - public ViewBindingPropertyDescriptor( DetailConfiguration detailConfig, DefaultDetailConfiguration defaultDetailConfig, Views.ViewBase view, DependencyProperty dp, ViewPropertyMode viewPropertyMode ) - : base( dp.Name, null ) - { - if( dp == null ) - throw new ArgumentNullException( "dp" ); + if (viewPropertyMode == ViewPropertyMode.None) + throw new ArgumentException("viewPropertyMode cannot be ViewPropertyMode.None", "mode"); - if( view == null ) - throw new ArgumentNullException( "view" ); + m_dp = dp; + m_detailConfig = detailConfig; + m_defaultDetailConfig = defaultDetailConfig; + m_view = view; + m_viewPropertyMode = viewPropertyMode; + } - if( viewPropertyMode == ViewPropertyMode.None ) - throw new ArgumentException( "viewPropertyMode cannot be ViewPropertyMode.None", "mode" ); + #region DependencyProperty Read-Only Property - m_dp = dp; - m_detailConfig = detailConfig; - m_defaultDetailConfig = defaultDetailConfig; - m_view = view; - m_viewPropertyMode = viewPropertyMode; - } + public DependencyProperty DependencyProperty + { + get + { + return m_dp; + } + } - #region DependencyProperty Read-Only Property + private DependencyProperty m_dp; // = null - public DependencyProperty DependencyProperty - { - get - { - return m_dp; - } - } + #endregion - private DependencyProperty m_dp; // = null + #region DetailConfig Read-Only Property - #endregion + public DetailConfiguration DetailConfig + { + get + { + return m_detailConfig; + } + } - #region DetailConfig Read-Only Property + private DetailConfiguration m_detailConfig; - public DetailConfiguration DetailConfig - { - get - { - return m_detailConfig; - } - } + #endregion - private DetailConfiguration m_detailConfig; + #region DefaultDetailConfig Read-Only Property - #endregion + public DefaultDetailConfiguration DefaultDetailConfig + { + get + { + return m_defaultDetailConfig; + } + } - #region DefaultDetailConfig Read-Only Property + private DefaultDetailConfiguration m_defaultDetailConfig; - public DefaultDetailConfiguration DefaultDetailConfig - { - get - { - return m_defaultDetailConfig; - } - } + #endregion - private DefaultDetailConfiguration m_defaultDetailConfig; + #region View Read-Only Property - #endregion + public Views.ViewBase View + { + get + { + return m_view; + } + } - #region View Read-Only Property + private Views.ViewBase m_view; - public Views.ViewBase View - { - get - { - return m_view; - } - } + #endregion - private Views.ViewBase m_view; + #region ViewPropertyMode Read-Only Property - #endregion + public ViewPropertyMode ViewPropertyMode + { + get + { + return m_viewPropertyMode; + } + } - #region ViewPropertyMode Read-Only Property + private ViewPropertyMode m_viewPropertyMode; - public ViewPropertyMode ViewPropertyMode - { - get - { - return m_viewPropertyMode; - } - } + #endregion - private ViewPropertyMode m_viewPropertyMode; + public override bool CanResetValue(object component) + { + return false; //stubbing this so that value cannot be reset through the PropertyDescriptor + } - #endregion + public override Type ComponentType + { + get + { + return typeof(DataGridContext); + } + } - public override bool CanResetValue( object component ) - { - return false; //stubbing this so that value cannot be reset through the PropertyDescriptor - } + public override object GetValue(object component) + { + if (m_viewPropertyMode == ViewPropertyMode.Routed) + { + var source = (DependencyObject)m_defaultDetailConfig ?? m_detailConfig; - public override Type ComponentType - { - get - { - return typeof( DataGridContext ); - } - } + //If there is a DefaultDetailConfig, process it in precedence to the DetailConfig. + if (source != null) + { + var valueSource = DependencyPropertyHelper.GetValueSource(source, m_dp); + + switch (valueSource.BaseValueSource) + { + // Pick the value on the view. + case BaseValueSource.Default: + case BaseValueSource.Inherited: + case BaseValueSource.Unknown: + return m_view.GetValue(m_dp); + + // Pick the value on the source component itself. + default: + break; + } + } + } - public override object GetValue( object component ) - { - if( m_viewPropertyMode == ViewPropertyMode.Routed ) - { - var source = ( DependencyObject )m_defaultDetailConfig ?? m_detailConfig; + var dependencyObject = component as DependencyObject; + if (dependencyObject != null) + return dependencyObject.GetValue(m_dp); - //If there is a DefaultDetailConfig, process it in precedence to the DetailConfig. - if( source != null ) - { - var valueSource = DependencyPropertyHelper.GetValueSource( source, m_dp ); + return null; + } - switch( valueSource.BaseValueSource ) + public override bool IsReadOnly { - // Pick the value on the view. - case BaseValueSource.Default: - case BaseValueSource.Inherited: - case BaseValueSource.Unknown: - return m_view.GetValue( m_dp ); + get + { + return m_dp.ReadOnly; + } + } - // Pick the value on the source component itself. - default: - break; + public override Type PropertyType + { + get + { + return m_dp.PropertyType; + } } - } - } - var dependencyObject = component as DependencyObject; - if( dependencyObject != null ) - return dependencyObject.GetValue( m_dp ); + public override void ResetValue(object component) + { + throw new InvalidOperationException(); + } - return null; - } + public override void SetValue(object component, object value) + { + var dependencyObject = component as DependencyObject; + if (dependencyObject == null) + throw new ArgumentException("SetValue was called for an object which is not a DependencyObject.", component.ToString()); - public override bool IsReadOnly - { - get - { - return m_dp.ReadOnly; - } - } + dependencyObject.SetValue(m_dp, value); + } - public override Type PropertyType - { - get - { - return m_dp.PropertyType; + public override bool ShouldSerializeValue(object component) + { + return false; + } } - } - public override void ResetValue( object component ) - { - throw new InvalidOperationException(); - } + #endregion - public override void SetValue( object component, object value ) - { - var dependencyObject = component as DependencyObject; - if( dependencyObject == null ) - throw new ArgumentException( "SetValue was called for an object which is not a DependencyObject.", component.ToString() ); + #region DataGridContextToggleColumnSortCommand Private Class - dependencyObject.SetValue( m_dp, value ); - } + private sealed class DataGridContextToggleColumnSortCommand : ToggleColumnSortCommand + { + #region Constructor - public override bool ShouldSerializeValue( object component ) - { - return false; - } - } + internal DataGridContextToggleColumnSortCommand(DataGridContext dataGridContext) + : base() + { + ToggleColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - #endregion + m_dataGridContext = new WeakReference(dataGridContext); + } - #region DataGridContextToggleColumnSortCommand Private Class + #endregion - private sealed class DataGridContextToggleColumnSortCommand : ToggleColumnSortCommand - { - #region Constructor + #region Properties - internal DataGridContextToggleColumnSortCommand( DataGridContext dataGridContext ) - : base() - { - ToggleColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + #region CanSort Protected Property - m_dataGridContext = new WeakReference( dataGridContext ); - } + protected override bool CanSort + { + get + { + var dataGridContext = this.DataGridContext; + if (this.DataGridContext == null) + return false; - #endregion + return this.DataGridContext.Items.CanSort; + } + } - #region Properties + #endregion - #region CanSort Protected Property + #region Columns Protected Property - protected override bool CanSort - { - get - { - var dataGridContext = this.DataGridContext; - if( this.DataGridContext == null ) - return false; + protected override ColumnCollection Columns + { + get + { + return this.DataGridContext.Columns; + } + } - return this.DataGridContext.Items.CanSort; - } - } + #endregion - #endregion + #region DataGridContext Protected Property - #region Columns Protected Property + protected override DataGridContext DataGridContext + { + get + { + return (m_dataGridContext != null) ? m_dataGridContext.Target as DataGridContext : null; + } + } - protected override ColumnCollection Columns - { - get - { - return this.DataGridContext.Columns; - } - } + private readonly WeakReference m_dataGridContext; - #endregion + #endregion - #region DataGridContext Protected Property + #region MaxSortLevels Protected Property - protected override DataGridContext DataGridContext - { - get - { - return ( m_dataGridContext != null ) ? m_dataGridContext.Target as DataGridContext : null; - } - } + protected override int MaxSortLevels + { + get + { + return this.DataGridContext.MaxSortLevels; + } + } - private readonly WeakReference m_dataGridContext; + #endregion - #endregion + #region SortDescriptions Protected Property - #region MaxSortLevels Protected Property + protected override SortDescriptionCollection SortDescriptions + { + get + { + return this.DataGridContext.Items.SortDescriptions; + } + } - protected override int MaxSortLevels - { - get - { - return this.DataGridContext.MaxSortLevels; - } - } + #endregion - #endregion + #endregion - #region SortDescriptions Protected Property + #region Methods Override - protected override SortDescriptionCollection SortDescriptions - { - get - { - return this.DataGridContext.Items.SortDescriptions; - } - } + protected override bool CanExecuteCore(ColumnBase column, bool resetSort) + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return false; - #endregion + return base.CanExecuteCore(column, resetSort); + } - #endregion + protected override void ValidateToggleColumnSort() + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return; - #region Methods Override + Debug.Assert(!dataGridContext.IsAFlattenDetail, "A flatten detail should not be able to toggle the column sort direction."); + } - protected override bool CanExecuteCore( ColumnBase column, bool resetSort ) - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return false; + protected override SortDescriptionsSyncContext GetSortDescriptionsSyncContext() + { + var dataGridContext = this.DataGridContext; - return base.CanExecuteCore( column, resetSort ); - } + ToggleColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); + return dataGridContext.SortDescriptionsSyncContext; + } - protected override void ValidateToggleColumnSort() - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return; + protected override void ValidateSynchronizationContext(SynchronizationContext synchronizationContext) + { + var dataGridContext = this.DataGridContext; + ToggleColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - Debug.Assert( !dataGridContext.IsAFlattenDetail, "A flatten detail should not be able to toggle the column sort direction." ); - } + if (!synchronizationContext.Own) + throw new DataGridInternalException("The column is already being processed.", dataGridContext.DataGridControl); + } - protected override SortDescriptionsSyncContext GetSortDescriptionsSyncContext() - { - var dataGridContext = this.DataGridContext; + protected override void DeferRestoreStateOnLevel(Disposer disposer) + { + var dataGridContext = this.DataGridContext; + ToggleColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - ToggleColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); - return dataGridContext.SortDescriptionsSyncContext; - } + ToggleColumnSortCommand.DeferRestoreStateOnLevel(disposer, dataGridContext); + } - protected override void ValidateSynchronizationContext( SynchronizationContext synchronizationContext ) - { - var dataGridContext = this.DataGridContext; - ToggleColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + protected override IDisposable SetQueueBringIntoViewRestrictions(AutoScrollCurrentItemSourceTriggers triggers) + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return null; - if( !synchronizationContext.Own ) - throw new DataGridInternalException( "The column is already being processed.", dataGridContext.DataGridControl ); - } + return this.DataGridContext.SetQueueBringIntoViewRestrictions(triggers); + } - protected override void DeferRestoreStateOnLevel( Disposer disposer ) - { - var dataGridContext = this.DataGridContext; - ToggleColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + protected override bool TryDeferResortSourceDetailConfiguration(out IDisposable defer) + { + var dataGridContext = this.DataGridContext; + ToggleColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - ToggleColumnSortCommand.DeferRestoreStateOnLevel( disposer, dataGridContext ); - } + return this.TryDeferResort(dataGridContext.SourceDetailConfiguration, out defer); + } - protected override IDisposable SetQueueBringIntoViewRestrictions( AutoScrollCurrentItemSourceTriggers triggers ) - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return null; + protected override IDisposable DeferResortHelperItemsSourceCollection() + { + var dataGridContext = this.DataGridContext; + ToggleColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - return this.DataGridContext.SetQueueBringIntoViewRestrictions( triggers ); - } + return this.DeferResortHelper(dataGridContext.ItemsSourceCollection, dataGridContext.Items); + } - protected override bool TryDeferResortSourceDetailConfiguration( out IDisposable defer ) - { - var dataGridContext = this.DataGridContext; - ToggleColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + protected override void UpdateColumnSort() + { + var dataGridContext = this.DataGridContext; + Debug.Assert(dataGridContext != null); - return this.TryDeferResort( dataGridContext.SourceDetailConfiguration, out defer ); - } + base.UpdateColumnSort(); + } - protected override IDisposable DeferResortHelperItemsSourceCollection() - { - var dataGridContext = this.DataGridContext; - ToggleColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + #endregion + } - return this.DeferResortHelper( dataGridContext.ItemsSourceCollection, dataGridContext.Items ); - } + #endregion - protected override void UpdateColumnSort() - { - var dataGridContext = this.DataGridContext; - Debug.Assert( dataGridContext != null ); + #region DataGridContextUpdateColumnSortCommand Private Class - base.UpdateColumnSort(); - } + private sealed class DataGridContextUpdateColumnSortCommand : UpdateColumnSortCommand + { + #region Validation Methods - #endregion - } + private static void ThrowIfDetailDataGridContext(DataGridContext dataGridContext, string paramName) + { + Debug.Assert(dataGridContext != null); - #endregion + if (dataGridContext.ParentDataGridContext != null) + throw new ArgumentException("The DataGridContext is not the topmost DataGridContext.", paramName); + } - #region DataGridContextUpdateColumnSortCommand Private Class + #endregion - private sealed class DataGridContextUpdateColumnSortCommand : UpdateColumnSortCommand - { - #region Validation Methods + #region Constructor - private static void ThrowIfDetailDataGridContext( DataGridContext dataGridContext, string paramName ) - { - Debug.Assert( dataGridContext != null ); + internal DataGridContextUpdateColumnSortCommand(DataGridContext dataGridContext) + { + DataGridContextUpdateColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - if( dataGridContext.ParentDataGridContext != null ) - throw new ArgumentException( "The DataGridContext is not the topmost DataGridContext.", paramName ); - } + m_dataGridContext = new WeakReference(dataGridContext); + } - #endregion + #endregion - #region Constructor + #region SortDescriptionsSyncContext Protected Property - internal DataGridContextUpdateColumnSortCommand( DataGridContext dataGridContext ) - { - DataGridContextUpdateColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + protected override SortDescriptionsSyncContext SortDescriptionsSyncContext + { + get + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return null; - m_dataGridContext = new WeakReference( dataGridContext ); - } + return dataGridContext.SortDescriptionsSyncContext; + } + } - #endregion + #endregion - #region SortDescriptionsSyncContext Protected Property + #region DataGridContext Private Property - protected override SortDescriptionsSyncContext SortDescriptionsSyncContext - { - get - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return null; + private DataGridContext DataGridContext + { + get + { + return m_dataGridContext.Target as DataGridContext; + } + } - return dataGridContext.SortDescriptionsSyncContext; - } - } + private readonly WeakReference m_dataGridContext; - #endregion + #endregion - #region DataGridContext Private Property + protected override bool CanExecuteCore() + { + return (this.DataGridContext != null); + } - private DataGridContext DataGridContext - { - get - { - return m_dataGridContext.Target as DataGridContext; - } - } + protected override void ExecuteCore() + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return; - private readonly WeakReference m_dataGridContext; + var detailConfiguration = dataGridContext.SourceDetailConfiguration; + if (detailConfiguration != null) + { + this.Update(detailConfiguration); + } + // The current DataGridContext is the top most DataGridContext; + else + { + this.Update(dataGridContext); + } + } - #endregion + private void Update(DataGridContext dataGridContext) + { + ColumnSortCommand.ThrowIfNull(dataGridContext, "dataGridContext"); + DataGridContextUpdateColumnSortCommand.ThrowIfDetailDataGridContext(dataGridContext, "dataGridContext"); - protected override bool CanExecuteCore() - { - return ( this.DataGridContext != null ); - } + // The sort order of the flatten details is driven by the master. A sort order change + // on the master must be reflected in the details. + if (dataGridContext.AreDetailsFlatten) + { + foreach (var detailConfiguration in dataGridContext.DetailConfigurations) + { + this.Update(detailConfiguration, true); + } + } - protected override void ExecuteCore() - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return; + using (var synchronizationContext = this.StartSynchronizing(dataGridContext.SortDescriptionsSyncContext)) + { + this.SynchronizeColumnSort( + synchronizationContext, + dataGridContext.Items.SortDescriptions, + dataGridContext.Columns); + } + } - var detailConfiguration = dataGridContext.SourceDetailConfiguration; - if( detailConfiguration != null ) - { - this.Update( detailConfiguration ); - } - // The current DataGridContext is the top most DataGridContext; - else - { - this.Update( dataGridContext ); - } - } + private void Update(DetailConfiguration detailConfiguration) + { + this.Update(detailConfiguration, false); + } - private void Update( DataGridContext dataGridContext ) - { - ColumnSortCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); - DataGridContextUpdateColumnSortCommand.ThrowIfDetailDataGridContext( dataGridContext, "dataGridContext" ); + private void Update(DetailConfiguration detailConfiguration, bool recursive) + { + ColumnSortCommand.ThrowIfNull(detailConfiguration, "detailConfiguration"); - // The sort order of the flatten details is driven by the master. A sort order change - // on the master must be reflected in the details. - if( dataGridContext.AreDetailsFlatten ) - { - foreach( var detailConfiguration in dataGridContext.DetailConfigurations ) - { - this.Update( detailConfiguration, true ); - } - } + if (recursive) + { + foreach (var children in detailConfiguration.DetailConfigurations) + { + this.Update(children, true); + } + } - using( var synchronizationContext = this.StartSynchronizing( dataGridContext.SortDescriptionsSyncContext ) ) - { - this.SynchronizeColumnSort( - synchronizationContext, - dataGridContext.Items.SortDescriptions, - dataGridContext.Columns ); + var command = detailConfiguration.UpdateColumnSortCommand; + if (command.CanExecute()) + { + command.Execute(); + } + } } - } - private void Update( DetailConfiguration detailConfiguration ) - { - this.Update( detailConfiguration, false ); - } + #endregion - private void Update( DetailConfiguration detailConfiguration, bool recursive ) - { - ColumnSortCommand.ThrowIfNull( detailConfiguration, "detailConfiguration" ); + #region DataGridContextAddGroupCommand Private Class - if( recursive ) + private sealed class DataGridContextAddGroupCommand : ColumnAddGroupCommand { - foreach( var children in detailConfiguration.DetailConfigurations ) - { - this.Update( children, true ); - } - } - - var command = detailConfiguration.UpdateColumnSortCommand; - if( command.CanExecute() ) - { - command.Execute(); - } - } - } + #region Constructor - #endregion + internal DataGridContextAddGroupCommand(DataGridContext dataGridContext) + { + DataGridContextAddGroupCommand.ThrowIfNull(dataGridContext, "dataGridContext"); - #region DataGridContextAddGroupCommand Private Class + m_dataGridContext = new WeakReference(dataGridContext); + } - private sealed class DataGridContextAddGroupCommand : ColumnAddGroupCommand - { - #region Constructor + #endregion - internal DataGridContextAddGroupCommand( DataGridContext dataGridContext ) - { - DataGridContextAddGroupCommand.ThrowIfNull( dataGridContext, "dataGridContext" ); + #region GroupDescriptions Protected Property - m_dataGridContext = new WeakReference( dataGridContext ); - } + protected override ObservableCollection GroupDescriptions + { + get + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return null; - #endregion + return dataGridContext.Items.GroupDescriptions; + } + } - #region GroupDescriptions Protected Property + #endregion - protected override ObservableCollection GroupDescriptions - { - get - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return null; + #region DataGridContext Private Property - return dataGridContext.Items.GroupDescriptions; - } - } + private DataGridContext DataGridContext + { + get + { + return m_dataGridContext.Target as DataGridContext; + } + } - #endregion + private readonly WeakReference m_dataGridContext; - #region DataGridContext Private Property + #endregion - private DataGridContext DataGridContext - { - get - { - return m_dataGridContext.Target as DataGridContext; - } - } + protected override string GetColumnName(ColumnBase column) + { + var dataGridContext = this.DataGridContext; + if ((dataGridContext == null) || (column == null)) + return null; - private readonly WeakReference m_dataGridContext; + var itemPropertyMap = dataGridContext.ItemPropertyMap; + if ((itemPropertyMap != null) && itemPropertyMap.IsMapping) + { + string fieldName; + if (DataGridItemPropertyMapHelper.TryGetDetailColumnName(itemPropertyMap, column.FieldName, out fieldName)) + return fieldName; + } + else + { + return column.FieldName; + } - #endregion + return null; + } - protected override string GetColumnName( ColumnBase column ) - { - var dataGridContext = this.DataGridContext; - if( ( dataGridContext == null ) || ( column == null ) ) - return null; + protected override GroupDescription GetGroupDescription(ColumnBase column) + { + if (this.DataGridContext == null) + return null; - var itemPropertyMap = dataGridContext.ItemPropertyMap; - if( ( itemPropertyMap != null ) && itemPropertyMap.IsMapping ) - { - string fieldName; - if( DataGridItemPropertyMapHelper.TryGetDetailColumnName( itemPropertyMap, column.FieldName, out fieldName ) ) - return fieldName; - } - else - { - return column.FieldName; - } + return base.GetGroupDescription(column); + } - return null; - } + protected override GroupConfiguration GetGroupConfiguration(ColumnBase column) + { + if (this.DataGridContext == null) + return null; - protected override GroupDescription GetGroupDescription( ColumnBase column ) - { - if( this.DataGridContext == null ) - return null; + return base.GetGroupConfiguration(column); + } - return base.GetGroupDescription( column ); - } + protected override bool CanExecuteCore(ColumnBase column, int index) + { + if (this.DataGridContext == null) + return false; - protected override GroupConfiguration GetGroupConfiguration( ColumnBase column ) - { - if( this.DataGridContext == null ) - return null; + return base.CanExecuteCore(column, index); + } - return base.GetGroupConfiguration( column ); - } + protected override void ExecuteCore(ColumnBase column, int index) + { + var dataGridContext = this.DataGridContext; + if (dataGridContext == null) + return; - protected override bool CanExecuteCore( ColumnBase column, int index ) - { - if( this.DataGridContext == null ) - return false; + using (dataGridContext.SetQueueBringIntoViewRestrictions(AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged)) + { + base.ExecuteCore(column, index); + } + } + } - return base.CanExecuteCore( column, index ); - } + #endregion - protected override void ExecuteCore( ColumnBase column, int index ) - { - var dataGridContext = this.DataGridContext; - if( dataGridContext == null ) - return; + #region DataGridContextFlags Private Enum - using( dataGridContext.SetQueueBringIntoViewRestrictions( AutoScrollCurrentItemSourceTriggers.CollectionViewCurrentItemChanged ) ) + [Flags] + private enum DataGridContextFlags { - base.ExecuteCore( column, index ); + AlreadySearchedForDetailConfig = 1, + DefaultImageColumnDetermined = 2, + IsCurrent = 4, + IsRestoringState = 8, + IsSavingState = 16, } - } - } - #endregion - - #region DataGridContextFlags Private Enum - - [Flags] - private enum DataGridContextFlags - { - AlreadySearchedForDetailConfig = 1, - DefaultImageColumnDetermined = 2, - IsCurrent = 4, - IsRestoringState = 8, - IsSavingState = 16, + #endregion } - - #endregion - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GenericContentTemplateSelector.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GenericContentTemplateSelector.cs index a63c558f..92384ad0 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GenericContentTemplateSelector.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GenericContentTemplateSelector.cs @@ -31,370 +31,370 @@ using Xceed.Wpf.DataGrid.Converters; namespace Xceed.Wpf.DataGrid { - internal sealed class GenericContentTemplateSelector : DataTemplateSelector - { - #region Static Fields + internal sealed class GenericContentTemplateSelector : DataTemplateSelector + { + #region Static Fields - internal static readonly DataTemplate ForeignKeyCellContentTemplate; - internal static readonly DataTemplate ForeignKeyGroupValueTemplate; - internal static readonly DataTemplate ForeignKeyScrollTipContentTemplate; + internal static readonly DataTemplate ForeignKeyCellContentTemplate; + internal static readonly DataTemplate ForeignKeyGroupValueTemplate; + internal static readonly DataTemplate ForeignKeyScrollTipContentTemplate; - private static readonly DataTemplate BoolTemplate; - private static readonly DataTemplate CommonTemplate; - private static readonly DataTemplate ImageTemplate; + private static readonly DataTemplate BoolTemplate; + private static readonly DataTemplate CommonTemplate; + private static readonly DataTemplate ImageTemplate; - private static readonly List> DefaultTemplates = new List>( 0 ); + private static readonly List> DefaultTemplates = new List>(0); - private static readonly GenericContentTemplateSelectorResources GenericContentTemplateResources = new GenericContentTemplateSelectorResources(); + private static readonly GenericContentTemplateSelectorResources GenericContentTemplateResources = new GenericContentTemplateSelectorResources(); - private static Func FindTemplateResource; //null + private static Func FindTemplateResource; //null - #endregion + #endregion - #region Constructors + #region Constructors - static GenericContentTemplateSelector() - { - // We need to initalize the ResourceDictionary before accessing since we access - // it in a static constructor and will be called before the Layout was performed - GenericContentTemplateSelector.GenericContentTemplateResources.InitializeComponent(); + static GenericContentTemplateSelector() + { + // We need to initalize the ResourceDictionary before accessing since we access + // it in a static constructor and will be called before the Layout was performed + GenericContentTemplateSelector.GenericContentTemplateResources.InitializeComponent(); - GenericContentTemplateSelector.BoolTemplate = GenericContentTemplateSelector.GenericContentTemplateResources[ "booleanDefaultContentTemplate" ] as DataTemplate; - Debug.Assert( GenericContentTemplateSelector.BoolTemplate != null ); - GenericContentTemplateSelector.BoolTemplate.Seal(); + GenericContentTemplateSelector.BoolTemplate = GenericContentTemplateSelector.GenericContentTemplateResources["booleanDefaultContentTemplate"] as DataTemplate; + Debug.Assert(GenericContentTemplateSelector.BoolTemplate != null); + GenericContentTemplateSelector.BoolTemplate.Seal(); - GenericContentTemplateSelector.CommonTemplate = GenericContentTemplateSelector.GenericContentTemplateResources[ "commonDefaultContentTemplate" ] as DataTemplate; - Debug.Assert( GenericContentTemplateSelector.CommonTemplate != null ); - GenericContentTemplateSelector.CommonTemplate.Seal(); + GenericContentTemplateSelector.CommonTemplate = GenericContentTemplateSelector.GenericContentTemplateResources["commonDefaultContentTemplate"] as DataTemplate; + Debug.Assert(GenericContentTemplateSelector.CommonTemplate != null); + GenericContentTemplateSelector.CommonTemplate.Seal(); - GenericContentTemplateSelector.ImageTemplate = GenericContentTemplateSelector.GenericContentTemplateResources[ "imageDefaultContentTemplate" ] as DataTemplate; - Debug.Assert( GenericContentTemplateSelector.ImageTemplate != null ); - GenericContentTemplateSelector.ImageTemplate.Seal(); + GenericContentTemplateSelector.ImageTemplate = GenericContentTemplateSelector.GenericContentTemplateResources["imageDefaultContentTemplate"] as DataTemplate; + Debug.Assert(GenericContentTemplateSelector.ImageTemplate != null); + GenericContentTemplateSelector.ImageTemplate.Seal(); - GenericContentTemplateSelector.ForeignKeyCellContentTemplate = GenericContentTemplateSelector.GenericContentTemplateResources[ "foreignKeyDefaultContentTemplate" ] as DataTemplate; - Debug.Assert( GenericContentTemplateSelector.ForeignKeyCellContentTemplate != null ); - GenericContentTemplateSelector.ForeignKeyCellContentTemplate.Seal(); + GenericContentTemplateSelector.ForeignKeyCellContentTemplate = GenericContentTemplateSelector.GenericContentTemplateResources["foreignKeyDefaultContentTemplate"] as DataTemplate; + Debug.Assert(GenericContentTemplateSelector.ForeignKeyCellContentTemplate != null); + GenericContentTemplateSelector.ForeignKeyCellContentTemplate.Seal(); - GenericContentTemplateSelector.ForeignKeyGroupValueTemplate = GenericContentTemplateSelector.GenericContentTemplateResources[ "foreignKeyGroupValueDefaultContentTemplate" ] as DataTemplate; - Debug.Assert( GenericContentTemplateSelector.ForeignKeyGroupValueTemplate != null ); - GenericContentTemplateSelector.ForeignKeyGroupValueTemplate.Seal(); + GenericContentTemplateSelector.ForeignKeyGroupValueTemplate = GenericContentTemplateSelector.GenericContentTemplateResources["foreignKeyGroupValueDefaultContentTemplate"] as DataTemplate; + Debug.Assert(GenericContentTemplateSelector.ForeignKeyGroupValueTemplate != null); + GenericContentTemplateSelector.ForeignKeyGroupValueTemplate.Seal(); - GenericContentTemplateSelector.ForeignKeyScrollTipContentTemplate = GenericContentTemplateSelector.GenericContentTemplateResources[ "foreignKeyScrollTipDefaultContentTemplate" ] as DataTemplate; - Debug.Assert( GenericContentTemplateSelector.ForeignKeyScrollTipContentTemplate != null ); - GenericContentTemplateSelector.ForeignKeyScrollTipContentTemplate.Seal(); - } + GenericContentTemplateSelector.ForeignKeyScrollTipContentTemplate = GenericContentTemplateSelector.GenericContentTemplateResources["foreignKeyScrollTipDefaultContentTemplate"] as DataTemplate; + Debug.Assert(GenericContentTemplateSelector.ForeignKeyScrollTipContentTemplate != null); + GenericContentTemplateSelector.ForeignKeyScrollTipContentTemplate.Seal(); + } - private GenericContentTemplateSelector() - { - } + private GenericContentTemplateSelector() + { + } - #endregion + #endregion - #region Instance Static Property + #region Instance Static Property - public static GenericContentTemplateSelector Instance - { - get - { - return m_instance; - } - } + public static GenericContentTemplateSelector Instance + { + get + { + return m_instance; + } + } - private static GenericContentTemplateSelector m_instance = new GenericContentTemplateSelector(); + private static GenericContentTemplateSelector m_instance = new GenericContentTemplateSelector(); - #endregion + #endregion - public override DataTemplate SelectTemplate( object item, DependencyObject container ) - { - if( item == null ) - return base.SelectTemplate( item, container ); + public override DataTemplate SelectTemplate(object item, DependencyObject container) + { + if (item == null) + return base.SelectTemplate(item, container); - DataTemplate template = null; + DataTemplate template = null; - if( ( item is byte[] ) || ( item is System.Drawing.Image ) ) - { - bool useImageTemplate = false; + if ((item is byte[]) /*|| (item is System.Drawing.Image)*/) + { + bool useImageTemplate = false; + + try + { + var converter = new ImageConverter(); + useImageTemplate = (converter.Convert(item, typeof(ImageSource), null, CultureInfo.CurrentCulture) != null); + } + catch (NotSupportedException) + { + //suppress the exception, the byte[] is not an image. convertedValue will remain null + } + + if (useImageTemplate) + { + template = GenericContentTemplateSelector.GetImageTemplate(container); + } + } + else if (item is ImageSource) + { + template = GenericContentTemplateSelector.GetImageTemplate(container); + } + else if (item is bool) + { + template = GenericContentTemplateSelector.BoolTemplate; + } - try - { - var converter = new ImageConverter(); - useImageTemplate = ( converter.Convert( item, typeof( ImageSource ), null, CultureInfo.CurrentCulture ) != null ); + if (template == null) + { + template = GenericContentTemplateSelector.GetCommonTemplate(item, container); + } + + if (template != null) + return template; + + return base.SelectTemplate(item, container); } - catch( NotSupportedException ) + + private static DataTemplate GetImageTemplate(DependencyObject container) { - //suppress the exception, the byte[] is not an image. convertedValue will remain null + return GenericContentTemplateSelector.ImageTemplate; } - if( useImageTemplate ) + private static DataTemplate GetCommonTemplate(object item, DependencyObject container) { - template = GenericContentTemplateSelector.GetImageTemplate( container ); - } - } - else if( item is ImageSource ) - { - template = GenericContentTemplateSelector.GetImageTemplate( container ); - } - else if( item is bool ) - { - template = GenericContentTemplateSelector.BoolTemplate; - } - - if( template == null ) - { - template = GenericContentTemplateSelector.GetCommonTemplate( item, container ); - } - - if( template != null ) - return template; - - return base.SelectTemplate( item, container ); - } + Debug.Assert(item != null); - private static DataTemplate GetImageTemplate( DependencyObject container ) - { - return GenericContentTemplateSelector.ImageTemplate; - } + var itemType = item.GetType(); - private static DataTemplate GetCommonTemplate( object item, DependencyObject container ) - { - Debug.Assert( item != null ); + // Do not provide a template for data types that are already optimized by the framework or + // for data types that have a default template. + if (GenericContentTemplateSelector.IsTypeOptimized(itemType) + || GenericContentTemplateSelector.HasImplicitTemplate(item, itemType, container)) + return null; - var itemType = item.GetType(); + return GenericContentTemplateSelector.GetDefaultTemplate(itemType); + } - // Do not provide a template for data types that are already optimized by the framework or - // for data types that have a default template. - if( GenericContentTemplateSelector.IsTypeOptimized( itemType ) - || GenericContentTemplateSelector.HasImplicitTemplate( item, itemType, container ) ) - return null; + private static DataTemplate GetDefaultTemplate(Type type) + { + Debug.Assert(type != null); - return GenericContentTemplateSelector.GetDefaultTemplate( itemType ); - } + var converter = TypeDescriptor.GetConverter(type); + if ((converter == null) || (!converter.CanConvertTo(typeof(string)))) + return GenericContentTemplateSelector.CommonTemplate; - private static DataTemplate GetDefaultTemplate( Type type ) - { - Debug.Assert( type != null ); + var templates = GenericContentTemplateSelector.DefaultTemplates; + lock (((ICollection)templates).SyncRoot) + { + for (int i = templates.Count - 1; i >= 0; i--) + { + var target = templates[i]; + var targetTemplate = target.Value.Target as DataTemplate; - var converter = TypeDescriptor.GetConverter( type ); - if( ( converter == null ) || ( !converter.CanConvertTo( typeof( string ) ) ) ) - return GenericContentTemplateSelector.CommonTemplate; + // We have found the desired template. + if (target.Key == type) + { + if (targetTemplate != null) + return targetTemplate; - var templates = GenericContentTemplateSelector.DefaultTemplates; - lock( ( ( ICollection )templates ).SyncRoot ) - { - for( int i = templates.Count - 1; i >= 0; i-- ) - { - var target = templates[ i ]; - var targetTemplate = target.Value.Target as DataTemplate; - - // We have found the desired template. - if( target.Key == type ) - { - if( targetTemplate != null ) - return targetTemplate; - - // Unfortunately, the template has been garbage collected. - templates.RemoveAt( i ); - break; - } - } + // Unfortunately, the template has been garbage collected. + templates.RemoveAt(i); + break; + } + } - templates.TrimExcess(); + templates.TrimExcess(); - var template = GenericContentTemplateSelector.CreateDefaultTemplate( type, converter ); + var template = GenericContentTemplateSelector.CreateDefaultTemplate(type, converter); - templates.Add( new KeyValuePair( type, new WeakReference( template ) ) ); + templates.Add(new KeyValuePair(type, new WeakReference(template))); - return template; - } - } + return template; + } + } - private static DataTemplate CreateDefaultTemplate( Type type, TypeConverter converter ) - { - Debug.Assert( type != null ); - Debug.Assert( converter != null ); + private static DataTemplate CreateDefaultTemplate(Type type, TypeConverter converter) + { + Debug.Assert(type != null); + Debug.Assert(converter != null); - var template = new DataTemplate(); - var factory = new FrameworkElementFactory( typeof( TextBlock ) ); + var template = new DataTemplate(); + var factory = new FrameworkElementFactory(typeof(TextBlock)); - var binding = new Binding(); - binding.Mode = BindingMode.OneWay; - binding.Converter = new DefaultConverter( converter ); - binding.ConverterCulture = CultureInfo.CurrentCulture; + var binding = new Binding(); + binding.Mode = BindingMode.OneWay; + binding.Converter = new DefaultConverter(converter); + binding.ConverterCulture = CultureInfo.CurrentCulture; - factory.SetBinding( TextBlock.TextProperty, binding ); + factory.SetBinding(TextBlock.TextProperty, binding); - template.VisualTree = factory; - template.Seal(); + template.VisualTree = factory; + template.Seal(); - return template; - } + return template; + } - private static bool IsTypeOptimized( Type type ) - { - Debug.Assert( type != null ); + private static bool IsTypeOptimized(Type type) + { + Debug.Assert(type != null); - if( typeof( string ).IsAssignableFrom( type ) - || typeof( UIElement ).IsAssignableFrom( type ) - || typeof( XmlNode ).IsAssignableFrom( type ) ) - return true; + if (typeof(string).IsAssignableFrom(type) + || typeof(UIElement).IsAssignableFrom(type) + || typeof(XmlNode).IsAssignableFrom(type)) + return true; - if( !typeof( Inline ).IsAssignableFrom( type ) ) - { - var converter = TypeDescriptor.GetConverter( type ); - if( ( converter != null ) && ( converter.CanConvertTo( typeof( UIElement ) ) ) ) - return true; - } + if (!typeof(Inline).IsAssignableFrom(type)) + { + var converter = TypeDescriptor.GetConverter(type); + if ((converter != null) && (converter.CanConvertTo(typeof(UIElement)))) + return true; + } - return false; - } + return false; + } - private static bool HasImplicitTemplate( object item, Type type, DependencyObject container ) - { - Debug.Assert( type != null ); + private static bool HasImplicitTemplate(object item, Type type, DependencyObject container) + { + Debug.Assert(type != null); - var finder = GenericContentTemplateSelector.FindTemplateResource; + var finder = GenericContentTemplateSelector.FindTemplateResource; - if( finder == null ) - { - finder = GenericContentTemplateSelector.GetFindTemplateResourceInternal(); + if (finder == null) + { + finder = GenericContentTemplateSelector.GetFindTemplateResourceInternal(); - if( finder == null ) - { - finder = GenericContentTemplateSelector.FindTemplateResourceFallback; - } + if (finder == null) + { + finder = GenericContentTemplateSelector.FindTemplateResourceFallback; + } - GenericContentTemplateSelector.FindTemplateResource = finder; - } + GenericContentTemplateSelector.FindTemplateResource = finder; + } - Debug.Assert( finder != null ); + Debug.Assert(finder != null); - return ( finder.Invoke( container, item, type ) != null ); - } + return (finder.Invoke(container, item, type) != null); + } - private static Func GetFindTemplateResourceInternal() - { - try - { - var methodInfo = typeof( FrameworkElement ).GetMethod( - "FindTemplateResourceInternal", - BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, - null, - CallingConventions.Any, - new Type[] { typeof( DependencyObject ), typeof( object ), typeof( Type ) }, - null ); - - if( methodInfo != null ) + private static Func GetFindTemplateResourceInternal() { - var finder = ( Func )Delegate.CreateDelegate( typeof( Func ), methodInfo ); + try + { + var methodInfo = typeof(FrameworkElement).GetMethod( + "FindTemplateResourceInternal", + BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static, + null, + CallingConventions.Any, + new Type[] { typeof(DependencyObject), typeof(object), typeof(Type) }, + null); + + if (methodInfo != null) + { + var finder = (Func)Delegate.CreateDelegate(typeof(Func), methodInfo); + + return (container, item, type) => finder.Invoke(container, item, typeof(DataTemplate)); + } + } + catch (AmbiguousMatchException) + { + // We swallow the exception and use a fallback method instead. + } + catch (MethodAccessException) + { + // We swallow the exception and use a fallback method instead. + } - return ( container, item, type ) => finder.Invoke( container, item, typeof( DataTemplate ) ); + return null; } - } - catch( AmbiguousMatchException ) - { - // We swallow the exception and use a fallback method instead. - } - catch( MethodAccessException ) - { - // We swallow the exception and use a fallback method instead. - } - - return null; - } - private static object FindTemplateResourceFallback( DependencyObject container, object item, Type type ) - { - var fe = container as FrameworkElement; - if( fe == null ) - return null; + private static object FindTemplateResourceFallback(DependencyObject container, object item, Type type) + { + var fe = container as FrameworkElement; + if (fe == null) + return null; - return fe.TryFindResource( new DataTemplateKey( type ) ); - } + return fe.TryFindResource(new DataTemplateKey(type)); + } - #region DefaultConverter Private Class + #region DefaultConverter Private Class - private sealed class DefaultConverter : IValueConverter - { - internal DefaultConverter( TypeConverter converter ) - { - if( converter == null ) - throw new ArgumentNullException( "converter" ); + private sealed class DefaultConverter : IValueConverter + { + internal DefaultConverter(TypeConverter converter) + { + if (converter == null) + throw new ArgumentNullException("converter"); - m_converter = converter; - } + m_converter = converter; + } - public object Convert( object value, Type targetType, object parameter, CultureInfo culture ) - { - object result; + public object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + object result; - if( DefaultConverter.TryConvertTo( value, targetType, culture, m_converter, out result ) ) - return result; + if (DefaultConverter.TryConvertTo(value, targetType, culture, m_converter, out result)) + return result; - if( value != null ) - { - var valueType = value.GetType(); + if (value != null) + { + var valueType = value.GetType(); - if( DefaultConverter.TryConvertTo( value, targetType, culture, TypeDescriptor.GetConverter( valueType ), out result ) ) - return result; + if (DefaultConverter.TryConvertTo(value, targetType, culture, TypeDescriptor.GetConverter(valueType), out result)) + return result; - if( targetType.IsAssignableFrom( valueType ) ) - return value; - } - else if( DefaultConverter.IsNullableType( targetType ) ) - { - return value; - } + if (targetType.IsAssignableFrom(valueType)) + return value; + } + else if (DefaultConverter.IsNullableType(targetType)) + { + return value; + } - throw new ArgumentException( "Cannot convert to type " + targetType.FullName + ".", "value" ); - } - - public object ConvertBack( object value, Type targetType, object parameter, CultureInfo culture ) - { - throw new NotSupportedException(); - } + throw new ArgumentException("Cannot convert to type " + targetType.FullName + ".", "value"); + } - private static bool TryConvertTo( object value, Type targetType, CultureInfo culture, TypeConverter converter, out object result ) - { - if( converter != null ) - { - try - { - result = converter.ConvertTo( null, culture, value, targetType ); - return true; - } - catch - { - // We'll try to convert the value another way. - } - - if( ( value != null ) && ( converter.CanConvertFrom( value.GetType() ) ) ) - { - try + public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { - var newValue = converter.ConvertFrom( null, culture, value ); - result = converter.ConvertTo( null, culture, newValue, targetType ); - - return true; + throw new NotSupportedException(); } - catch + + private static bool TryConvertTo(object value, Type targetType, CultureInfo culture, TypeConverter converter, out object result) { + if (converter != null) + { + try + { + result = converter.ConvertTo(null, culture, value, targetType); + return true; + } + catch + { + // We'll try to convert the value another way. + } + + if ((value != null) && (converter.CanConvertFrom(value.GetType()))) + { + try + { + var newValue = converter.ConvertFrom(null, culture, value); + result = converter.ConvertTo(null, culture, newValue, targetType); + + return true; + } + catch + { + } + } + } + + result = null; + return false; } - } - } - result = null; - return false; - } + private static bool IsNullableType(Type type) + { + return (!type.IsValueType) + || (type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable<>))); + } - private static bool IsNullableType( Type type ) - { - return ( !type.IsValueType ) - || ( type.IsGenericType && ( type.GetGenericTypeDefinition() == typeof( Nullable<> ) ) ); - } + private readonly TypeConverter m_converter; + } - private readonly TypeConverter m_converter; + #endregion } - - #endregion - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupHeaderControl.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupHeaderControl.cs index a432d768..cb684215 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupHeaderControl.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/GroupHeaderControl.cs @@ -16,426 +16,425 @@ using System.ComponentModel; using System.Diagnostics; -using System.Drawing; using System.Windows; -using System.Windows.Automation.Peers; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; +using System.Windows.Media; using Xceed.Utils.Wpf; using Xceed.Wpf.DataGrid.Utils; namespace Xceed.Wpf.DataGrid { - public class GroupHeaderControl : ContentControl, INotifyPropertyChanged, IDataGridItemContainer - { - #region Static Fields - - internal static readonly string GroupPropertyName = PropertyHelper.GetPropertyName( ( GroupHeaderControl g ) => g.Group ); - - #endregion - - static GroupHeaderControl() + public class GroupHeaderControl : ContentControl, INotifyPropertyChanged, IDataGridItemContainer { - // This DefaultStyleKey will only be used in design-time. - DefaultStyleKeyProperty.OverrideMetadata( typeof( GroupHeaderControl ), new FrameworkPropertyMetadata( new Markup.ThemeKey( typeof( Views.TableView ), typeof( GroupHeaderControl ) ) ) ); + #region Static Fields - DataGridControl.ParentDataGridControlPropertyKey.OverrideMetadata( typeof( GroupHeaderControl ), new FrameworkPropertyMetadata( new PropertyChangedCallback( OnParentGridControlChanged ) ) ); + internal static readonly string GroupPropertyName = PropertyHelper.GetPropertyName((GroupHeaderControl g) => g.Group); - KeyboardNavigation.TabNavigationProperty.OverrideMetadata( - typeof( GroupHeaderControl ), new FrameworkPropertyMetadata( KeyboardNavigationMode.None ) ); - } + #endregion - public GroupHeaderControl() - { - this.CommandBindings.Add( new CommandBinding( DataGridCommands.ExpandGroup, - this.OnExpandExecuted, - this.OnExpandCanExecute ) ); + static GroupHeaderControl() + { + // This DefaultStyleKey will only be used in design-time. + DefaultStyleKeyProperty.OverrideMetadata(typeof(GroupHeaderControl), new FrameworkPropertyMetadata(new Markup.ThemeKey(typeof(Views.TableView), typeof(GroupHeaderControl)))); - this.CommandBindings.Add( new CommandBinding( DataGridCommands.CollapseGroup, - this.OnCollapseExecuted, - this.OnCollapseCanExecute ) ); + DataGridControl.ParentDataGridControlPropertyKey.OverrideMetadata(typeof(GroupHeaderControl), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnParentGridControlChanged))); - this.CommandBindings.Add( new CommandBinding( DataGridCommands.ToggleGroupExpansion, - this.OnToggleExecuted, - this.OnToggleCanExecute ) ); + KeyboardNavigation.TabNavigationProperty.OverrideMetadata( + typeof(GroupHeaderControl), new FrameworkPropertyMetadata(KeyboardNavigationMode.None)); + } - m_itemContainerManager = new DataGridItemContainerManager( this ); - } + public GroupHeaderControl() + { + this.CommandBindings.Add(new CommandBinding(DataGridCommands.ExpandGroup, + this.OnExpandExecuted, + this.OnExpandCanExecute)); - #region Group Internal Attached Property + this.CommandBindings.Add(new CommandBinding(DataGridCommands.CollapseGroup, + this.OnCollapseExecuted, + this.OnCollapseCanExecute)); - internal static readonly DependencyProperty GroupProperty = DependencyProperty.RegisterAttached( - "Group", typeof( Group ), typeof( GroupHeaderControl ), - new FrameworkPropertyMetadata( null, FrameworkPropertyMetadataOptions.Inherits ) ); + this.CommandBindings.Add(new CommandBinding(DataGridCommands.ToggleGroupExpansion, + this.OnToggleExecuted, + this.OnToggleCanExecute)); - internal static Group GetGroup( DependencyObject obj ) - { - return ( Group )obj.GetValue( GroupHeaderControl.GroupProperty ); - } + m_itemContainerManager = new DataGridItemContainerManager(this); + } - internal static void SetGroup( DependencyObject obj, Group value ) - { - obj.SetValue( GroupHeaderControl.GroupProperty, value ); - } + #region Group Internal Attached Property - #endregion + internal static readonly DependencyProperty GroupProperty = DependencyProperty.RegisterAttached( + "Group", typeof(Group), typeof(GroupHeaderControl), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits)); - #region Group Property + internal static Group GetGroup(DependencyObject obj) + { + return (Group)obj.GetValue(GroupHeaderControl.GroupProperty); + } - public Group Group - { - get - { - return m_group; - } - } + internal static void SetGroup(DependencyObject obj, Group value) + { + obj.SetValue(GroupHeaderControl.GroupProperty, value); + } - internal void SetGroup( Group group ) - { - m_group = group; - this.Content = m_group; - GroupHeaderControl.SetGroup( this, group ); + #endregion - this.RaisePropertyChanged( GroupHeaderControl.GroupPropertyName ); - } + #region Group Property - private Group m_group; + public Group Group + { + get + { + return m_group; + } + } - #endregion + internal void SetGroup(Group group) + { + m_group = group; + this.Content = m_group; + GroupHeaderControl.SetGroup(this, group); - #region SelectionBackground Property + this.RaisePropertyChanged(GroupHeaderControl.GroupPropertyName); + } - public static readonly DependencyProperty SelectionBackgroundProperty = Cell.SelectionBackgroundProperty.AddOwner( typeof( GroupHeaderControl ) ); + private Group m_group; - public Brush SelectionBackground - { - get - { - return ( Brush )this.GetValue( GroupHeaderControl.SelectionBackgroundProperty ); - } - set - { - this.SetValue( GroupHeaderControl.SelectionBackgroundProperty, value ); - } - } + #endregion - #endregion SelectionBackground Property + #region SelectionBackground Property - #region SelectionForeground Property + public static readonly DependencyProperty SelectionBackgroundProperty = Cell.SelectionBackgroundProperty.AddOwner(typeof(GroupHeaderControl)); - public static readonly DependencyProperty SelectionForegroundProperty = Cell.SelectionForegroundProperty.AddOwner( typeof( GroupHeaderControl ) ); + public Brush SelectionBackground + { + get + { + return (Brush)this.GetValue(GroupHeaderControl.SelectionBackgroundProperty); + } + set + { + this.SetValue(GroupHeaderControl.SelectionBackgroundProperty, value); + } + } - public Brush SelectionForeground - { - get - { - return ( Brush )this.GetValue( GroupHeaderControl.SelectionForegroundProperty ); - } - set - { - this.SetValue( GroupHeaderControl.SelectionForegroundProperty, value ); - } - } + #endregion SelectionBackground Property - #endregion SelectionForeground Property + #region SelectionForeground Property - #region InactiveSelectionBackground Property + public static readonly DependencyProperty SelectionForegroundProperty = Cell.SelectionForegroundProperty.AddOwner(typeof(GroupHeaderControl)); - public static readonly DependencyProperty InactiveSelectionBackgroundProperty = Cell.InactiveSelectionBackgroundProperty.AddOwner( typeof( GroupHeaderControl ) ); + public Brush SelectionForeground + { + get + { + return (Brush)this.GetValue(GroupHeaderControl.SelectionForegroundProperty); + } + set + { + this.SetValue(GroupHeaderControl.SelectionForegroundProperty, value); + } + } - public Brush InactiveSelectionBackground - { - get - { - return ( Brush )this.GetValue( GroupHeaderControl.InactiveSelectionBackgroundProperty ); - } - set - { - this.SetValue( GroupHeaderControl.InactiveSelectionBackgroundProperty, value ); - } - } + #endregion SelectionForeground Property - #endregion InactiveSelectionBackground Property + #region InactiveSelectionBackground Property - #region InactiveSelectionForeground Property + public static readonly DependencyProperty InactiveSelectionBackgroundProperty = Cell.InactiveSelectionBackgroundProperty.AddOwner(typeof(GroupHeaderControl)); - public static readonly DependencyProperty InactiveSelectionForegroundProperty = Cell.InactiveSelectionForegroundProperty.AddOwner( typeof( GroupHeaderControl ) ); + public Brush InactiveSelectionBackground + { + get + { + return (Brush)this.GetValue(GroupHeaderControl.InactiveSelectionBackgroundProperty); + } + set + { + this.SetValue(GroupHeaderControl.InactiveSelectionBackgroundProperty, value); + } + } - public Brush InactiveSelectionForeground - { - get - { - return ( Brush )this.GetValue( GroupHeaderControl.InactiveSelectionForegroundProperty ); - } - set - { - this.SetValue( GroupHeaderControl.InactiveSelectionForegroundProperty, value ); - } - } + #endregion InactiveSelectionBackground Property - #endregion InactiveSelectionForeground Property + #region InactiveSelectionForeground Property - #region CanBeRecycled Protected Property + public static readonly DependencyProperty InactiveSelectionForegroundProperty = Cell.InactiveSelectionForegroundProperty.AddOwner(typeof(GroupHeaderControl)); - protected virtual bool CanBeRecycled - { - get - { - if( this.IsKeyboardFocused || this.IsKeyboardFocusWithin ) - return false; + public Brush InactiveSelectionForeground + { + get + { + return (Brush)this.GetValue(GroupHeaderControl.InactiveSelectionForegroundProperty); + } + set + { + this.SetValue(GroupHeaderControl.InactiveSelectionForegroundProperty, value); + } + } - return m_itemContainerManager.CanBeRecycled; - } - } + #endregion InactiveSelectionForeground Property - #endregion + #region CanBeRecycled Protected Property - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); + protected virtual bool CanBeRecycled + { + get + { + if (this.IsKeyboardFocused || this.IsKeyboardFocusWithin) + return false; - m_itemContainerManager.Update(); - } + return m_itemContainerManager.CanBeRecycled; + } + } + #endregion - protected override void OnPreviewMouseLeftButtonUp( MouseButtonEventArgs e ) - { - base.OnPreviewMouseLeftButtonUp( e ); - return; - } + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); - protected override void OnIsKeyboardFocusWithinChanged( DependencyPropertyChangedEventArgs e ) - { - base.OnIsKeyboardFocusWithinChanged( e ); + m_itemContainerManager.Update(); + } - bool newValue = ( bool )e.NewValue; - if( newValue == true ) - { - DataGridContext dataGridContext = DataGridControl.GetDataGridContext( this ); + protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e) + { + base.OnPreviewMouseLeftButtonUp(e); + return; + } - if( dataGridContext != null ) + protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e) { - object item = dataGridContext.GetItemFromContainer( this ); + base.OnIsKeyboardFocusWithinChanged(e); - if( ( item != null ) && ( dataGridContext.InternalCurrentItem != item ) ) - { - try + bool newValue = (bool)e.NewValue; + + if (newValue == true) { - dataGridContext.SetCurrent( item, null, -1, dataGridContext.CurrentColumn, true, true, false, AutoScrollCurrentItemSourceTriggers.FocusChanged ); + DataGridContext dataGridContext = DataGridControl.GetDataGridContext(this); + + if (dataGridContext != null) + { + object item = dataGridContext.GetItemFromContainer(this); + + if ((item != null) && (dataGridContext.InternalCurrentItem != item)) + { + try + { + dataGridContext.SetCurrent(item, null, -1, dataGridContext.CurrentColumn, true, true, false, AutoScrollCurrentItemSourceTriggers.FocusChanged); + } + catch (DataGridException) + { + // We swallow the exception if it occurs because of a validation error or Cell was read-only or + // any other GridException. + } + } + } } - catch( DataGridException ) + } + + protected virtual void PrepareContainer(DataGridContext dataGridContext, object item) + { + m_isRecyclingCandidate = false; + + if (m_isContainerPrepared) + Debug.Fail("A GroupHeaderControl can't be prepared twice, it must be cleaned before PrepareContainer is called again"); + + Group group = null; + DataGridContext gridContext = DataGridControl.GetDataGridContext(this); + + if (gridContext != null) { - // We swallow the exception if it occurs because of a validation error or Cell was read-only or - // any other GridException. + object dataItem = gridContext.GetItemFromContainer(this); + if (dataItem != null) + { + group = gridContext.GetGroupFromItem(dataItem); + } } - } - } - } - } - protected virtual void PrepareContainer( DataGridContext dataGridContext, object item ) - { - m_isRecyclingCandidate = false; + this.SetGroup(group); - if( m_isContainerPrepared ) - Debug.Fail( "A GroupHeaderControl can't be prepared twice, it must be cleaned before PrepareContainer is called again" ); + m_itemContainerManager.Prepare(gridContext, item); - Group group = null; - DataGridContext gridContext = DataGridControl.GetDataGridContext( this ); + m_isContainerPrepared = true; + } - if( gridContext != null ) - { - object dataItem = gridContext.GetItemFromContainer( this ); - if( dataItem != null ) + protected virtual void ClearContainer() { - group = gridContext.GetGroupFromItem( dataItem ); + m_itemContainerManager.Clear(m_isRecyclingCandidate); + m_isContainerPrepared = false; } - } - - this.SetGroup( group ); - m_itemContainerManager.Prepare( gridContext, item ); - - m_isContainerPrepared = true; - } + protected internal virtual void PrepareDefaultStyleKey(Xceed.Wpf.DataGrid.Views.ViewBase view) + { + this.DefaultStyleKey = view.GetDefaultStyleKey(typeof(GroupHeaderControl)); + } - protected virtual void ClearContainer() - { - m_itemContainerManager.Clear( m_isRecyclingCandidate ); - m_isContainerPrepared = false; - } + protected internal virtual bool ShouldHandleSelectionEvent(InputEventArgs eventArgs) + { + var targetChild = eventArgs.OriginalSource as DependencyObject; - protected internal virtual void PrepareDefaultStyleKey( Xceed.Wpf.DataGrid.Views.ViewBase view ) - { - this.DefaultStyleKey = view.GetDefaultStyleKey( typeof( GroupHeaderControl ) ); - } + // If the event is comming from a specific control inside the header (GroupNavigationControl or Collapsed button), + // ignore the event since it is not for selection purposes that the user targeted this control. + var collapsedButtonParent = TreeHelper.FindParent(targetChild, true, null, this); + if (collapsedButtonParent != null) + return false; - protected internal virtual bool ShouldHandleSelectionEvent( InputEventArgs eventArgs ) - { - var targetChild = eventArgs.OriginalSource as DependencyObject; + var groupNavigationControlParent = TreeHelper.FindParent(targetChild, true, null, this); + if (groupNavigationControlParent != null) + return false; - // If the event is comming from a specific control inside the header (GroupNavigationControl or Collapsed button), - // ignore the event since it is not for selection purposes that the user targeted this control. - var collapsedButtonParent = TreeHelper.FindParent( targetChild, true, null, this ); - if( collapsedButtonParent != null ) - return false; + return true; + } - var groupNavigationControlParent = TreeHelper.FindParent( targetChild, true, null, this ); - if( groupNavigationControlParent != null ) - return false; + private static void OnParentGridControlChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + DataGridControl grid = e.NewValue as DataGridControl; + GroupHeaderControl groupHeaderControl = sender as GroupHeaderControl; - return true; - } + if ((groupHeaderControl != null) && (grid != null)) + { + groupHeaderControl.PrepareDefaultStyleKey(grid.GetView()); + } + } - private static void OnParentGridControlChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - DataGridControl grid = e.NewValue as DataGridControl; - GroupHeaderControl groupHeaderControl = sender as GroupHeaderControl; + private void OnExpandCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = false; - if( ( groupHeaderControl != null ) && ( grid != null ) ) - { - groupHeaderControl.PrepareDefaultStyleKey( grid.GetView() ); - } - } + if (e.Parameter == null) + { + //can execute the Expand command if the group is NOT expanded. + e.CanExecute = !this.FindGroupCommandTarget(e.OriginalSource).IsExpanded; + } + } - private void OnExpandCanExecute( object sender, CanExecuteRoutedEventArgs e ) - { - e.CanExecute = false; + private void OnExpandExecuted(object sender, ExecutedRoutedEventArgs e) + { + this.FindGroupCommandTarget(e.OriginalSource).IsExpanded = true; + } - if( e.Parameter == null ) - { - //can execute the Expand command if the group is NOT expanded. - e.CanExecute = !this.FindGroupCommandTarget( e.OriginalSource ).IsExpanded; - } - } + private void OnCollapseCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = false; - private void OnExpandExecuted( object sender, ExecutedRoutedEventArgs e ) - { - this.FindGroupCommandTarget( e.OriginalSource ).IsExpanded = true; - } + if (e.Parameter == null) + { + //can execute the Collapse command if the group is expanded. + e.CanExecute = this.FindGroupCommandTarget(e.OriginalSource).IsExpanded; + } + } - private void OnCollapseCanExecute( object sender, CanExecuteRoutedEventArgs e ) - { - e.CanExecute = false; + private void OnCollapseExecuted(object sender, ExecutedRoutedEventArgs e) + { + this.FindGroupCommandTarget(e.OriginalSource).IsExpanded = false; + } - if( e.Parameter == null ) - { - //can execute the Collapse command if the group is expanded. - e.CanExecute = this.FindGroupCommandTarget( e.OriginalSource ).IsExpanded; - } - } + private void OnToggleCanExecute(object sender, CanExecuteRoutedEventArgs e) + { + e.CanExecute = false; - private void OnCollapseExecuted( object sender, ExecutedRoutedEventArgs e ) - { - this.FindGroupCommandTarget( e.OriginalSource ).IsExpanded = false; - } + if (e.Parameter == null) + { + e.CanExecute = true; //can always toggle + } + } - private void OnToggleCanExecute( object sender, CanExecuteRoutedEventArgs e ) - { - e.CanExecute = false; + private void OnToggleExecuted(object sender, ExecutedRoutedEventArgs e) + { + Group group = FindGroupCommandTarget(e.OriginalSource); - if( e.Parameter == null ) - { - e.CanExecute = true; //can always toggle - } - } + group.IsExpanded = !group.IsExpanded; + } - private void OnToggleExecuted( object sender, ExecutedRoutedEventArgs e ) - { - Group group = FindGroupCommandTarget( e.OriginalSource ); + // We use an ItemsControl inside the GroupHeaderControl to represent the + // ancestors (ParentGroups) of this.Group, and each item in this ItemsControl + // is a Group templated to look like a single, stand-alone GroupHeaderControl. + // + // In the ItemTemplate for each Group in the ItemsControl, we have a Border that + // declares some InputBindings to the group commands. In this case, we want to + // execute the command on this specific instance of Group, which is the DataContext + // of the Border. + private Group FindGroupCommandTarget(object originalSource) + { + object dataContext = null; - group.IsExpanded = !group.IsExpanded; - } + FrameworkElement fe = originalSource as FrameworkElement; + if (fe != null) + { + dataContext = fe.DataContext; + } + else + { + FrameworkContentElement fce = originalSource as FrameworkContentElement; + if (fce != null) + { + dataContext = fce.DataContext; + } + } - // We use an ItemsControl inside the GroupHeaderControl to represent the - // ancestors (ParentGroups) of this.Group, and each item in this ItemsControl - // is a Group templated to look like a single, stand-alone GroupHeaderControl. - // - // In the ItemTemplate for each Group in the ItemsControl, we have a Border that - // declares some InputBindings to the group commands. In this case, we want to - // execute the command on this specific instance of Group, which is the DataContext - // of the Border. - private Group FindGroupCommandTarget( object originalSource ) - { - object dataContext = null; + Group groupCommandTarget = dataContext as Group; - FrameworkElement fe = originalSource as FrameworkElement; - if( fe != null ) - { - dataContext = fe.DataContext; - } - else - { - FrameworkContentElement fce = originalSource as FrameworkContentElement; - if( fce != null ) - { - dataContext = fce.DataContext; + return (groupCommandTarget != null) ? groupCommandTarget : this.Group; } - } - Group groupCommandTarget = dataContext as Group; + #region INotifyPropertyChanged Members - return ( groupCommandTarget != null ) ? groupCommandTarget : this.Group; - } + public event PropertyChangedEventHandler PropertyChanged; - #region INotifyPropertyChanged Members + private void RaisePropertyChanged(string propertyName) + { + var handler = this.PropertyChanged; + if (handler == null) + return; - public event PropertyChangedEventHandler PropertyChanged; + handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } - private void RaisePropertyChanged( string propertyName ) - { - var handler = this.PropertyChanged; - if( handler == null ) - return; + #endregion - handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); - } + #region IDataGridItemContainer Members - #endregion + bool IDataGridItemContainer.CanBeRecycled + { + get + { + return this.CanBeRecycled; + } + } - #region IDataGridItemContainer Members + bool IDataGridItemContainer.IsRecyclingCandidate + { + get + { + return m_isRecyclingCandidate; + } + set + { + m_isRecyclingCandidate = value; + } + } - bool IDataGridItemContainer.CanBeRecycled - { - get - { - return this.CanBeRecycled; - } - } + void IDataGridItemContainer.PrepareContainer(DataGridContext dataGridContext, object item) + { + this.PrepareContainer(dataGridContext, item); + } - bool IDataGridItemContainer.IsRecyclingCandidate - { - get - { - return m_isRecyclingCandidate; - } - set - { - m_isRecyclingCandidate = value; - } - } + void IDataGridItemContainer.ClearContainer() + { + this.ClearContainer(); + } - void IDataGridItemContainer.PrepareContainer( DataGridContext dataGridContext, object item ) - { - this.PrepareContainer( dataGridContext, item ); - } + void IDataGridItemContainer.CleanRecyclingCandidate() + { + m_itemContainerManager.CleanRecyclingCandidates(); + } - void IDataGridItemContainer.ClearContainer() - { - this.ClearContainer(); - } + #endregion - void IDataGridItemContainer.CleanRecyclingCandidate() - { - m_itemContainerManager.CleanRecyclingCandidates(); + private readonly DataGridItemContainerManager m_itemContainerManager; + private bool m_isContainerPrepared; + private bool m_isRecyclingCandidate; } - - #endregion - - private readonly DataGridItemContainerManager m_itemContainerManager; - private bool m_isContainerPrepared; - private bool m_isRecyclingCandidate; - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceHelper.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceHelper.cs index bd6e7139..d4d30326 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceHelper.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/ItemsSourceHelper.cs @@ -20,7 +20,8 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Data; -using System.Data.Objects.DataClasses; +using System.Data.Entity; +using System.Data.Entity.Core.Objects.DataClasses; using System.Diagnostics; using System.Globalization; using System.Linq; @@ -35,2685 +36,2685 @@ using Xceed.Wpf.DataGrid.ValidationRules; namespace Xceed.Wpf.DataGrid { - internal static class ItemsSourceHelper - { - #region Static Fields + internal static class ItemsSourceHelper + { + #region Static Fields - private static readonly Type EntityObjectType = Type.GetType( - "System.Data.Objects.DataClasses.EntityObject, System.Data.Entity, Version=" + _XceedVersionInfo.FrameworkVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089", - false, false ); + private static readonly Type EntityObjectType = Type.GetType( + "System.Data.Objects.DataClasses.EntityObject, System.Data.Entity, Version=" + _XceedVersionInfo.FrameworkVersion + ", Culture=neutral, PublicKeyToken=b77a5c561934e089", + false, false); - #endregion + #endregion - internal static bool IsSourceSupportingChangeNotification( object source ) - { - if( source is INotifyCollectionChanged ) - return true; + internal static bool IsSourceSupportingChangeNotification(object source) + { + if (source is INotifyCollectionChanged) + return true; - var collection = source as IBindingList; + var collection = source as IBindingList; - return ( collection != null ) - && ( collection.SupportsChangeNotification ); - } + return (collection != null) + && (collection.SupportsChangeNotification); + } - private static bool IsSupportingDBNull( IEnumerable source ) - { - // return false because all the DBNull conversion should have been done in the DataGridCollectionView.ItemProperties converter. - if( source is DataGridCollectionView ) - return false; + private static bool IsSupportingDBNull(IEnumerable source) + { + // return false because all the DBNull conversion should have been done in the DataGridCollectionView.ItemProperties converter. + if (source is DataGridCollectionView) + return false; - if( source is DataView ) - return true; + if (source is DataView) + return true; - var collectionView = source as CollectionView; - if( collectionView != null ) - return ItemsSourceHelper.IsSupportingDBNull( collectionView.SourceCollection ); + var collectionView = source as CollectionView; + if (collectionView != null) + return ItemsSourceHelper.IsSupportingDBNull(collectionView.SourceCollection); - return false; - } + return false; + } - internal static bool IsItemSupportingDBNull( object source ) - { - return ( source is System.Data.DataRow ) - || ( source is DataRowView ); - } + internal static bool IsItemSupportingDBNull(object source) + { + return (source is System.Data.DataRow) + || (source is DataRowView); + } - internal static bool IsDataView( IEnumerable source ) - { - if( source is DataGridCollectionView ) - return false; + internal static bool IsDataView(IEnumerable source) + { + if (source is DataGridCollectionView) + return false; - if( source is DataView ) - return true; + if (source is DataView) + return true; - var collectionView = source as CollectionView; + var collectionView = source as CollectionView; - return ( collectionView != null ) - && ( collectionView.SourceCollection is DataView ); - } + return (collectionView != null) + && (collectionView.SourceCollection is DataView); + } - internal static IList TryGetIList( IEnumerable itemsSourceCollection ) - { - var collectionView = itemsSourceCollection as ItemCollection; - if( collectionView != null ) - { - var list = collectionView.SourceCollection as IList; - if( list != null ) - return list; - } - - return itemsSourceCollection as IList; - } + internal static IList TryGetIList(IEnumerable itemsSourceCollection) + { + var collectionView = itemsSourceCollection as ItemCollection; + if (collectionView != null) + { + var list = collectionView.SourceCollection as IList; + if (list != null) + return list; + } - private static bool IsValueType( Type itemType ) - { - if( typeof( string ) == itemType ) - return true; + return itemsSourceCollection as IList; + } - if( !itemType.IsValueType ) - return false; + private static bool IsValueType(Type itemType) + { + if (typeof(string) == itemType) + return true; - return ( itemType.IsPrimitive ) - || ( typeof( decimal ) == itemType ) - || ( typeof( DateTime ) == itemType ) - || ( typeof( TimeSpan ) == itemType ) - || ( typeof( Guid ) == itemType ); - } + if (!itemType.IsValueType) + return false; - internal static bool IsEntityObjectLoadable( EntityObject entityObject ) - { - return ( ( entityObject.EntityState & EntityState.Added ) != EntityState.Added ) - && ( ( entityObject.EntityState & EntityState.Detached ) != EntityState.Detached ); - } + return (itemType.IsPrimitive) + || (typeof(decimal) == itemType) + || (typeof(DateTime) == itemType) + || (typeof(TimeSpan) == itemType) + || (typeof(Guid) == itemType); + } - private static bool IsEntityFramework( Type itemType ) - { - var entityObjectType = ItemsSourceHelper.EntityObjectType; + internal static bool IsEntityObjectLoadable(EntityObject entityObject) + { + return ((entityObject.EntityState & EntityState.Added) != EntityState.Added) + && ((entityObject.EntityState & EntityState.Detached) != EntityState.Detached); + } - // The EntityFramework assembly is not loaded. We are running on the client framework. - return ( entityObjectType != null ) - && ( entityObjectType.IsAssignableFrom( itemType ) ); - } + private static bool IsEntityFramework(Type itemType) + { + var entityObjectType = ItemsSourceHelper.EntityObjectType; - internal static bool IsEntityFramework( object source ) - { - return ( source != null ) - && ( ItemsSourceHelper.IsEntityFramework( source.GetType() ) ); - } + // The EntityFramework assembly is not loaded. We are running on the client framework. + return (entityObjectType != null) + && (entityObjectType.IsAssignableFrom(itemType)); + } - internal static object GetFirstItemByEnumerable( IEnumerable source ) - { - if( source == null ) - return null; + internal static bool IsEntityFramework(object source) + { + return (source != null) + && (ItemsSourceHelper.IsEntityFramework(source.GetType())); + } - return source.Cast().FirstOrDefault(); - } + internal static object GetFirstItemByEnumerable(IEnumerable source) + { + if (source == null) + return null; - internal static DataGridItemPropertyCollection GetRootCollection( DataGridItemPropertyCollection collection ) - { - if( collection == null ) - return null; + return source.Cast().FirstOrDefault(); + } - var owner = collection.Owner; - if( owner == null ) - return collection; + internal static DataGridItemPropertyCollection GetRootCollection(DataGridItemPropertyCollection collection) + { + if (collection == null) + return null; - return ItemsSourceHelper.GetRootCollection( owner ); - } + var owner = collection.Owner; + if (owner == null) + return collection; - internal static DataGridItemPropertyCollection GetRootCollection( DataGridItemPropertyBase itemProperty ) - { - if( itemProperty == null ) - return null; + return ItemsSourceHelper.GetRootCollection(owner); + } - return ItemsSourceHelper.GetRootCollection( itemProperty.ContainingCollection ); - } + internal static DataGridItemPropertyCollection GetRootCollection(DataGridItemPropertyBase itemProperty) + { + if (itemProperty == null) + return null; - internal static object AddNewDataItem( IEnumerable itemsSourceCollection, DataGridControl dataGridControl, out int itemIndex ) - { - var dataGridCollectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - { - if( !dataGridCollectionViewBase.CanAddNew ) - throw new InvalidOperationException( "An attempt was made to add a new data item to a source that does not support insertion." ); + return ItemsSourceHelper.GetRootCollection(itemProperty.ContainingCollection); + } - itemIndex = dataGridCollectionViewBase.Count; + internal static object AddNewDataItem(IEnumerable itemsSourceCollection, DataGridControl dataGridControl, out int itemIndex) + { + var dataGridCollectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + { + if (!dataGridCollectionViewBase.CanAddNew) + throw new InvalidOperationException("An attempt was made to add a new data item to a source that does not support insertion."); - return dataGridCollectionViewBase.AddNew(); - } + itemIndex = dataGridCollectionViewBase.Count; + + return dataGridCollectionViewBase.AddNew(); + } - var newItem = default( object ); + var newItem = default(object); - if( ( dataGridControl != null ) && ( dataGridControl.ItemsSource == null ) ) - { - //unbound + if ((dataGridControl != null) && (dataGridControl.ItemsSource == null)) + { + //unbound #pragma warning disable 618 - var eventArgs = new AddingNewDataItemEventArgs(); - dataGridControl.OnAddingNewDataItem( eventArgs ); + var eventArgs = new AddingNewDataItemEventArgs(); + dataGridControl.OnAddingNewDataItem(eventArgs); - newItem = eventArgs.DataItem; + newItem = eventArgs.DataItem; #pragma warning restore 618 - if( newItem == null ) - throw new InvalidOperationException( "The AddingNewDataItem event did not return a new data item because the grid is not bound to a data source." ); - - itemIndex = dataGridControl.Items.Add( newItem ); + if (newItem == null) + throw new InvalidOperationException("The AddingNewDataItem event did not return a new data item because the grid is not bound to a data source."); - return newItem; - } + itemIndex = dataGridControl.Items.Add(newItem); - var dataView = itemsSourceCollection as DataView; - if( dataView == null ) - { - var collectionView = itemsSourceCollection as CollectionView; - - dataView = ( collectionView == null ) ? null : collectionView.SourceCollection as DataView; - } + return newItem; + } - if( dataView != null ) - { - itemIndex = dataView.Count; + var dataView = itemsSourceCollection as DataView; + if (dataView == null) + { + var collectionView = itemsSourceCollection as CollectionView; - return dataView.AddNew(); - } + dataView = (collectionView == null) ? null : collectionView.SourceCollection as DataView; + } - var bindingList = itemsSourceCollection as IBindingList; - if( bindingList == null ) - { - var collectionView = itemsSourceCollection as CollectionView; + if (dataView != null) + { + itemIndex = dataView.Count; - bindingList = ( collectionView == null ) ? null : collectionView.SourceCollection as IBindingList; - } + return dataView.AddNew(); + } - if( ( bindingList != null ) && ( bindingList.AllowNew ) ) - { - itemIndex = bindingList.Count; - newItem = bindingList.AddNew(); - } - else - { - var itemType = ItemsSourceHelper.GetItemTypeFromEnumeration( itemsSourceCollection ); - if( itemType == null ) - throw new InvalidOperationException( "An attempt was made to use a source whose item type cannot be determined." ); + var bindingList = itemsSourceCollection as IBindingList; + if (bindingList == null) + { + var collectionView = itemsSourceCollection as CollectionView; - try - { - itemIndex = -1; - newItem = Activator.CreateInstance( itemType ); - } - catch( MissingMethodException exception ) - { - throw new InvalidOperationException( "An attempt was made to use a source whose item type does not have a default constructor.", exception ); - } - catch( Exception exception ) - { - throw new InvalidOperationException( "An unsuccessful attempt was made to create an instance of the source's item type using the item's default constructor.", exception ); - } - } + bindingList = (collectionView == null) ? null : collectionView.SourceCollection as IBindingList; + } - var initializableObject = ItemsSourceHelper.GetSupportInitializeObject( newItem ); - if( initializableObject != null ) - { - initializableObject.BeginInit(); - } + if ((bindingList != null) && (bindingList.AllowNew)) + { + itemIndex = bindingList.Count; + newItem = bindingList.AddNew(); + } + else + { + var itemType = ItemsSourceHelper.GetItemTypeFromEnumeration(itemsSourceCollection); + if (itemType == null) + throw new InvalidOperationException("An attempt was made to use a source whose item type cannot be determined."); + + try + { + itemIndex = -1; + newItem = Activator.CreateInstance(itemType); + } + catch (MissingMethodException exception) + { + throw new InvalidOperationException("An attempt was made to use a source whose item type does not have a default constructor.", exception); + } + catch (Exception exception) + { + throw new InvalidOperationException("An unsuccessful attempt was made to create an instance of the source's item type using the item's default constructor.", exception); + } + } - var editableObject = ItemsSourceHelper.GetEditableObject( newItem ); - if( editableObject != null ) - { - editableObject.BeginEdit(); - } + var initializableObject = ItemsSourceHelper.GetSupportInitializeObject(newItem); + if (initializableObject != null) + { + initializableObject.BeginInit(); + } - return newItem; - } + var editableObject = ItemsSourceHelper.GetEditableObject(newItem); + if (editableObject != null) + { + editableObject.BeginEdit(); + } - internal static void CancelNewDataItem( IEnumerable itemsSourceCollection, DataGridControl dataGridControl, object newItem, int newItemIndex ) - { - var dataGridCollectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - { - if( dataGridCollectionViewBase.CurrentAddItem == newItem ) - { - // The DataGridCollectionViewBase's CancelNew will take care of calling the item's CancelEdit if it must do so. - dataGridCollectionViewBase.CancelNew(); + return newItem; } - return; - } - - //if unbound - if( ( dataGridControl != null ) && ( dataGridControl.ItemsSource == null ) ) - return; + internal static void CancelNewDataItem(IEnumerable itemsSourceCollection, DataGridControl dataGridControl, object newItem, int newItemIndex) + { + var dataGridCollectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + { + if (dataGridCollectionViewBase.CurrentAddItem == newItem) + { + // The DataGridCollectionViewBase's CancelNew will take care of calling the item's CancelEdit if it must do so. + dataGridCollectionViewBase.CancelNew(); + } - var editableObject = ItemsSourceHelper.GetEditableObject( newItem ); - if( editableObject != null ) - { - editableObject.CancelEdit(); - } + return; + } - var initializableObject = ItemsSourceHelper.GetSupportInitializeObject( newItem ); - if( initializableObject != null ) - { - initializableObject.EndInit(); - } + //if unbound + if ((dataGridControl != null) && (dataGridControl.ItemsSource == null)) + return; - if( ItemsSourceHelper.IsEditableObjectInsertedOrRemovedFromDataSourceAutomatically( editableObject ) ) - return; + var editableObject = ItemsSourceHelper.GetEditableObject(newItem); + if (editableObject != null) + { + editableObject.CancelEdit(); + } - var cancelAddNew = itemsSourceCollection as ICancelAddNew; - if( cancelAddNew == null ) - { - var collectionView = itemsSourceCollection as CollectionView; + var initializableObject = ItemsSourceHelper.GetSupportInitializeObject(newItem); + if (initializableObject != null) + { + initializableObject.EndInit(); + } - cancelAddNew = ( collectionView == null ) ? null : collectionView.SourceCollection as ICancelAddNew; - } + if (ItemsSourceHelper.IsEditableObjectInsertedOrRemovedFromDataSourceAutomatically(editableObject)) + return; - if( cancelAddNew != null ) - { - cancelAddNew.CancelNew( newItemIndex ); - return; - } + var cancelAddNew = itemsSourceCollection as ICancelAddNew; + if (cancelAddNew == null) + { + var collectionView = itemsSourceCollection as CollectionView; - if( newItemIndex >= 0 ) - { - var list = itemsSourceCollection as IList; - if( list == null ) - { - var collectionView = itemsSourceCollection as CollectionView; + cancelAddNew = (collectionView == null) ? null : collectionView.SourceCollection as ICancelAddNew; + } - list = ( collectionView == null ) ? null : collectionView.SourceCollection as IList; - } + if (cancelAddNew != null) + { + cancelAddNew.CancelNew(newItemIndex); + return; + } - if( ( list != null ) && ( !list.IsFixedSize ) ) - { - list.RemoveAt( newItemIndex ); + if (newItemIndex >= 0) + { + var list = itemsSourceCollection as IList; + if (list == null) + { + var collectionView = itemsSourceCollection as CollectionView; + + list = (collectionView == null) ? null : collectionView.SourceCollection as IList; + } + + if ((list != null) && (!list.IsFixedSize)) + { + list.RemoveAt(newItemIndex); + } + } } - } - } - internal static void EndNewDataItem( IEnumerable itemsSourceCollection, DataGridControl dataGridControl, object newItem, ref int newItemIndex ) - { - var dataGridCollectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionViewBase != null ) - { - if( dataGridCollectionViewBase.CurrentAddItem == newItem ) + internal static void EndNewDataItem(IEnumerable itemsSourceCollection, DataGridControl dataGridControl, object newItem, ref int newItemIndex) { - // The DataGridCollectionViewBase's EndNew will take care of calling the item's EndEdit if it must do so. - dataGridCollectionViewBase.CommitNew(); - } - - return; - } - - //if unbound - if( ( dataGridControl != null ) && ( dataGridControl.ItemsSource == null ) ) - return; + var dataGridCollectionViewBase = itemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionViewBase != null) + { + if (dataGridCollectionViewBase.CurrentAddItem == newItem) + { + // The DataGridCollectionViewBase's EndNew will take care of calling the item's EndEdit if it must do so. + dataGridCollectionViewBase.CommitNew(); + } - var editableObject = ItemsSourceHelper.GetEditableObject( newItem ); - if( editableObject != null ) - { - editableObject.EndEdit(); - } + return; + } - var initializableObject = ItemsSourceHelper.GetSupportInitializeObject( newItem ); - if( initializableObject != null ) - { - initializableObject.EndInit(); - } + //if unbound + if ((dataGridControl != null) && (dataGridControl.ItemsSource == null)) + return; - if( ItemsSourceHelper.IsEditableObjectInsertedOrRemovedFromDataSourceAutomatically( editableObject ) ) - return; + var editableObject = ItemsSourceHelper.GetEditableObject(newItem); + if (editableObject != null) + { + editableObject.EndEdit(); + } - var cancelAddNew = itemsSourceCollection as ICancelAddNew; - if( cancelAddNew == null ) - { - var collectionView = itemsSourceCollection as CollectionView; + var initializableObject = ItemsSourceHelper.GetSupportInitializeObject(newItem); + if (initializableObject != null) + { + initializableObject.EndInit(); + } - cancelAddNew = ( collectionView == null ) ? null : collectionView.SourceCollection as ICancelAddNew; - } + if (ItemsSourceHelper.IsEditableObjectInsertedOrRemovedFromDataSourceAutomatically(editableObject)) + return; - if( cancelAddNew != null ) - { - cancelAddNew.EndNew( newItemIndex ); - return; - } + var cancelAddNew = itemsSourceCollection as ICancelAddNew; + if (cancelAddNew == null) + { + var collectionView = itemsSourceCollection as CollectionView; - var bindingList = itemsSourceCollection as IBindingList; - if( bindingList == null ) - { - var collectionView = itemsSourceCollection as CollectionView; + cancelAddNew = (collectionView == null) ? null : collectionView.SourceCollection as ICancelAddNew; + } - bindingList = ( collectionView == null ) ? null : collectionView.SourceCollection as IBindingList; - } + if (cancelAddNew != null) + { + cancelAddNew.EndNew(newItemIndex); + return; + } - // If the item is already added into the list by IBindingList.AddNew. - if( ( bindingList != null ) && ( bindingList.AllowNew ) ) - return; + var bindingList = itemsSourceCollection as IBindingList; + if (bindingList == null) + { + var collectionView = itemsSourceCollection as CollectionView; - var list = itemsSourceCollection as IList; - if( list == null ) - { - var collectionView = itemsSourceCollection as CollectionView; + bindingList = (collectionView == null) ? null : collectionView.SourceCollection as IBindingList; + } - list = ( collectionView == null ) ? null : collectionView.SourceCollection as IList; - } + // If the item is already added into the list by IBindingList.AddNew. + if ((bindingList != null) && (bindingList.AllowNew)) + return; - if( ( list == null ) || ( list.IsFixedSize ) ) - throw new InvalidOperationException( "An attempt was made to insert an item into a source that does not implement the IList interface or that has a fixed size." ); + var list = itemsSourceCollection as IList; + if (list == null) + { + var collectionView = itemsSourceCollection as CollectionView; - newItemIndex = list.Count; - list.Add( newItem ); - } + list = (collectionView == null) ? null : collectionView.SourceCollection as IList; + } - private static PropertyDescription GetPropertyDescriptionFromItemProperty( PropertyDescriptionRouteDictionary propertyDescriptions, DataGridItemPropertyRoute itemPropertyRoute ) - { - if( ( propertyDescriptions == null ) || ( itemPropertyRoute == null ) ) - return null; + if ((list == null) || (list.IsFixedSize)) + throw new InvalidOperationException("An attempt was made to insert an item into a source that does not implement the IList interface or that has a fixed size."); - var propertyRoute = PropertyRouteBuilder.ToPropertyRoute( itemPropertyRoute ); - if( propertyRoute == null ) - return null; + newItemIndex = list.Count; + list.Add(newItem); + } - PropertyDescriptionRoute propertyDescription; - if( !propertyDescriptions.TryGetValue( propertyRoute, out propertyDescription ) ) - return null; + private static PropertyDescription GetPropertyDescriptionFromItemProperty(PropertyDescriptionRouteDictionary propertyDescriptions, DataGridItemPropertyRoute itemPropertyRoute) + { + if ((propertyDescriptions == null) || (itemPropertyRoute == null)) + return null; - return propertyDescription.Current; - } + var propertyRoute = PropertyRouteBuilder.ToPropertyRoute(itemPropertyRoute); + if (propertyRoute == null) + return null; - internal static void CreateAndAddItemPropertiesForPropertyDescriptions( DataGridItemPropertyCollection itemProperties, IEnumerable propertyDescriptions ) - { - if( ( itemProperties == null ) || ( propertyDescriptions == null ) ) - return; + PropertyDescriptionRoute propertyDescription; + if (!propertyDescriptions.TryGetValue(propertyRoute, out propertyDescription)) + return null; - using( itemProperties.DeferCollectionChanged() ) - { - foreach( var propertyDescription in propertyDescriptions ) - { - ItemsSourceHelper.CreateAndAddItemPropertyForPropertyDescription( itemProperties, propertyDescription ); + return propertyDescription.Current; } - } - } - internal static void CreateAndAddItemPropertyForPropertyDescription( DataGridItemPropertyCollection itemProperties, PropertyDescriptionRoute propertyDescription ) - { - if( ( itemProperties == null ) || ( propertyDescription == null ) ) - return; + internal static void CreateAndAddItemPropertiesForPropertyDescriptions(DataGridItemPropertyCollection itemProperties, IEnumerable propertyDescriptions) + { + if ((itemProperties == null) || (propertyDescriptions == null)) + return; - if( !propertyDescription.Current.IsBrowsable ) - return; + using (itemProperties.DeferCollectionChanged()) + { + foreach (var propertyDescription in propertyDescriptions) + { + ItemsSourceHelper.CreateAndAddItemPropertyForPropertyDescription(itemProperties, propertyDescription); + } + } + } - var ancestors = new Stack(); - for( var current = propertyDescription; current != null; current = current.Parent ) - { - var description = current.Current; - if( description.IsSubRelationship ) - return; + internal static void CreateAndAddItemPropertyForPropertyDescription(DataGridItemPropertyCollection itemProperties, PropertyDescriptionRoute propertyDescription) + { + if ((itemProperties == null) || (propertyDescription == null)) + return; - ancestors.Push( description ); - } + if (!propertyDescription.Current.IsBrowsable) + return; - var parentItemProperty = default( DataGridItemPropertyBase ); - var isRoot = true; + var ancestors = new Stack(); + for (var current = propertyDescription; current != null; current = current.Parent) + { + var description = current.Current; + if (description.IsSubRelationship) + return; - while( ancestors.Count > 0 ) - { - var description = ancestors.Pop(); - var itemProperty = ( isRoot ) ? itemProperties[ description.Name ] : parentItemProperty.ItemProperties[ description.Name ]; + ancestors.Push(description); + } - if( itemProperty == null ) - { - itemProperty = ItemsSourceHelper.CreateItemPropertyFromPropertyDescription( description ); - Debug.Assert( itemProperty != null ); + var parentItemProperty = default(DataGridItemPropertyBase); + var isRoot = true; - if( isRoot ) - { - itemProperties.Add( itemProperty ); - } - else - { - Debug.Assert( parentItemProperty != null ); - parentItemProperty.ItemProperties.Add( itemProperty ); - } + while (ancestors.Count > 0) + { + var description = ancestors.Pop(); + var itemProperty = (isRoot) ? itemProperties[description.Name] : parentItemProperty.ItemProperties[description.Name]; + + if (itemProperty == null) + { + itemProperty = ItemsSourceHelper.CreateItemPropertyFromPropertyDescription(description); + Debug.Assert(itemProperty != null); + + if (isRoot) + { + itemProperties.Add(itemProperty); + } + else + { + Debug.Assert(parentItemProperty != null); + parentItemProperty.ItemProperties.Add(itemProperty); + } + } + + parentItemProperty = itemProperty; + isRoot = false; + } } - parentItemProperty = itemProperty; - isRoot = false; - } - } + internal static void CreateColumnsFromPropertyDescriptions( + ColumnHierarchyManager columnManager, + IDictionary defaultCellEditors, + PropertyDescriptionRouteDictionary propertyDescriptions, + bool autoCreateForeignKeyConfigurations) + { + Debug.Assert(columnManager != null); - internal static void CreateColumnsFromPropertyDescriptions( - ColumnHierarchyManager columnManager, - IDictionary defaultCellEditors, - PropertyDescriptionRouteDictionary propertyDescriptions, - bool autoCreateForeignKeyConfigurations ) - { - Debug.Assert( columnManager != null ); + var columns = columnManager.Columns; - var columns = columnManager.Columns; + using (columnManager.DeferUpdate()) + { + using (columns.DeferNotifications()) + { + foreach (var propertyDescriptionRoute in propertyDescriptions.Values) + { + var fieldName = PropertyRouteParser.Parse(PropertyRouteBuilder.ToPropertyRoute(propertyDescriptionRoute)); + var columnBase = columns[fieldName]; + var column = columnBase as Column; + + if (columnBase == null) + { + column = ItemsSourceHelper.CreateColumnFromPropertyDescription(defaultCellEditors, propertyDescriptionRoute, autoCreateForeignKeyConfigurations); + + if (column != null) + { + columns.Add(column); + } + } + else if (column != null) + { + ItemsSourceHelper.UpdateColumnFromPropertyDescription(column, defaultCellEditors, autoCreateForeignKeyConfigurations, propertyDescriptionRoute); + } + } + } + } + } - using( columnManager.DeferUpdate() ) - { - using( columns.DeferNotifications() ) + internal static void UpdateColumnsFromPropertyDescriptions( + ColumnHierarchyManager columnManager, + IDictionary defaultCellEditors, + PropertyDescriptionRouteDictionary propertyDescriptions, + bool autoCreateForeignKeyConfigurations) { - foreach( var propertyDescriptionRoute in propertyDescriptions.Values ) - { - var fieldName = PropertyRouteParser.Parse( PropertyRouteBuilder.ToPropertyRoute( propertyDescriptionRoute ) ); - var columnBase = columns[ fieldName ]; - var column = columnBase as Column; + Debug.Assert(columnManager != null); - if( columnBase == null ) - { - column = ItemsSourceHelper.CreateColumnFromPropertyDescription( defaultCellEditors, propertyDescriptionRoute, autoCreateForeignKeyConfigurations ); + var columns = columnManager.Columns; - if( column != null ) - { - columns.Add( column ); - } - } - else if( column != null ) + using (columnManager.DeferUpdate()) { - ItemsSourceHelper.UpdateColumnFromPropertyDescription( column, defaultCellEditors, autoCreateForeignKeyConfigurations, propertyDescriptionRoute ); + using (columns.DeferNotifications()) + { + var columnsToRemove = new HashSet((from columnBase in columns + let column = columnBase as Column + where (column != null) && column.IsAutoCreated + select column)); + + foreach (var propertyDescriptionRoute in propertyDescriptions.Values) + { + var fieldName = PropertyRouteParser.Parse(PropertyRouteBuilder.ToPropertyRoute(propertyDescriptionRoute)); + var columnBase = columns[fieldName]; + var column = columnBase as Column; + + if (columnBase == null) + { + column = ItemsSourceHelper.CreateColumnFromPropertyDescription(defaultCellEditors, propertyDescriptionRoute, autoCreateForeignKeyConfigurations); + + if (column != null) + { + columns.Add(column); + } + } + else if (column != null) + { + columnsToRemove.Remove(column); + + ItemsSourceHelper.UpdateColumnFromPropertyDescription(column, defaultCellEditors, autoCreateForeignKeyConfigurations, propertyDescriptionRoute); + } + } + + foreach (var column in columnsToRemove) + { + columns.Remove(column); + } + } } - } } - } - } - - internal static void UpdateColumnsFromPropertyDescriptions( - ColumnHierarchyManager columnManager, - IDictionary defaultCellEditors, - PropertyDescriptionRouteDictionary propertyDescriptions, - bool autoCreateForeignKeyConfigurations ) - { - Debug.Assert( columnManager != null ); - - var columns = columnManager.Columns; - using( columnManager.DeferUpdate() ) - { - using( columns.DeferNotifications() ) + private static Column CreateColumnFromPropertyDescription(IDictionary defaultCellEditors, PropertyDescriptionRoute propertyDescriptionRoute, bool autoCreateForeignKeyConfigurations) { - var columnsToRemove = new HashSet( ( from columnBase in columns - let column = columnBase as Column - where ( column != null ) && column.IsAutoCreated - select column ) ); + if (propertyDescriptionRoute == null) + return null; - foreach( var propertyDescriptionRoute in propertyDescriptions.Values ) - { - var fieldName = PropertyRouteParser.Parse( PropertyRouteBuilder.ToPropertyRoute( propertyDescriptionRoute ) ); - var columnBase = columns[ fieldName ]; - var column = columnBase as Column; + var propertyDescription = propertyDescriptionRoute.Current; + var dataType = propertyDescription.DataType; - if( columnBase == null ) - { - column = ItemsSourceHelper.CreateColumnFromPropertyDescription( defaultCellEditors, propertyDescriptionRoute, autoCreateForeignKeyConfigurations ); + if (!propertyDescription.IsBrowsable || !propertyDescription.IsDisplayable) + return null; - if( column != null ) - { - columns.Add( column ); - } - } - else if( column != null ) + for (var current = propertyDescriptionRoute; current != null; current = current.Parent) { - columnsToRemove.Remove( column ); - - ItemsSourceHelper.UpdateColumnFromPropertyDescription( column, defaultCellEditors, autoCreateForeignKeyConfigurations, propertyDescriptionRoute ); + var description = current.Current; + if (description.IsSubRelationship) + return null; } - } - - foreach( var column in columnsToRemove ) - { - columns.Remove( column ); - } - } - } - } - private static Column CreateColumnFromPropertyDescription( IDictionary defaultCellEditors, PropertyDescriptionRoute propertyDescriptionRoute, bool autoCreateForeignKeyConfigurations ) - { - if( propertyDescriptionRoute == null ) - return null; + var name = PropertyRouteParser.Parse(PropertyRouteBuilder.ToPropertyRoute(propertyDescriptionRoute)); + if (string.IsNullOrEmpty(name)) + return null; - var propertyDescription = propertyDescriptionRoute.Current; - var dataType = propertyDescription.DataType; + var column = new Column(); + column.IsAutoCreated = true; + column.FieldName = name; + column.Title = propertyDescription.DisplayName; + column.OverrideReadOnlyForInsertion = propertyDescription.OverrideReadOnlyForInsertion; + column.SetDisplayMemberBinding(ItemsSourceHelper.CreateDefaultBinding(propertyDescriptionRoute)); + column.IsBindingAutoCreated = true; + column.IsBoundToDataGridUnboundItemProperty = propertyDescription.IsDataGridUnboundItemProperty; - if( !propertyDescription.IsBrowsable || !propertyDescription.IsDisplayable ) - return null; + if (propertyDescription.IsReadOnly) + { + column.ReadOnly = true; + } - for( var current = propertyDescriptionRoute; current != null; current = current.Parent ) - { - var description = current.Current; - if( description.IsSubRelationship ) - return null; - } + var cellEditor = default(CellEditor); - var name = PropertyRouteParser.Parse( PropertyRouteBuilder.ToPropertyRoute( propertyDescriptionRoute ) ); - if( string.IsNullOrEmpty( name ) ) - return null; + if ((defaultCellEditors != null) && !defaultCellEditors.TryGetValue(dataType, out cellEditor)) + { + cellEditor = default(CellEditor); + } - var column = new Column(); - column.IsAutoCreated = true; - column.FieldName = name; - column.Title = propertyDescription.DisplayName; - column.OverrideReadOnlyForInsertion = propertyDescription.OverrideReadOnlyForInsertion; - column.SetDisplayMemberBinding( ItemsSourceHelper.CreateDefaultBinding( propertyDescriptionRoute ) ); - column.IsBindingAutoCreated = true; - column.IsBoundToDataGridUnboundItemProperty = propertyDescription.IsDataGridUnboundItemProperty; + var foreignKeyDescription = propertyDescription.ForeignKeyDescription; - if( propertyDescription.IsReadOnly ) - { - column.ReadOnly = true; - } + if ((foreignKeyDescription != null) && (foreignKeyDescription.ItemsSource != null) && (autoCreateForeignKeyConfigurations)) + { + // We will only use the default foreign key CellEditor if: + // - a ForeignKey ItemsSource was detected + // - the grid allows the auto-creation of the ForeignKeyConfigurations + // else, use the default CellEditor + if (cellEditor == null) + { + cellEditor = DefaultCellEditorSelector.ForeignKeyCellEditor; + } + + // Update the ForeignKeyConfiguration from the ForeignKeyDescription found on the FieldDescriptor + ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription(column, foreignKeyDescription, autoCreateForeignKeyConfigurations); + } - var cellEditor = default( CellEditor ); + if (cellEditor == null) + { + cellEditor = DefaultCellEditorSelector.SelectCellEditor(dataType); + } - if( ( defaultCellEditors != null ) && !defaultCellEditors.TryGetValue( dataType, out cellEditor ) ) - { - cellEditor = default( CellEditor ); - } + column.CellEditor = cellEditor; + column.DefaultCellRecyclingGroupDataType = dataType; - var foreignKeyDescription = propertyDescription.ForeignKeyDescription; + return column; + } - if( ( foreignKeyDescription != null ) && ( foreignKeyDescription.ItemsSource != null ) && ( autoCreateForeignKeyConfigurations ) ) - { - // We will only use the default foreign key CellEditor if: - // - a ForeignKey ItemsSource was detected - // - the grid allows the auto-creation of the ForeignKeyConfigurations - // else, use the default CellEditor - if( cellEditor == null ) + internal static void UpdateColumnFromPropertyDescription( + ColumnBase column, + IDictionary defaultCellEditors, + bool autoCreateForeignKeyConfigurations, + PropertyDescriptionRoute propertyDescription) { - cellEditor = DefaultCellEditorSelector.ForeignKeyCellEditor; - } + if ((column == null) || (propertyDescription == null)) + return; - // Update the ForeignKeyConfiguration from the ForeignKeyDescription found on the FieldDescriptor - ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription( column, foreignKeyDescription, autoCreateForeignKeyConfigurations ); - } + var targetColumn = column as Column; + var targetPropertyDescription = propertyDescription.Current; - if( cellEditor == null ) - { - cellEditor = DefaultCellEditorSelector.SelectCellEditor( dataType ); - } + if (targetPropertyDescription.IsReadOnly) + { + if (column.ReadLocalValue(Column.ReadOnlyProperty) == DependencyProperty.UnsetValue) + { + column.ReadOnly = targetPropertyDescription.IsReadOnly; + } + } - column.CellEditor = cellEditor; - column.DefaultCellRecyclingGroupDataType = dataType; + if (targetPropertyDescription.OverrideReadOnlyForInsertion) + { + if (column.ReadLocalValue(ColumnBase.OverrideReadOnlyForInsertionProperty) == DependencyProperty.UnsetValue) + { + column.OverrideReadOnlyForInsertion = targetPropertyDescription.OverrideReadOnlyForInsertion; + } + } - return column; - } + if (column.ReadLocalValue(ColumnBase.TitleProperty) == DependencyProperty.UnsetValue) + { + column.Title = targetPropertyDescription.DisplayName; + } - internal static void UpdateColumnFromPropertyDescription( - ColumnBase column, - IDictionary defaultCellEditors, - bool autoCreateForeignKeyConfigurations, - PropertyDescriptionRoute propertyDescription ) - { - if( ( column == null ) || ( propertyDescription == null ) ) - return; + if (column.ReadLocalValue(ColumnBase.CellEditorProperty) == DependencyProperty.UnsetValue) + { + var cellEditor = default(CellEditor); + + if (defaultCellEditors != null) + { + defaultCellEditors.TryGetValue(targetPropertyDescription.DataType, out cellEditor); + } + + if ((cellEditor == null) && (targetColumn != null)) + { + var descriptionItemsSource = default(object); + var configurationItemsSource = default(object); + var configuration = targetColumn.ForeignKeyConfiguration; + + if (targetPropertyDescription.ForeignKeyDescription != null) + { + descriptionItemsSource = targetPropertyDescription.ForeignKeyDescription.ItemsSource; + } + + if (configuration != null) + { + configurationItemsSource = configuration.ItemsSource; + + if (configurationItemsSource == null) + { + configurationItemsSource = targetColumn.ReadLocalValue(Column.ForeignKeyConfigurationProperty); + } + } + + // A foreign key ItemsSource is set and we can auto-create configuration, OR, + // if the foreign key ItemsSource was found in the ForeignKeyConfiguration, use the Default ForeignKey CellEditor. + if (((descriptionItemsSource != null) && (autoCreateForeignKeyConfigurations)) || (configurationItemsSource != null)) + { + cellEditor = DefaultCellEditorSelector.ForeignKeyCellEditor; + } + } + + if (cellEditor == null) + { + cellEditor = DefaultCellEditorSelector.SelectCellEditor(targetPropertyDescription.DataType); + } + + column.CellEditor = cellEditor; + } - var targetColumn = column as Column; - var targetPropertyDescription = propertyDescription.Current; + if (targetColumn != null) + { + if ((targetPropertyDescription.ForeignKeyDescription != null) && (targetPropertyDescription.ForeignKeyDescription.ItemsSource != null) && (autoCreateForeignKeyConfigurations)) + { + // Update the ForeignKeyConfiguration from the ForeignKeyDescription found on the FieldDescriptor + ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription(targetColumn, targetPropertyDescription.ForeignKeyDescription, autoCreateForeignKeyConfigurations); + } + + if (targetColumn.GetDisplayMemberBinding() == null) + { + targetColumn.SetDisplayMemberBinding(ItemsSourceHelper.CreateDefaultBinding(propertyDescription)); + targetColumn.IsBindingAutoCreated = true; + targetColumn.IsBoundToDataGridUnboundItemProperty = targetPropertyDescription.IsDataGridUnboundItemProperty; + } + } - if( targetPropertyDescription.IsReadOnly ) - { - if( column.ReadLocalValue( Column.ReadOnlyProperty ) == DependencyProperty.UnsetValue ) - { - column.ReadOnly = targetPropertyDescription.IsReadOnly; + column.DefaultCellRecyclingGroupDataType = targetPropertyDescription.DataType; } - } - if( targetPropertyDescription.OverrideReadOnlyForInsertion ) - { - if( column.ReadLocalValue( ColumnBase.OverrideReadOnlyForInsertionProperty ) == DependencyProperty.UnsetValue ) + internal static DataGridItemPropertyBase GetItemPropertyFromProperty(DataGridItemPropertyCollection itemProperties, string propertyPath) { - column.OverrideReadOnlyForInsertion = targetPropertyDescription.OverrideReadOnlyForInsertion; + if (itemProperties == null) + return null; + + return ItemsSourceHelper.GetItemPropertyFromProperty(itemProperties, PropertyRouteParser.Parse(propertyPath)); } - } - if( column.ReadLocalValue( ColumnBase.TitleProperty ) == DependencyProperty.UnsetValue ) - { - column.Title = targetPropertyDescription.DisplayName; - } + internal static DataGridItemPropertyBase GetItemPropertyFromProperty(DataGridItemPropertyCollection itemProperties, PropertyRoute propertyRoute) + { + if ((itemProperties == null) || (propertyRoute == null)) + return null; - if( column.ReadLocalValue( ColumnBase.CellEditorProperty ) == DependencyProperty.UnsetValue ) - { - var cellEditor = default( CellEditor ); + if (propertyRoute.Parent != null) + { + var parentItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty(itemProperties, propertyRoute.Parent); + if (parentItemProperty == null) + return null; - if( defaultCellEditors != null ) - { - defaultCellEditors.TryGetValue( targetPropertyDescription.DataType, out cellEditor ); + itemProperties = parentItemProperty.ItemPropertiesInternal; + if (itemProperties == null) + return null; + } + + return itemProperties[propertyRoute.Current.Name]; } - if( ( cellEditor == null ) && ( targetColumn != null ) ) + internal static object GetValueFromItemProperty(DataGridItemPropertyBase itemProperty, object item) { - var descriptionItemsSource = default( object ); - var configurationItemsSource = default( object ); - var configuration = targetColumn.ForeignKeyConfiguration; + return ItemsSourceHelper.GetValueFromItemProperty(itemProperty, item, null); + } - if( targetPropertyDescription.ForeignKeyDescription != null ) - { - descriptionItemsSource = targetPropertyDescription.ForeignKeyDescription.ItemsSource; - } + internal static object GetValueFromItemProperty(DataGridItemPropertyBase itemProperty, object item, object defaultValue) + { + if (itemProperty == null) + throw new ArgumentNullException("itemProperty"); - if( configuration != null ) - { - configurationItemsSource = configuration.ItemsSource; + // Make sure the DataGridItemProperty is still in use. + var collection = itemProperty.ContainingCollection; + if (collection == null) + return defaultValue; - if( configurationItemsSource == null ) + var parentItemProperty = collection.Owner; + if (parentItemProperty != null) { - configurationItemsSource = targetColumn.ReadLocalValue( Column.ForeignKeyConfigurationProperty ); + item = ItemsSourceHelper.GetValueFromItemProperty(parentItemProperty, item); } - } - // A foreign key ItemsSource is set and we can auto-create configuration, OR, - // if the foreign key ItemsSource was found in the ForeignKeyConfiguration, use the Default ForeignKey CellEditor. - if( ( ( descriptionItemsSource != null ) && ( autoCreateForeignKeyConfigurations ) ) || ( configurationItemsSource != null ) ) - { - cellEditor = DefaultCellEditorSelector.ForeignKeyCellEditor; - } - } + if (item == null) + return defaultValue; - if( cellEditor == null ) - { - cellEditor = DefaultCellEditorSelector.SelectCellEditor( targetPropertyDescription.DataType ); + return itemProperty.GetValue(item); } - column.CellEditor = cellEditor; - } - - if( targetColumn != null ) - { - if( ( targetPropertyDescription.ForeignKeyDescription != null ) && ( targetPropertyDescription.ForeignKeyDescription.ItemsSource != null ) && ( autoCreateForeignKeyConfigurations ) ) + internal static void SetValueForItemProperty(DataGridItemPropertyBase itemProperty, object item, object value) { - // Update the ForeignKeyConfiguration from the ForeignKeyDescription found on the FieldDescriptor - ForeignKeyConfiguration.SynchronizeForeignKeyConfigurationFromForeignKeyDescription( targetColumn, targetPropertyDescription.ForeignKeyDescription, autoCreateForeignKeyConfigurations ); - } + if (itemProperty == null) + throw new ArgumentNullException("itemProperty"); - if( targetColumn.GetDisplayMemberBinding() == null ) - { - targetColumn.SetDisplayMemberBinding( ItemsSourceHelper.CreateDefaultBinding( propertyDescription ) ); - targetColumn.IsBindingAutoCreated = true; - targetColumn.IsBoundToDataGridUnboundItemProperty = targetPropertyDescription.IsDataGridUnboundItemProperty; - } - } + // Make sure the DataGridItemProperty is still in use. + var collection = itemProperty.ContainingCollection; + if (collection == null) + return; - column.DefaultCellRecyclingGroupDataType = targetPropertyDescription.DataType; - } + var parentItemProperty = collection.Owner; + if (parentItemProperty != null) + { + item = ItemsSourceHelper.GetValueFromItemProperty(parentItemProperty, item); + } - internal static DataGridItemPropertyBase GetItemPropertyFromProperty( DataGridItemPropertyCollection itemProperties, string propertyPath ) - { - if( itemProperties == null ) - return null; + if (item == null) + return; - return ItemsSourceHelper.GetItemPropertyFromProperty( itemProperties, PropertyRouteParser.Parse( propertyPath ) ); - } + itemProperty.SetValue(item, value); + } - internal static DataGridItemPropertyBase GetItemPropertyFromProperty( DataGridItemPropertyCollection itemProperties, PropertyRoute propertyRoute ) - { - if( ( itemProperties == null ) || ( propertyRoute == null ) ) - return null; + internal static void AutoDetectSynonyms(DataGridCollectionViewBase collectionView) + { + if (collectionView == null) + return; - if( propertyRoute.Parent != null ) - { - var parentItemProperty = ItemsSourceHelper.GetItemPropertyFromProperty( itemProperties, propertyRoute.Parent ); - if( parentItemProperty == null ) - return null; + // The root CollectionView does not need to have its ItemProperties binded. + var masterCollectionView = collectionView.RootDataGridCollectionViewBase; + if ((masterCollectionView == null) || (masterCollectionView == collectionView)) + return; - itemProperties = parentItemProperty.ItemPropertiesInternal; - if( itemProperties == null ) - return null; - } + ItemsSourceHelper.AutoDetectSynonyms(masterCollectionView.ItemProperties, collectionView.ItemProperties); + } - return itemProperties[ propertyRoute.Current.Name ]; - } + internal static void AutoDetectSynonyms(DataGridCollectionViewBase collectionView, DataGridItemPropertyRoute detailItemPropertyRoute) + { + if ((collectionView == null) || (detailItemPropertyRoute == null)) + return; - internal static object GetValueFromItemProperty( DataGridItemPropertyBase itemProperty, object item ) - { - return ItemsSourceHelper.GetValueFromItemProperty( itemProperty, item, null ); - } + // The root CollectionView does not need to have its ItemProperties binded. + var masterCollectionView = collectionView.RootDataGridCollectionViewBase; + if ((masterCollectionView == null) || (masterCollectionView == collectionView)) + return; - internal static object GetValueFromItemProperty( DataGridItemPropertyBase itemProperty, object item, object defaultValue ) - { - if( itemProperty == null ) - throw new ArgumentNullException( "itemProperty" ); + var masterItemProperty = ItemsSourceHelper.AutoDetectSynonyms(masterCollectionView.ItemProperties, detailItemPropertyRoute); + if (masterItemProperty == null) + return; - // Make sure the DataGridItemProperty is still in use. - var collection = itemProperty.ContainingCollection; - if( collection == null ) - return defaultValue; + // Do the auto detection on child properties. + ItemsSourceHelper.AutoDetectSynonyms(masterItemProperty.ItemPropertiesInternal, detailItemPropertyRoute.Current.ItemPropertiesInternal); + } - var parentItemProperty = collection.Owner; - if( parentItemProperty != null ) - { - item = ItemsSourceHelper.GetValueFromItemProperty( parentItemProperty, item ); - } + private static void AutoDetectSynonyms(DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyCollection detailItemProperties) + { + if ((masterItemProperties == null) || (detailItemProperties == null)) + return; - if( item == null ) - return defaultValue; + foreach (var detailItemProperty in detailItemProperties) + { + ItemsSourceHelper.AutoDetectSynonyms(masterItemProperties, detailItemProperty, true); + } + } - return itemProperty.GetValue( item ); - } + private static DataGridItemPropertyBase AutoDetectSynonyms(DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyRoute detailItemPropertyRoute) + { + if ((masterItemProperties == null) || (detailItemPropertyRoute == null)) + return null; - internal static void SetValueForItemProperty( DataGridItemPropertyBase itemProperty, object item, object value ) - { - if( itemProperty == null ) - throw new ArgumentNullException( "itemProperty" ); + if (detailItemPropertyRoute.Parent == null) + return ItemsSourceHelper.AutoDetectSynonyms(masterItemProperties, detailItemPropertyRoute.Current, false); - // Make sure the DataGridItemProperty is still in use. - var collection = itemProperty.ContainingCollection; - if( collection == null ) - return; + var masterParentItemProperty = ItemsSourceHelper.AutoDetectSynonyms(masterItemProperties, detailItemPropertyRoute.Parent); + if (masterParentItemProperty == null) + return null; - var parentItemProperty = collection.Owner; - if( parentItemProperty != null ) - { - item = ItemsSourceHelper.GetValueFromItemProperty( parentItemProperty, item ); - } + return ItemsSourceHelper.AutoDetectSynonyms(masterParentItemProperty.ItemPropertiesInternal, detailItemPropertyRoute.Current, false); + } - if( item == null ) - return; + private static DataGridItemPropertyBase AutoDetectSynonyms(DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyBase detailItemProperty, bool autoDetectSubProperties) + { + if ((masterItemProperties == null) || (detailItemProperty == null)) + return null; - itemProperty.SetValue( item, value ); - } + var masterItemProperty = default(DataGridItemPropertyBase); - internal static void AutoDetectSynonyms( DataGridCollectionViewBase collectionView ) - { - if( collectionView == null ) - return; + if (string.IsNullOrEmpty(detailItemProperty.Synonym)) + { + masterItemProperty = masterItemProperties[detailItemProperty.Name]; + + if ((masterItemProperty != null) && (masterItemProperty.DataType == detailItemProperty.DataType)) + { + detailItemProperty.SetSynonym(masterItemProperty.Name); + } + else + { + masterItemProperty = null; + } + } + else if ((detailItemProperty.ItemPropertiesInternal != null) && (detailItemProperty.Synonym == detailItemProperty.Name)) + { + masterItemProperty = masterItemProperties[detailItemProperty.Name]; + } - // The root CollectionView does not need to have its ItemProperties binded. - var masterCollectionView = collectionView.RootDataGridCollectionViewBase; - if( ( masterCollectionView == null ) || ( masterCollectionView == collectionView ) ) - return; + if (autoDetectSubProperties && (masterItemProperty != null) && (masterItemProperty.ItemPropertiesInternal != null) && (detailItemProperty.ItemPropertiesInternal != null)) + { + ItemsSourceHelper.AutoDetectSynonyms(masterItemProperty.ItemPropertiesInternal, detailItemProperty.ItemPropertiesInternal); + } - ItemsSourceHelper.AutoDetectSynonyms( masterCollectionView.ItemProperties, collectionView.ItemProperties ); - } + return masterItemProperty; + } - internal static void AutoDetectSynonyms( DataGridCollectionViewBase collectionView, DataGridItemPropertyRoute detailItemPropertyRoute ) - { - if( ( collectionView == null ) || ( detailItemPropertyRoute == null ) ) - return; + internal static ICustomTypeDescriptor GetCustomTypeDescriptorFromItem(object item, Type itemType) + { + var descriptionProvider = default(TypeDescriptionProvider); + if (itemType != null) + { + descriptionProvider = TypeDescriptor.GetProvider(itemType); + } - // The root CollectionView does not need to have its ItemProperties binded. - var masterCollectionView = collectionView.RootDataGridCollectionViewBase; - if( ( masterCollectionView == null ) || ( masterCollectionView == collectionView ) ) - return; + if (!(descriptionProvider is DataItemTypeDescriptionProvider)) + { + descriptionProvider = new DataItemTypeDescriptionProvider(descriptionProvider); + } - var masterItemProperty = ItemsSourceHelper.AutoDetectSynonyms( masterCollectionView.ItemProperties, detailItemPropertyRoute ); - if( masterItemProperty == null ) - return; + return descriptionProvider.GetTypeDescriptor(itemType, item); + } - // Do the auto detection on child properties. - ItemsSourceHelper.AutoDetectSynonyms( masterItemProperty.ItemPropertiesInternal, detailItemPropertyRoute.Current.ItemPropertiesInternal ); - } + private static ICustomTypeDescriptor GetCustomTypeDescriptor(IEnumerable itemsSource, Type itemType) + { + if ((itemsSource == null) && (itemType == null)) + return null; - private static void AutoDetectSynonyms( DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyCollection detailItemProperties ) - { - if( ( masterItemProperties == null ) || ( detailItemProperties == null ) ) - return; + var firstItem = ItemsSourceHelper.GetFirstItemByEnumerable(itemsSource); - foreach( var detailItemProperty in detailItemProperties ) - { - ItemsSourceHelper.AutoDetectSynonyms( masterItemProperties, detailItemProperty, true ); - } - } + return ItemsSourceHelper.GetCustomTypeDescriptor(firstItem, itemType); + } - private static DataGridItemPropertyBase AutoDetectSynonyms( DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyRoute detailItemPropertyRoute ) - { - if( ( masterItemProperties == null ) || ( detailItemPropertyRoute == null ) ) - return null; + private static ICustomTypeDescriptor GetCustomTypeDescriptor(object item, Type itemType) + { + var descriptor = item as ICustomTypeDescriptor; + if (descriptor == null) + return ItemsSourceHelper.GetCustomTypeDescriptorFromItem(item, itemType); - if( detailItemPropertyRoute.Parent == null ) - return ItemsSourceHelper.AutoDetectSynonyms( masterItemProperties, detailItemPropertyRoute.Current, false ); + if (!(descriptor is DataItemTypeDescriptor)) + return DataItemTypeDescriptionProvider.GetTypeDescriptor(itemType, descriptor); - var masterParentItemProperty = ItemsSourceHelper.AutoDetectSynonyms( masterItemProperties, detailItemPropertyRoute.Parent ); - if( masterParentItemProperty == null ) - return null; + return descriptor; + } - return ItemsSourceHelper.AutoDetectSynonyms( masterParentItemProperty.ItemPropertiesInternal, detailItemPropertyRoute.Current, false ); - } + internal static void ResetPropertyDescriptions(PropertyDescriptionRouteDictionary collection, DataGridItemPropertyMap itemPropertyMap, DataGridControl dataGridControl, IEnumerable itemsSource) + { + if (collection == null) + throw new ArgumentNullException("collection"); - private static DataGridItemPropertyBase AutoDetectSynonyms( DataGridItemPropertyCollection masterItemProperties, DataGridItemPropertyBase detailItemProperty, bool autoDetectSubProperties ) - { - if( ( masterItemProperties == null ) || ( detailItemProperty == null ) ) - return null; + if (dataGridControl == null) + throw new ArgumentNullException("dataGridControl"); - var masterItemProperty = default( DataGridItemPropertyBase ); + collection.Clear(); - if( string.IsNullOrEmpty( detailItemProperty.Synonym ) ) - { - masterItemProperty = masterItemProperties[ detailItemProperty.Name ]; + var masterPropertyDescriptions = dataGridControl.ItemsSourcePropertyDescriptions; - if( ( masterItemProperty != null ) && ( masterItemProperty.DataType == detailItemProperty.DataType ) ) - { - detailItemProperty.SetSynonym( masterItemProperty.Name ); - } - else - { - masterItemProperty = null; + if ((collection != masterPropertyDescriptions) && dataGridControl.AreDetailsFlatten) + { + var collectionView = itemsSource as DataGridCollectionViewBase; + if (collectionView != null) + { + ItemsSourceHelper.SetPropertyDescriptions(collection, masterPropertyDescriptions, itemPropertyMap, collectionView); + } + } + else + { + ItemsSourceHelper.SetPropertyDescriptions(collection, null, itemsSource, null, true); + } } - } - else if( ( detailItemProperty.ItemPropertiesInternal != null ) && ( detailItemProperty.Synonym == detailItemProperty.Name ) ) - { - masterItemProperty = masterItemProperties[ detailItemProperty.Name ]; - } - if( autoDetectSubProperties && ( masterItemProperty != null ) && ( masterItemProperty.ItemPropertiesInternal != null ) && ( detailItemProperty.ItemPropertiesInternal != null ) ) - { - ItemsSourceHelper.AutoDetectSynonyms( masterItemProperty.ItemPropertiesInternal, detailItemProperty.ItemPropertiesInternal ); - } + internal static void SetPropertyDescriptions(PropertyDescriptionRouteDictionary collection, DataTable model, IEnumerable itemsSource, Type itemType, bool displayable) + { + if (collection == null) + throw new ArgumentNullException("collection"); - return masterItemProperty; - } + var descriptions = default(IEnumerable); + var supportsDBNull = ItemsSourceHelper.IsSupportingDBNull(itemsSource); - internal static ICustomTypeDescriptor GetCustomTypeDescriptorFromItem( object item, Type itemType ) - { - var descriptionProvider = default( TypeDescriptionProvider ); - if( itemType != null ) - { - descriptionProvider = TypeDescriptor.GetProvider( itemType ); - } - - if( !( descriptionProvider is DataItemTypeDescriptionProvider ) ) - { - descriptionProvider = new DataItemTypeDescriptionProvider( descriptionProvider ); - } - - return descriptionProvider.GetTypeDescriptor( itemType, item ); - } - - private static ICustomTypeDescriptor GetCustomTypeDescriptor( IEnumerable itemsSource, Type itemType ) - { - if( ( itemsSource == null ) && ( itemType == null ) ) - return null; + if (model != null) + { + descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromDataTable(model, displayable); + } + else if (itemsSource is DataView) + { + descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromDataView((DataView)itemsSource, displayable); + } + else if (itemsSource is DataGridCollectionViewBase) + { + descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromDataGridCollectionView((DataGridCollectionViewBase)itemsSource); + } + else if (itemsSource is ITypedList) + { + descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors(((ITypedList)itemsSource).GetItemProperties(null), supportsDBNull, displayable); + } + else + { + if (itemType == null) + { + itemType = ItemsSourceHelper.GetItemTypeFromEnumeration(itemsSource); + } - var firstItem = ItemsSourceHelper.GetFirstItemByEnumerable( itemsSource ); + descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromItemType(itemsSource, itemType, supportsDBNull, displayable); + } - return ItemsSourceHelper.GetCustomTypeDescriptor( firstItem, itemType ); - } + if (descriptions != null) + { + foreach (var description in descriptions) + { + collection.Add(description, true); + } + } + } - private static ICustomTypeDescriptor GetCustomTypeDescriptor( object item, Type itemType ) - { - var descriptor = item as ICustomTypeDescriptor; - if( descriptor == null ) - return ItemsSourceHelper.GetCustomTypeDescriptorFromItem( item, itemType ); + private static void SetPropertyDescriptions(PropertyDescriptionRouteDictionary detailCollection, PropertyDescriptionRouteDictionary masterCollection, DataGridItemPropertyMap itemPropertyMap, DataGridCollectionViewBase collectionView) + { + if (collectionView == null) + return; - if( !( descriptor is DataItemTypeDescriptor ) ) - return DataItemTypeDescriptionProvider.GetTypeDescriptor( itemType, descriptor ); + foreach (var itemProperty in collectionView.ItemProperties) + { + var masterItemProperty = default(DataGridItemPropertyBase); + if (!itemPropertyMap.TryGetMasterItemProperty(itemProperty, out masterItemProperty)) + { + Debug.WriteLine(string.Format("No mapping was found for the item property.")); + continue; + } + + var masterPropertyRoute = PropertyRouteBuilder.ToPropertyRoute(DataGridItemPropertyRoute.Create(masterItemProperty)); + if (masterPropertyRoute == null) + { + masterPropertyRoute = PropertyRouteBuilder.ToPropertyRoute(new PropertyRouteSegment(PropertyRouteSegmentType.Property, masterItemProperty.Name)); + } + + var masterPropertyDescription = masterCollection[masterPropertyRoute]; + if (masterPropertyDescription == null) + { + Debug.WriteLine(string.Format("An item property is mapped to a non-existent master field.")); + continue; + } + + var detailPropertyDescription = ItemsSourceHelper.CreatePropertyDescriptionFromDataGridItemProperty(itemProperty); + if (detailPropertyDescription.Current.DataType != masterPropertyDescription.Current.DataType) + { + Debug.WriteLine(string.Format("The data type of an item property doesn't match the data type of its master field.")); + continue; + } + + if (detailCollection.Contains(masterPropertyRoute)) + { + Debug.WriteLine(string.Format("Another detail field is already linked to the master field.")); + continue; + } + + detailCollection.Add(masterPropertyRoute, detailPropertyDescription, false); + } + } - return descriptor; - } + internal static void SetPropertyDescriptionsFromItemProperty(PropertyDescriptionRouteDictionary propertyDescriptions, DataTable model, IEnumerable itemsSource, Type itemType, DataGridItemPropertyRoute itemPropertyRoute) + { + if ((propertyDescriptions == null) || (itemPropertyRoute == null)) + return; - internal static void ResetPropertyDescriptions( PropertyDescriptionRouteDictionary collection, DataGridItemPropertyMap itemPropertyMap, DataGridControl dataGridControl, IEnumerable itemsSource ) - { - if( collection == null ) - throw new ArgumentNullException( "collection" ); + var key = PropertyRouteBuilder.ToPropertyRoute(itemPropertyRoute); + ItemsSourceHelper.SetPropertyDescriptions(propertyDescriptions, model, itemsSource, itemType, key); - if( dataGridControl == null ) - throw new ArgumentNullException( "dataGridControl" ); + var propertyDescription = default(PropertyDescriptionRoute); + if (!propertyDescriptions.TryGetValue(key, out propertyDescription)) + return; - collection.Clear(); + var itemProperty = itemPropertyRoute.Current; + if (itemProperty.ItemPropertiesInternal == null) + return; - var masterPropertyDescriptions = dataGridControl.ItemsSourcePropertyDescriptions; + foreach (var childItemProperty in itemProperty.ItemPropertiesInternal) + { + ItemsSourceHelper.SetPropertyDescriptionsFromItemProperty( + propertyDescriptions, + null, + null, + itemProperty.DataType, + DataGridItemPropertyRoute.Combine(childItemProperty, itemPropertyRoute)); + } + } - if( ( collection != masterPropertyDescriptions ) && dataGridControl.AreDetailsFlatten ) - { - var collectionView = itemsSource as DataGridCollectionViewBase; - if( collectionView != null ) + internal static void InitializePropertyDescriptions(PropertyDescriptionRouteDictionary collection, DataGridItemPropertyRoute itemPropertyRoute, Type itemType, bool defaultPropertyDescriptionsCreated) { - ItemsSourceHelper.SetPropertyDescriptions( collection, masterPropertyDescriptions, itemPropertyMap, collectionView ); - } - } - else - { - ItemsSourceHelper.SetPropertyDescriptions( collection, null, itemsSource, null, true ); - } - } + if ((collection == null) || (itemPropertyRoute == null)) + return; - internal static void SetPropertyDescriptions( PropertyDescriptionRouteDictionary collection, DataTable model, IEnumerable itemsSource, Type itemType, bool displayable ) - { - if( collection == null ) - throw new ArgumentNullException( "collection" ); - - var descriptions = default( IEnumerable ); - var supportsDBNull = ItemsSourceHelper.IsSupportingDBNull( itemsSource ); - - if( model != null ) - { - descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromDataTable( model, displayable ); - } - else if( itemsSource is DataView ) - { - descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromDataView( ( DataView )itemsSource, displayable ); - } - else if( itemsSource is DataGridCollectionViewBase ) - { - descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromDataGridCollectionView( ( DataGridCollectionViewBase )itemsSource ); - } - else if( itemsSource is ITypedList ) - { - descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors( ( ( ITypedList )itemsSource ).GetItemProperties( null ), supportsDBNull, displayable ); - } - else - { - if( itemType == null ) - { - itemType = ItemsSourceHelper.GetItemTypeFromEnumeration( itemsSource ); - } - - descriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromItemType( itemsSource, itemType, supportsDBNull, displayable ); - } - - if( descriptions != null ) - { - foreach( var description in descriptions ) - { - collection.Add( description, true ); - } - } - } + var propertyDescription = ItemsSourceHelper.GetPropertyDescriptionFromItemProperty(collection, itemPropertyRoute); + var itemProperty = itemPropertyRoute.Current; - private static void SetPropertyDescriptions( PropertyDescriptionRouteDictionary detailCollection, PropertyDescriptionRouteDictionary masterCollection, DataGridItemPropertyMap itemPropertyMap, DataGridCollectionViewBase collectionView ) - { - if( collectionView == null ) - return; + itemProperty.SetUnspecifiedPropertiesValues(propertyDescription, itemType, defaultPropertyDescriptionsCreated); - foreach( var itemProperty in collectionView.ItemProperties ) - { - var masterItemProperty = default( DataGridItemPropertyBase ); - if( !itemPropertyMap.TryGetMasterItemProperty( itemProperty, out masterItemProperty ) ) - { - Debug.WriteLine( string.Format( "No mapping was found for the item property." ) ); - continue; + if (itemProperty.ItemPropertiesInternal != null) + { + foreach (var childItemProperty in itemProperty.ItemPropertiesInternal) + { + ItemsSourceHelper.InitializePropertyDescriptions(collection, DataGridItemPropertyRoute.Combine(childItemProperty, itemPropertyRoute), itemProperty.DataType, defaultPropertyDescriptionsCreated); + } + } } - var masterPropertyRoute = PropertyRouteBuilder.ToPropertyRoute( DataGridItemPropertyRoute.Create( masterItemProperty ) ); - if( masterPropertyRoute == null ) + internal static Type GetItemTypeFromEnumeration(IEnumerable source) { - masterPropertyRoute = PropertyRouteBuilder.ToPropertyRoute( new PropertyRouteSegment( PropertyRouteSegmentType.Property, masterItemProperty.Name ) ); + if (source == null) + return null; + + var enumerationType = source.GetType(); + var itemType = ItemsSourceHelper.GetItemTypeFromEnumerationType(enumerationType); + + if (itemType != null) + return itemType; + + var item = ItemsSourceHelper.GetFirstItemByEnumerable(source); + if (item != null) + return item.GetType(); + + return typeof(object); } - var masterPropertyDescription = masterCollection[ masterPropertyRoute ]; - if( masterPropertyDescription == null ) + internal static Type GetItemTypeFromEnumerationType(Type enumerationType) { - Debug.WriteLine( string.Format( "An item property is mapped to a non-existent master field." ) ); - continue; + if (enumerationType == null) + return null; + + if (typeof(Array).IsAssignableFrom(enumerationType)) + return enumerationType.GetElementType(); + + var itemType = ItemsSourceHelper.GetTypedListIndexerType(enumerationType); + if (itemType != null) + return itemType; + + return ItemsSourceHelper.GetTypedEnumerationItemType(enumerationType); } - var detailPropertyDescription = ItemsSourceHelper.CreatePropertyDescriptionFromDataGridItemProperty( itemProperty ); - if( detailPropertyDescription.Current.DataType != masterPropertyDescription.Current.DataType ) + internal static IEditableObject GetEditableObject(object item) { - Debug.WriteLine( string.Format( "The data type of an item property doesn't match the data type of its master field." ) ); - continue; + var dataRow = item as System.Data.DataRow; + if (dataRow != null) + return new DataRowEditableWrapper(dataRow); + + return item as IEditableObject; } - if( detailCollection.Contains( masterPropertyRoute ) ) + internal static ISupportInitialize GetSupportInitializeObject(object item) { - Debug.WriteLine( string.Format( "Another detail field is already linked to the master field." ) ); - continue; + return item as ISupportInitialize; } - detailCollection.Add( masterPropertyRoute, detailPropertyDescription, false ); - } - } + internal static bool IsASubRelationship(Type dataType) + { + if ((dataType == null) || (dataType.IsValueType) || (typeof(string).IsAssignableFrom(dataType))) + return false; - internal static void SetPropertyDescriptionsFromItemProperty( PropertyDescriptionRouteDictionary propertyDescriptions, DataTable model, IEnumerable itemsSource, Type itemType, DataGridItemPropertyRoute itemPropertyRoute ) - { - if( ( propertyDescriptions == null ) || ( itemPropertyRoute == null ) ) - return; - - var key = PropertyRouteBuilder.ToPropertyRoute( itemPropertyRoute ); - ItemsSourceHelper.SetPropertyDescriptions( propertyDescriptions, model, itemsSource, itemType, key ); - - var propertyDescription = default( PropertyDescriptionRoute ); - if( !propertyDescriptions.TryGetValue( key, out propertyDescription ) ) - return; - - var itemProperty = itemPropertyRoute.Current; - if( itemProperty.ItemPropertiesInternal == null ) - return; - - foreach( var childItemProperty in itemProperty.ItemPropertiesInternal ) - { - ItemsSourceHelper.SetPropertyDescriptionsFromItemProperty( - propertyDescriptions, - null, - null, - itemProperty.DataType, - DataGridItemPropertyRoute.Combine( childItemProperty, itemPropertyRoute ) ); - } - } + if (typeof(IEnumerable).IsAssignableFrom(dataType)) + return !typeof(byte[]).IsAssignableFrom(dataType); - internal static void InitializePropertyDescriptions( PropertyDescriptionRouteDictionary collection, DataGridItemPropertyRoute itemPropertyRoute, Type itemType, bool defaultPropertyDescriptionsCreated ) - { - if( ( collection == null ) || ( itemPropertyRoute == null ) ) - return; + return typeof(IListSource).IsAssignableFrom(dataType); + } - var propertyDescription = ItemsSourceHelper.GetPropertyDescriptionFromItemProperty( collection, itemPropertyRoute ); - var itemProperty = itemPropertyRoute.Current; + internal static object TryGetDataRowFromDataItem(object dataItem) + { + var dataRowView = dataItem as DataRowView; + if (dataRowView != null) + return dataRowView.Row; - itemProperty.SetUnspecifiedPropertiesValues( propertyDescription, itemType, defaultPropertyDescriptionsCreated ); + return dataItem; + } - if( itemProperty.ItemPropertiesInternal != null ) - { - foreach( var childItemProperty in itemProperty.ItemPropertiesInternal ) + internal static DataView TryGetDataViewFromDataGridContext(DataGridContext context) { - ItemsSourceHelper.InitializePropertyDescriptions( collection, DataGridItemPropertyRoute.Combine( childItemProperty, itemPropertyRoute ), itemProperty.DataType, defaultPropertyDescriptionsCreated ); - } - } - } + if (context == null) + return null; - internal static Type GetItemTypeFromEnumeration( IEnumerable source ) - { - if( source == null ) - return null; + var dataView = context.ItemsSourceCollection as DataView; + if (dataView != null) + return dataView; - var enumerationType = source.GetType(); - var itemType = ItemsSourceHelper.GetItemTypeFromEnumerationType( enumerationType ); + var collectionViewBase = context.ItemsSourceCollection as DataGridCollectionViewBase; + if (collectionViewBase != null) + return collectionViewBase.SourceCollection as DataView; - if( itemType != null ) - return itemType; + return null; + } - var item = ItemsSourceHelper.GetFirstItemByEnumerable( source ); - if( item != null ) - return item.GetType(); + internal static Type GetColumnDataType(DataColumn column) + { + if (!column.AllowDBNull) + return column.DataType; - return typeof( object ); - } + if (column.DataType == typeof(Boolean)) + return typeof(Nullable); - internal static Type GetItemTypeFromEnumerationType( Type enumerationType ) - { - if( enumerationType == null ) - return null; + if (column.DataType == typeof(Byte)) + return typeof(Nullable); - if( typeof( Array ).IsAssignableFrom( enumerationType ) ) - return enumerationType.GetElementType(); + if (column.DataType == typeof(Char)) + return typeof(Nullable); - var itemType = ItemsSourceHelper.GetTypedListIndexerType( enumerationType ); - if( itemType != null ) - return itemType; + if (column.DataType == typeof(DateTime)) + return typeof(Nullable); - return ItemsSourceHelper.GetTypedEnumerationItemType( enumerationType ); - } + if (column.DataType == typeof(Decimal)) + return typeof(Nullable); - internal static IEditableObject GetEditableObject( object item ) - { - var dataRow = item as System.Data.DataRow; - if( dataRow != null ) - return new DataRowEditableWrapper( dataRow ); + if (column.DataType == typeof(Double)) + return typeof(Nullable); - return item as IEditableObject; - } + if (column.DataType == typeof(Int16)) + return typeof(Nullable); - internal static ISupportInitialize GetSupportInitializeObject( object item ) - { - return item as ISupportInitialize; - } + if (column.DataType == typeof(Int32)) + return typeof(Nullable); - internal static bool IsASubRelationship( Type dataType ) - { - if( ( dataType == null ) || ( dataType.IsValueType ) || ( typeof( string ).IsAssignableFrom( dataType ) ) ) - return false; + if (column.DataType == typeof(Int64)) + return typeof(Nullable); - if( typeof( IEnumerable ).IsAssignableFrom( dataType ) ) - return !typeof( byte[] ).IsAssignableFrom( dataType ); + if (column.DataType == typeof(SByte)) + return typeof(Nullable); - return typeof( IListSource ).IsAssignableFrom( dataType ); - } + if (column.DataType == typeof(Single)) + return typeof(Nullable); - internal static object TryGetDataRowFromDataItem( object dataItem ) - { - var dataRowView = dataItem as DataRowView; - if( dataRowView != null ) - return dataRowView.Row; + if (column.DataType == typeof(TimeSpan)) + return typeof(Nullable); - return dataItem; - } + if (column.DataType == typeof(UInt16)) + return typeof(Nullable); - internal static DataView TryGetDataViewFromDataGridContext( DataGridContext context ) - { - if( context == null ) - return null; + if (column.DataType == typeof(UInt32)) + return typeof(Nullable); - var dataView = context.ItemsSourceCollection as DataView; - if( dataView != null ) - return dataView; + if (column.DataType == typeof(UInt64)) + return typeof(Nullable); - var collectionViewBase = context.ItemsSourceCollection as DataGridCollectionViewBase; - if( collectionViewBase != null ) - return collectionViewBase.SourceCollection as DataView; + return column.DataType; + } - return null; - } + internal static void CleanUpColumns(ColumnCollection columns, bool deleteAutoCreatedColumn) + { + var tempColumns = new ColumnBase[columns.Count]; + columns.CopyTo(tempColumns, 0); - internal static Type GetColumnDataType( DataColumn column ) - { - if( !column.AllowDBNull ) - return column.DataType; + foreach (ColumnBase column in tempColumns) + { + var dataColumn = column as Column; + if (dataColumn == null) + continue; + + if ((deleteAutoCreatedColumn) && (dataColumn.IsAutoCreated)) + { + columns.Remove(column); + } + else if (dataColumn.IsBindingAutoCreated) + { + dataColumn.IsBindingAutoCreated = false; + dataColumn.IsBoundToDataGridUnboundItemProperty = false; + dataColumn.SetDisplayMemberBinding(null); + } + } + } - if( column.DataType == typeof( Boolean ) ) - return typeof( Nullable ); + internal static PropertyDescriptionRoute CreateOrGetPropertyDescriptionFromColumn(DataGridContext dataGridContext, ColumnBase column, Type itemType) + { + if ((dataGridContext == null) || (column == null) || string.IsNullOrEmpty(column.FieldName)) + return null; - if( column.DataType == typeof( Byte ) ) - return typeof( Nullable ); + var key = PropertyRouteParser.Parse(column.FieldName); + if (key == null) + return null; - if( column.DataType == typeof( Char ) ) - return typeof( Nullable ); + var propertyDescriptions = dataGridContext.ItemsSourcePropertyDescriptions; + if (propertyDescriptions == null) + return null; - if( column.DataType == typeof( DateTime ) ) - return typeof( Nullable ); + var propertyDescriptionRoute = default(PropertyDescriptionRoute); + if (!propertyDescriptions.TryGetValue(key, out propertyDescriptionRoute)) + { + if ((itemType == null) || typeof(EmptyDataItem).IsAssignableFrom(itemType)) + { + var dataGridCollectionView = dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; + if (dataGridCollectionView != null) + { + itemType = dataGridCollectionView.ItemType; + } + else + { + var dataItem = ItemsSourceHelper.GetFirstItemByEnumerable(dataGridContext.Items); + + itemType = ((dataItem != null) && !(dataItem is EmptyDataItem)) ? dataItem.GetType() : null; + } + } + + ItemsSourceHelper.SetPropertyDescriptions(propertyDescriptions, null, dataGridContext.Items, itemType, key); + + if (!propertyDescriptions.TryGetValue(key, out propertyDescriptionRoute)) + return null; + } - if( column.DataType == typeof( Decimal ) ) - return typeof( Nullable ); + return propertyDescriptionRoute; + } - if( column.DataType == typeof( Double ) ) - return typeof( Nullable ); + internal static System.Windows.Data.Binding CreateDefaultBinding(PropertyDescriptionRoute propertyDescriptionRoute) + { + if (propertyDescriptionRoute == null) + return null; - if( column.DataType == typeof( Int16 ) ) - return typeof( Nullable ); + var propertyDescription = propertyDescriptionRoute.Current; + var bindingXPath = propertyDescription.XPath; + var bindingPath = new StringBuilder(); + var isPropertyDescriptorFirstAccessor = false; - if( column.DataType == typeof( Int32 ) ) - return typeof( Nullable ); + var propertyDescriptors = new List(); + if (propertyDescription.PropertyDescriptor != null) + { + bindingPath.Append("(").Append(propertyDescriptors.Count).Append(")"); + propertyDescriptors.Add(propertyDescription.PropertyDescriptor); + isPropertyDescriptorFirstAccessor = true; + } + else if (!string.IsNullOrEmpty(propertyDescription.Path)) + { + bindingPath.Append(propertyDescription.Path); + } - if( column.DataType == typeof( Int64 ) ) - return typeof( Nullable ); + var currentPropertyDescriptionRoute = propertyDescriptionRoute.Parent; - if( column.DataType == typeof( SByte ) ) - return typeof( Nullable ); + while (currentPropertyDescriptionRoute != null) + { + var currentPropertyDescription = currentPropertyDescriptionRoute.Current; - if( column.DataType == typeof( Single ) ) - return typeof( Nullable ); + if (currentPropertyDescription.SupportDBNull) + throw new InvalidOperationException("Cannot create binding when a parent property supports DBNull."); - if( column.DataType == typeof( TimeSpan ) ) - return typeof( Nullable ); + if (currentPropertyDescription.IsDataGridUnboundItemProperty) + throw new InvalidOperationException("Cannot create binding when a parent property is linked to an UnboundDataGridItemProperty."); - if( column.DataType == typeof( UInt16 ) ) - return typeof( Nullable ); + if (currentPropertyDescription.ForeignKeyDescription != null) + throw new InvalidOperationException("Cannot create binding when a parent property is a foreign key."); - if( column.DataType == typeof( UInt32 ) ) - return typeof( Nullable ); + if (!string.IsNullOrEmpty(bindingXPath)) + throw new InvalidOperationException("Cannot create binding when a child property has an XPath."); - if( column.DataType == typeof( UInt64 ) ) - return typeof( Nullable ); + bindingXPath = currentPropertyDescription.XPath; - return column.DataType; - } + if (currentPropertyDescription.PropertyDescriptor != null) + { + isPropertyDescriptorFirstAccessor = true; - internal static void CleanUpColumns( ColumnCollection columns, bool deleteAutoCreatedColumn ) - { - var tempColumns = new ColumnBase[ columns.Count ]; - columns.CopyTo( tempColumns, 0 ); + if (bindingPath.Length != 0) + { + bindingPath.Insert(0, "."); + } - foreach( ColumnBase column in tempColumns ) - { - var dataColumn = column as Column; - if( dataColumn == null ) - continue; + bindingPath.Insert(0, ")").Insert(0, propertyDescriptors.Count).Insert(0, "("); + propertyDescriptors.Add(currentPropertyDescription.PropertyDescriptor); + } + else if (!string.IsNullOrEmpty(currentPropertyDescription.Path)) + { + isPropertyDescriptorFirstAccessor = false; - if( ( deleteAutoCreatedColumn ) && ( dataColumn.IsAutoCreated ) ) - { - columns.Remove( column ); - } - else if( dataColumn.IsBindingAutoCreated ) - { - dataColumn.IsBindingAutoCreated = false; - dataColumn.IsBoundToDataGridUnboundItemProperty = false; - dataColumn.SetDisplayMemberBinding( null ); - } - } - } + if (bindingPath.Length != 0) + { + bindingPath.Insert(0, "."); + } - internal static PropertyDescriptionRoute CreateOrGetPropertyDescriptionFromColumn( DataGridContext dataGridContext, ColumnBase column, Type itemType ) - { - if( ( dataGridContext == null ) || ( column == null ) || string.IsNullOrEmpty( column.FieldName ) ) - return null; + bindingPath.Insert(0, currentPropertyDescription.Path); + } - var key = PropertyRouteParser.Parse( column.FieldName ); - if( key == null ) - return null; + currentPropertyDescriptionRoute = currentPropertyDescriptionRoute.Parent; + } - var propertyDescriptions = dataGridContext.ItemsSourcePropertyDescriptions; - if( propertyDescriptions == null ) - return null; + var bindingInfo = new DataGridBindingInfo(); - var propertyDescriptionRoute = default( PropertyDescriptionRoute ); - if( !propertyDescriptions.TryGetValue( key, out propertyDescriptionRoute ) ) - { - if( ( itemType == null ) || typeof( EmptyDataItem ).IsAssignableFrom( itemType ) ) - { - var dataGridCollectionView = dataGridContext.ItemsSourceCollection as DataGridCollectionViewBase; - if( dataGridCollectionView != null ) - { - itemType = dataGridCollectionView.ItemType; - } - else - { - var dataItem = ItemsSourceHelper.GetFirstItemByEnumerable( dataGridContext.Items ); + if (!string.IsNullOrEmpty(bindingXPath)) + { + bindingInfo.XPath = bindingXPath; + } + else + { + // We must insert a PropertyDescriptor to manage EmptyDataItem when the accessor is not from a DataGridItemPropertyBase. + if (isPropertyDescriptorFirstAccessor && !(propertyDescriptors.Last() is DataGridItemPropertyBase.PropertyDescriptorFromItemPropertyBase)) + { + if (bindingPath.Length != 0) + { + bindingPath.Insert(0, "."); + } + + bindingPath.Insert(0, ")").Insert(0, propertyDescriptors.Count).Insert(0, "("); + propertyDescriptors.Add(EmptyDataItemSafePropertyDescriptor.Singleton); + } + } - itemType = ( ( dataItem != null ) && !( dataItem is EmptyDataItem ) ) ? dataItem.GetType() : null; - } - } + bindingInfo.Path = new PropertyPath(bindingPath.ToString(), propertyDescriptors.ToArray()); + bindingInfo.ReadOnly = (propertyDescription.IsReadOnly && !propertyDescription.OverrideReadOnlyForInsertion); + bindingInfo.Converter = new SourceDataConverter(propertyDescription.SupportDBNull); - ItemsSourceHelper.SetPropertyDescriptions( propertyDescriptions, null, dataGridContext.Items, itemType, key ); + bindingInfo.ValidationRules.Add(new SourceDataConverterValidationRule(propertyDescription.SupportDBNull, propertyDescription.DataType)); - if( !propertyDescriptions.TryGetValue( key, out propertyDescriptionRoute ) ) - return null; - } + return bindingInfo.GetBinding(); + } - return propertyDescriptionRoute; - } + private static Type GetTypedListIndexerType(Type listType) + { + if ((!typeof(IList).IsAssignableFrom(listType) && !typeof(ITypedList).IsAssignableFrom(listType)) && !typeof(IListSource).IsAssignableFrom(listType)) + return null; - internal static System.Windows.Data.Binding CreateDefaultBinding( PropertyDescriptionRoute propertyDescriptionRoute ) - { - if( propertyDescriptionRoute == null ) - return null; + var info = default(PropertyInfo); + var propertyInfos = listType.GetProperties(BindingFlags.Public | BindingFlags.Instance); - var propertyDescription = propertyDescriptionRoute.Current; - var bindingXPath = propertyDescription.XPath; - var bindingPath = new StringBuilder(); - var isPropertyDescriptorFirstAccessor = false; + foreach (var propertyInfo in propertyInfos) + { + if ((propertyInfo.GetIndexParameters().Length > 0) && (propertyInfo.PropertyType != typeof(object))) + { + info = propertyInfo; - var propertyDescriptors = new List(); - if( propertyDescription.PropertyDescriptor != null ) - { - bindingPath.Append( "(" ).Append( propertyDescriptors.Count ).Append( ")" ); - propertyDescriptors.Add( propertyDescription.PropertyDescriptor ); - isPropertyDescriptorFirstAccessor = true; - } - else if( !string.IsNullOrEmpty( propertyDescription.Path ) ) - { - bindingPath.Append( propertyDescription.Path ); - } + if (info.Name == "Item") + return info.PropertyType; + } + } - var currentPropertyDescriptionRoute = propertyDescriptionRoute.Parent; + if (info != null) + return info.PropertyType; - while( currentPropertyDescriptionRoute != null ) - { - var currentPropertyDescription = currentPropertyDescriptionRoute.Current; + return null; + } - if( currentPropertyDescription.SupportDBNull ) - throw new InvalidOperationException( "Cannot create binding when a parent property supports DBNull." ); + private static Type GetTypedEnumerationItemType(Type listType) + { + if (listType == null) + return null; - if( currentPropertyDescription.IsDataGridUnboundItemProperty ) - throw new InvalidOperationException( "Cannot create binding when a parent property is linked to an UnboundDataGridItemProperty." ); + foreach (Type interfaceType in listType.GetInterfaces()) + { + if ((interfaceType.IsGenericType) && (interfaceType.GetGenericTypeDefinition() == typeof(IEnumerable<>))) + return interfaceType.GetGenericArguments()[0]; + } - if( currentPropertyDescription.ForeignKeyDescription != null ) - throw new InvalidOperationException( "Cannot create binding when a parent property is a foreign key." ); + return null; + } - if( !string.IsNullOrEmpty( bindingXPath ) ) - throw new InvalidOperationException( "Cannot create binding when a child property has an XPath." ); + private static void SetPropertyDescriptions(PropertyDescriptionRouteDictionary propertyDescriptions, DataTable model, IEnumerable itemsSource, Type itemType, PropertyRoute propertyRoute) + { + if ((propertyDescriptions == null) || (propertyRoute == null) || propertyDescriptions.Contains(propertyRoute)) + return; - bindingXPath = currentPropertyDescription.XPath; + var parentKey = propertyRoute.Parent; + if (parentKey != null) + { + ItemsSourceHelper.SetPropertyDescriptions(propertyDescriptions, model, itemsSource, itemType, parentKey); + + PropertyDescriptionRoute parentPropertyDescriptionRoute; + if (!propertyDescriptions.TryGetValue(parentKey, out parentPropertyDescriptionRoute)) + return; + + var parentItemType = parentPropertyDescriptionRoute.Current.DataType; + var childPropertyDescriptions = new PropertyDescriptionRouteDictionary(); + + ItemsSourceHelper.SetPropertyDescriptions(childPropertyDescriptions, null, null, parentItemType, false); + + foreach (var childPropertyDescriptionRoute in childPropertyDescriptions.Values) + { + var newPropertyDescriptionRoute = PropertyDescriptionRoute.Combine(childPropertyDescriptionRoute, parentPropertyDescriptionRoute); + var newPropertyRoute = PropertyRouteBuilder.ToPropertyRoute(newPropertyDescriptionRoute); + + if ((newPropertyRoute == null) || propertyDescriptions.Contains(newPropertyRoute)) + continue; + + propertyDescriptions.Add(newPropertyRoute, newPropertyDescriptionRoute, false); + } + + var currentSegment = propertyRoute.Current; + if (currentSegment.Type == PropertyRouteSegmentType.Indexer) + { + var indexerDescriptionRoute = ItemsSourceHelper.CreateIndexerDescription(itemsSource, parentItemType, currentSegment.Name, false); + if (indexerDescriptionRoute != null) + { + var newIndexerDescriptionRoute = PropertyDescriptionRoute.Combine(indexerDescriptionRoute, parentPropertyDescriptionRoute); + if (newIndexerDescriptionRoute != null) + { + var newIndexerRoute = PropertyRouteBuilder.ToPropertyRoute(newIndexerDescriptionRoute); + if ((newIndexerRoute != null) && !propertyDescriptions.Contains(newIndexerRoute)) + { + propertyDescriptions.Add(newIndexerRoute, newIndexerDescriptionRoute, false); + } + } + } + } + } + else + { + ItemsSourceHelper.SetPropertyDescriptions(propertyDescriptions, model, itemsSource, itemType, false); + + var currentSegment = propertyRoute.Current; + if (currentSegment.Type == PropertyRouteSegmentType.Indexer) + { + var newIndexerDescriptionRoute = ItemsSourceHelper.CreateIndexerDescription(itemsSource, itemType, currentSegment.Name, false); + if (newIndexerDescriptionRoute != null) + { + var newIndexerRoute = PropertyRouteBuilder.ToPropertyRoute(newIndexerDescriptionRoute); + if ((newIndexerRoute != null) && !propertyDescriptions.Contains(newIndexerRoute)) + { + propertyDescriptions.Add(newIndexerRoute, newIndexerDescriptionRoute, false); + } + } + } + } + } - if( currentPropertyDescription.PropertyDescriptor != null ) + private static IEnumerable CreatePropertyDescriptionsFromDataTable(DataTable source, bool displayable) { - isPropertyDescriptorFirstAccessor = true; + Debug.Assert(source != null); - if( bindingPath.Length != 0 ) - { - bindingPath.Insert( 0, "." ); - } + var foreignKeyConstraints = ItemsSourceHelper.GetForeignKeyConstraints(source.Constraints); + var columns = source.Columns; - bindingPath.Insert( 0, ")" ).Insert( 0, propertyDescriptors.Count ).Insert( 0, "(" ); - propertyDescriptors.Add( currentPropertyDescription.PropertyDescriptor ); + foreach (DataColumn column in columns) + { + yield return new PropertyDescriptionRoute( + new DataTablePropertyDescription( + new DataRowColumnPropertyDescriptor(column), + column, + foreignKeyConstraints, + displayable)); + } } - else if( !string.IsNullOrEmpty( currentPropertyDescription.Path ) ) + + private static IEnumerable CreatePropertyDescriptionsFromDataView(DataView source, bool displayable) { - isPropertyDescriptorFirstAccessor = false; + Debug.Assert(source != null); - if( bindingPath.Length != 0 ) - { - bindingPath.Insert( 0, "." ); - } + var itemProperties = ((ITypedList)source).GetItemProperties(null); + var dataTable = source.Table; + var foreignKeyConstraints = ItemsSourceHelper.GetForeignKeyConstraints(dataTable.Constraints); + var columns = dataTable.Columns; - bindingPath.Insert( 0, currentPropertyDescription.Path ); + foreach (PropertyDescriptor propertyDescriptor in itemProperties) + { + yield return new PropertyDescriptionRoute(new DataTablePropertyDescription(propertyDescriptor, columns[propertyDescriptor.Name], foreignKeyConstraints, displayable)); + } } - currentPropertyDescriptionRoute = currentPropertyDescriptionRoute.Parent; - } - - var bindingInfo = new DataGridBindingInfo(); - - if( !string.IsNullOrEmpty( bindingXPath ) ) - { - bindingInfo.XPath = bindingXPath; - } - else - { - // We must insert a PropertyDescriptor to manage EmptyDataItem when the accessor is not from a DataGridItemPropertyBase. - if( isPropertyDescriptorFirstAccessor && !( propertyDescriptors.Last() is DataGridItemPropertyBase.PropertyDescriptorFromItemPropertyBase ) ) + private static IEnumerable CreatePropertyDescriptionsFromDataGridCollectionView(DataGridCollectionViewBase source) { - if( bindingPath.Length != 0 ) - { - bindingPath.Insert( 0, "." ); - } + if (source == null) + return Enumerable.Empty(); - bindingPath.Insert( 0, ")" ).Insert( 0, propertyDescriptors.Count ).Insert( 0, "(" ); - propertyDescriptors.Add( EmptyDataItemSafePropertyDescriptor.Singleton ); + return ItemsSourceHelper.CreatePropertyDescriptionsFromItemProperties(source.ItemProperties); } - } - - bindingInfo.Path = new PropertyPath( bindingPath.ToString(), propertyDescriptors.ToArray() ); - bindingInfo.ReadOnly = ( propertyDescription.IsReadOnly && !propertyDescription.OverrideReadOnlyForInsertion ); - bindingInfo.Converter = new SourceDataConverter( propertyDescription.SupportDBNull ); - bindingInfo.ValidationRules.Add( new SourceDataConverterValidationRule( propertyDescription.SupportDBNull, propertyDescription.DataType ) ); - - return bindingInfo.GetBinding(); - } + private static IEnumerable CreatePropertyDescriptionsFromItemProperties(IEnumerable source) + { + if (source == null) + yield break; - private static Type GetTypedListIndexerType( Type listType ) - { - if( ( !typeof( IList ).IsAssignableFrom( listType ) && !typeof( ITypedList ).IsAssignableFrom( listType ) ) && !typeof( IListSource ).IsAssignableFrom( listType ) ) - return null; + foreach (var itemProperty in source) + { + yield return ItemsSourceHelper.CreatePropertyDescriptionFromDataGridItemProperty(itemProperty); - var info = default( PropertyInfo ); - var propertyInfos = listType.GetProperties( BindingFlags.Public | BindingFlags.Instance ); + foreach (var childItemProperty in ItemsSourceHelper.CreatePropertyDescriptionsFromItemProperties(itemProperty.ItemPropertiesInternal)) + { + yield return childItemProperty; + } + } + } - foreach( var propertyInfo in propertyInfos ) - { - if( ( propertyInfo.GetIndexParameters().Length > 0 ) && ( propertyInfo.PropertyType != typeof( object ) ) ) + private static IEnumerable CreatePropertyDescriptionsFromPropertyDescriptors(PropertyDescriptorCollection source, bool supportsDBNull, bool displayable) { - info = propertyInfo; + if (source == null) + yield break; - if( info.Name == "Item" ) - return info.PropertyType; + foreach (PropertyDescriptor propertyDescriptor in source) + { + yield return new PropertyDescriptionRoute(new PropertyDescriptorPropertyDescription(propertyDescriptor, supportsDBNull, displayable)); + } } - } - - if( info != null ) - return info.PropertyType; - return null; - } - - private static Type GetTypedEnumerationItemType( Type listType ) - { - if( listType == null ) - return null; + private static IEnumerable CreatePropertyDescriptionsFromItemType(IEnumerable itemsSource, Type itemType, bool supportsDBNull, bool displayable) + { + if (itemType == null) + return Enumerable.Empty(); - foreach( Type interfaceType in listType.GetInterfaces() ) - { - if( ( interfaceType.IsGenericType ) && ( interfaceType.GetGenericTypeDefinition() == typeof( IEnumerable<> ) ) ) - return interfaceType.GetGenericArguments()[ 0 ]; - } + if (typeof(XmlNode).IsAssignableFrom(itemType)) + return Enumerable.Empty(); - return null; - } + if (itemType.IsArray) + return ItemsSourceHelper.CreatePropertyDescriptionsFromJaggedArray(itemType, itemsSource, displayable); - private static void SetPropertyDescriptions( PropertyDescriptionRouteDictionary propertyDescriptions, DataTable model, IEnumerable itemsSource, Type itemType, PropertyRoute propertyRoute ) - { - if( ( propertyDescriptions == null ) || ( propertyRoute == null ) || propertyDescriptions.Contains( propertyRoute ) ) - return; + if (itemType.IsInterface) + return ItemsSourceHelper.CreatePropertyDescriptionsFromInterface(itemType, displayable); - var parentKey = propertyRoute.Parent; - if( parentKey != null ) - { - ItemsSourceHelper.SetPropertyDescriptions( propertyDescriptions, model, itemsSource, itemType, parentKey ); + if (ItemsSourceHelper.IsEntityFramework(itemType)) + return ItemsSourceHelper.CreatePropertyDescriptionsFromEntityFramework(itemType, displayable); - PropertyDescriptionRoute parentPropertyDescriptionRoute; - if( !propertyDescriptions.TryGetValue( parentKey, out parentPropertyDescriptionRoute ) ) - return; + if (ItemsSourceHelper.IsValueType(itemType)) + { + var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor(itemsSource, itemType); - var parentItemType = parentPropertyDescriptionRoute.Current.DataType; - var childPropertyDescriptions = new PropertyDescriptionRouteDictionary(); + return ItemsSourceHelper.CreatePropertyDescriptionsFromValueType(itemType, supportsDBNull, null, displayable).Concat( + (customTypeDescriptor != null) + ? ItemsSourceHelper.CreatePropertyDescriptionsFromCustomTypeDescriptor(customTypeDescriptor, itemType, supportsDBNull, false) + : ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors(TypeDescriptor.GetProperties(itemType), supportsDBNull, false)); + } + else + { + var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor(itemsSource, itemType); + if (customTypeDescriptor != null) + return ItemsSourceHelper.CreatePropertyDescriptionsFromCustomTypeDescriptor(customTypeDescriptor, itemType, supportsDBNull, displayable); - ItemsSourceHelper.SetPropertyDescriptions( childPropertyDescriptions, null, null, parentItemType, false ); + return ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors(TypeDescriptor.GetProperties(itemType), supportsDBNull, displayable); + } + } - foreach( var childPropertyDescriptionRoute in childPropertyDescriptions.Values ) + private static IEnumerable CreatePropertyDescriptionsFromJaggedArray(Type itemType, IEnumerable jaggedArray, bool displayable) { - var newPropertyDescriptionRoute = PropertyDescriptionRoute.Combine( childPropertyDescriptionRoute, parentPropertyDescriptionRoute ); - var newPropertyRoute = PropertyRouteBuilder.ToPropertyRoute( newPropertyDescriptionRoute ); + var firstItem = ItemsSourceHelper.GetFirstItemByEnumerable(jaggedArray) as Array; + if ((firstItem == null) || (itemType == null)) + yield break; - if( ( newPropertyRoute == null ) || propertyDescriptions.Contains( newPropertyRoute ) ) - continue; + var fieldCount = firstItem.GetLength(0); + var fieldType = itemType.GetElementType(); - propertyDescriptions.Add( newPropertyRoute, newPropertyDescriptionRoute, false ); + for (int i = 0; i < fieldCount; i++) + { + yield return new PropertyDescriptionRoute(new JaggedArrayPropertyDescription(i, fieldType, displayable)); + } } - var currentSegment = propertyRoute.Current; - if( currentSegment.Type == PropertyRouteSegmentType.Indexer ) + private static IEnumerable CreatePropertyDescriptionsFromInterface(Type itemType, bool displayable) { - var indexerDescriptionRoute = ItemsSourceHelper.CreateIndexerDescription( itemsSource, parentItemType, currentSegment.Name, false ); - if( indexerDescriptionRoute != null ) - { - var newIndexerDescriptionRoute = PropertyDescriptionRoute.Combine( indexerDescriptionRoute, parentPropertyDescriptionRoute ); - if( newIndexerDescriptionRoute != null ) + var propertyDescriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors(TypeDescriptor.GetProperties(itemType), false, displayable).ToList(); + var names = new HashSet(propertyDescriptions.Select(item => PropertyRouteParser.Parse(PropertyRouteBuilder.ToPropertyRoute(item)))); + + foreach (var interfaceType in itemType.GetInterfaces()) { - var newIndexerRoute = PropertyRouteBuilder.ToPropertyRoute( newIndexerDescriptionRoute ); - if( ( newIndexerRoute != null ) && !propertyDescriptions.Contains( newIndexerRoute ) ) - { - propertyDescriptions.Add( newIndexerRoute, newIndexerDescriptionRoute, false ); - } + foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(interfaceType)) + { + PropertyDescription propertyDescription; + + if (names.Contains(propertyDescriptor.Name)) + { + var newName = string.Format("{0}.{1}", interfaceType.FullName, propertyDescriptor.Name); + propertyDescription = new NamedPropertyDescriptorPropertyDescription(newName, propertyDescriptor, false, displayable); + } + else + { + propertyDescription = new PropertyDescriptorPropertyDescription(propertyDescriptor, false, displayable); + } + + Debug.Assert(propertyDescription != null); + + names.Add(propertyDescription.Name); + propertyDescriptions.Add(new PropertyDescriptionRoute(propertyDescription)); + } } - } + + return propertyDescriptions; } - } - else - { - ItemsSourceHelper.SetPropertyDescriptions( propertyDescriptions, model, itemsSource, itemType, false ); - var currentSegment = propertyRoute.Current; - if( currentSegment.Type == PropertyRouteSegmentType.Indexer ) + private static IEnumerable CreatePropertyDescriptionsFromEntityFramework(Type itemType, bool displayable) { - var newIndexerDescriptionRoute = ItemsSourceHelper.CreateIndexerDescription( itemsSource, itemType, currentSegment.Name, false ); - if( newIndexerDescriptionRoute != null ) - { - var newIndexerRoute = PropertyRouteBuilder.ToPropertyRoute( newIndexerDescriptionRoute ); - if( ( newIndexerRoute != null ) && !propertyDescriptions.Contains( newIndexerRoute ) ) + foreach (PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties(itemType)) { - propertyDescriptions.Add( newIndexerRoute, newIndexerDescriptionRoute, false ); + yield return new PropertyDescriptionRoute(new EntityFrameworkPropertyDescription(propertyDescriptor, displayable)); } - } } - } - } - - private static IEnumerable CreatePropertyDescriptionsFromDataTable( DataTable source, bool displayable ) - { - Debug.Assert( source != null ); - - var foreignKeyConstraints = ItemsSourceHelper.GetForeignKeyConstraints( source.Constraints ); - var columns = source.Columns; - - foreach( DataColumn column in columns ) - { - yield return new PropertyDescriptionRoute( - new DataTablePropertyDescription( - new DataRowColumnPropertyDescriptor( column ), - column, - foreignKeyConstraints, - displayable ) ); - } - } - - private static IEnumerable CreatePropertyDescriptionsFromDataView( DataView source, bool displayable ) - { - Debug.Assert( source != null ); - - var itemProperties = ( ( ITypedList )source ).GetItemProperties( null ); - var dataTable = source.Table; - var foreignKeyConstraints = ItemsSourceHelper.GetForeignKeyConstraints( dataTable.Constraints ); - var columns = dataTable.Columns; - - foreach( PropertyDescriptor propertyDescriptor in itemProperties ) - { - yield return new PropertyDescriptionRoute( new DataTablePropertyDescription( propertyDescriptor, columns[ propertyDescriptor.Name ], foreignKeyConstraints, displayable ) ); - } - } - private static IEnumerable CreatePropertyDescriptionsFromDataGridCollectionView( DataGridCollectionViewBase source ) - { - if( source == null ) - return Enumerable.Empty(); - - return ItemsSourceHelper.CreatePropertyDescriptionsFromItemProperties( source.ItemProperties ); - } - - private static IEnumerable CreatePropertyDescriptionsFromItemProperties( IEnumerable source ) - { - if( source == null ) - yield break; - - foreach( var itemProperty in source ) - { - yield return ItemsSourceHelper.CreatePropertyDescriptionFromDataGridItemProperty( itemProperty ); - - foreach( var childItemProperty in ItemsSourceHelper.CreatePropertyDescriptionsFromItemProperties( itemProperty.ItemPropertiesInternal ) ) + private static IEnumerable CreatePropertyDescriptionsFromValueType(Type itemType, bool supportsDBNull, DataGridForeignKeyDescription foreignKeyDescription, bool displayable) { - yield return childItemProperty; + yield return new PropertyDescriptionRoute(new ValueTypePropertyDescription(itemType, supportsDBNull, foreignKeyDescription, displayable)); } - } - } - private static IEnumerable CreatePropertyDescriptionsFromPropertyDescriptors( PropertyDescriptorCollection source, bool supportsDBNull, bool displayable ) - { - if( source == null ) - yield break; - - foreach( PropertyDescriptor propertyDescriptor in source ) - { - yield return new PropertyDescriptionRoute( new PropertyDescriptorPropertyDescription( propertyDescriptor, supportsDBNull, displayable ) ); - } - } - - private static IEnumerable CreatePropertyDescriptionsFromItemType( IEnumerable itemsSource, Type itemType, bool supportsDBNull, bool displayable ) - { - if( itemType == null ) - return Enumerable.Empty(); - - if( typeof( XmlNode ).IsAssignableFrom( itemType ) ) - return Enumerable.Empty(); - - if( itemType.IsArray ) - return ItemsSourceHelper.CreatePropertyDescriptionsFromJaggedArray( itemType, itemsSource, displayable ); - - if( itemType.IsInterface ) - return ItemsSourceHelper.CreatePropertyDescriptionsFromInterface( itemType, displayable ); - - if( ItemsSourceHelper.IsEntityFramework( itemType ) ) - return ItemsSourceHelper.CreatePropertyDescriptionsFromEntityFramework( itemType, displayable ); - - if( ItemsSourceHelper.IsValueType( itemType ) ) - { - var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor( itemsSource, itemType ); - - return ItemsSourceHelper.CreatePropertyDescriptionsFromValueType( itemType, supportsDBNull, null, displayable ).Concat( - ( customTypeDescriptor != null ) - ? ItemsSourceHelper.CreatePropertyDescriptionsFromCustomTypeDescriptor( customTypeDescriptor, itemType, supportsDBNull, false ) - : ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors( TypeDescriptor.GetProperties( itemType ), supportsDBNull, false ) ); - } - else - { - var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor( itemsSource, itemType ); - if( customTypeDescriptor != null ) - return ItemsSourceHelper.CreatePropertyDescriptionsFromCustomTypeDescriptor( customTypeDescriptor, itemType, supportsDBNull, displayable ); - - return ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors( TypeDescriptor.GetProperties( itemType ), supportsDBNull, displayable ); - } - } + private static IEnumerable CreatePropertyDescriptionsFromCustomTypeDescriptor(ICustomTypeDescriptor customTypeDescriptor, Type itemType, bool supportsDBNull, bool displayable) + { + if (customTypeDescriptor == null) + return Enumerable.Empty(); - private static IEnumerable CreatePropertyDescriptionsFromJaggedArray( Type itemType, IEnumerable jaggedArray, bool displayable ) - { - var firstItem = ItemsSourceHelper.GetFirstItemByEnumerable( jaggedArray ) as Array; - if( ( firstItem == null ) || ( itemType == null ) ) - yield break; + return ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors(customTypeDescriptor.GetProperties(), supportsDBNull, displayable); + } - var fieldCount = firstItem.GetLength( 0 ); - var fieldType = itemType.GetElementType(); + private static PropertyDescriptionRoute CreatePropertyDescriptionFromDataGridItemProperty(DataGridItemPropertyBase source) + { + if (source == null) + return null; - for( int i = 0; i < fieldCount; i++ ) - { - yield return new PropertyDescriptionRoute( new JaggedArrayPropertyDescription( i, fieldType, displayable ) ); - } - } + var collection = source.ContainingCollection; + var ancestors = (collection != null) ? ItemsSourceHelper.CreatePropertyDescriptionFromDataGridItemProperty(collection.Owner) : null; - private static IEnumerable CreatePropertyDescriptionsFromInterface( Type itemType, bool displayable ) - { - var propertyDescriptions = ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors( TypeDescriptor.GetProperties( itemType ), false, displayable ).ToList(); - var names = new HashSet( propertyDescriptions.Select( item => PropertyRouteParser.Parse( PropertyRouteBuilder.ToPropertyRoute( item ) ) ) ); + return PropertyDescriptionRoute.Combine(new ItemPropertyPropertyDescription(source), ancestors); + } - foreach( var interfaceType in itemType.GetInterfaces() ) - { - foreach( PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties( interfaceType ) ) + private static PropertyDescriptionRoute CreateIndexerDescription(IEnumerable itemsSource, Type itemType, string index, bool displayable) { - PropertyDescription propertyDescription; - - if( names.Contains( propertyDescriptor.Name ) ) - { - var newName = string.Format( "{0}.{1}", interfaceType.FullName, propertyDescriptor.Name ); - propertyDescription = new NamedPropertyDescriptorPropertyDescription( newName, propertyDescriptor, false, displayable ); - } - else - { - propertyDescription = new PropertyDescriptorPropertyDescription( propertyDescriptor, false, displayable ); - } + if ((itemType == null) || string.IsNullOrEmpty(index)) + return null; - Debug.Assert( propertyDescription != null ); + var typeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor(itemsSource, itemType) as DataItemTypeDescriptor; + if (typeDescriptor == null) + return null; - names.Add( propertyDescription.Name ); - propertyDescriptions.Add( new PropertyDescriptionRoute( propertyDescription ) ); - } - } + var parameters = IndexerParametersParser.Parse(index).ToArray(); + if (parameters.Length <= 0) + return null; - return propertyDescriptions; - } + var indexerDescriptor = typeDescriptor.GetIndexer(parameters); + if (indexerDescriptor == null) + return null; - private static IEnumerable CreatePropertyDescriptionsFromEntityFramework( Type itemType, bool displayable ) - { - foreach( PropertyDescriptor propertyDescriptor in TypeDescriptor.GetProperties( itemType ) ) - { - yield return new PropertyDescriptionRoute( new EntityFrameworkPropertyDescription( propertyDescriptor, displayable ) ); - } - } + var supportsDBNull = ItemsSourceHelper.IsSupportingDBNull(itemsSource); - private static IEnumerable CreatePropertyDescriptionsFromValueType( Type itemType, bool supportsDBNull, DataGridForeignKeyDescription foreignKeyDescription, bool displayable ) - { - yield return new PropertyDescriptionRoute( new ValueTypePropertyDescription( itemType, supportsDBNull, foreignKeyDescription, displayable ) ); - } + return new PropertyDescriptionRoute(new IndexerDescriptorPropertyDescription(indexerDescriptor, supportsDBNull, displayable)); + } - private static IEnumerable CreatePropertyDescriptionsFromCustomTypeDescriptor( ICustomTypeDescriptor customTypeDescriptor, Type itemType, bool supportsDBNull, bool displayable ) - { - if( customTypeDescriptor == null ) - return Enumerable.Empty(); + private static Dictionary GetForeignKeyConstraints(ConstraintCollection constraints) + { + var foreignKeyConstraints = new Dictionary(); - return ItemsSourceHelper.CreatePropertyDescriptionsFromPropertyDescriptors( customTypeDescriptor.GetProperties(), supportsDBNull, displayable ); - } + // Detect every ForeignKeyConstraints + foreach (Constraint constraint in constraints) + { + var foreignKeyConstraint = constraint as ForeignKeyConstraint; + if (foreignKeyConstraint == null) + continue; + + // We only support auto-detection when the ForeignKey is composed of a single column + if ((foreignKeyConstraint.Columns != null) && (foreignKeyConstraint.Columns.Length == 1)) + { + foreignKeyConstraints.Add(foreignKeyConstraint.Columns[0].ColumnName, foreignKeyConstraint); + } + } - private static PropertyDescriptionRoute CreatePropertyDescriptionFromDataGridItemProperty( DataGridItemPropertyBase source ) - { - if( source == null ) - return null; + return foreignKeyConstraints; + } - var collection = source.ContainingCollection; - var ancestors = ( collection != null ) ? ItemsSourceHelper.CreatePropertyDescriptionFromDataGridItemProperty( collection.Owner ) : null; + private static DataGridForeignKeyDescription GetDataGridForeignKeyDescriptionForEnum(Type enumType) + { + if ((enumType == null) || !enumType.IsEnum) + return null; - return PropertyDescriptionRoute.Combine( new ItemPropertyPropertyDescription( source ), ancestors ); - } + var description = new DataGridForeignKeyDescription(); - private static PropertyDescriptionRoute CreateIndexerDescription( IEnumerable itemsSource, Type itemType, string index, bool displayable ) - { - if( ( itemType == null ) || string.IsNullOrEmpty( index ) ) - return null; + // Using "." as default value path will revert to Self when used as SelectedValuePath when bound to a DataGridForeignKeyDictionary or ComboBox (default editor) + description.ValuePath = "."; + description.ItemsSource = Enum.GetValues(enumType); + description.IsAutoCreated = true; - var typeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor( itemsSource, itemType ) as DataItemTypeDescriptor; - if( typeDescriptor == null ) - return null; + return description; + } - var parameters = IndexerParametersParser.Parse( index ).ToArray(); - if( parameters.Length <= 0 ) - return null; + private static DataTableForeignKeyDescription GetDataGridForeignKeyDescriptionForForeignKeyConstraint(ForeignKeyConstraint foreignKeyConstraint) + { + if (foreignKeyConstraint == null) + return null; - var indexerDescriptor = typeDescriptor.GetIndexer( parameters ); - if( indexerDescriptor == null ) - return null; + var columns = foreignKeyConstraint.Columns; + if ((columns == null) || (columns.Length != 1)) + return null; - var supportsDBNull = ItemsSourceHelper.IsSupportingDBNull( itemsSource ); + var description = new DataTableForeignKeyDescription(); + description.ForeignKeyConstraint = foreignKeyConstraint; + description.IsAutoCreated = true; - return new PropertyDescriptionRoute( new IndexerDescriptorPropertyDescription( indexerDescriptor, supportsDBNull, displayable ) ); - } + return description; + } - private static Dictionary GetForeignKeyConstraints( ConstraintCollection constraints ) - { - var foreignKeyConstraints = new Dictionary(); + private static DataGridItemPropertyBase CreateItemPropertyFromPropertyDescription(PropertyDescription propertyDescription) + { + if (propertyDescription == null) + return null; - // Detect every ForeignKeyConstraints - foreach( Constraint constraint in constraints ) - { - var foreignKeyConstraint = constraint as ForeignKeyConstraint; - if( foreignKeyConstraint == null ) - continue; + return new DataGridItemProperty( + propertyDescription.Name, + propertyDescription.PropertyDescriptor, + propertyDescription.DisplayName, + propertyDescription.XPath, + propertyDescription.Path, + propertyDescription.DataType, + true, + propertyDescription.IsReadOnly, + propertyDescription.OverrideReadOnlyForInsertion, + propertyDescription.IsDisplayable, + propertyDescription.IsSubRelationship, + propertyDescription.ForeignKeyDescription); + } - // We only support auto-detection when the ForeignKey is composed of a single column - if( ( foreignKeyConstraint.Columns != null ) && ( foreignKeyConstraint.Columns.Length == 1 ) ) + internal static List CreateDetailDescriptions(Type itemType, IEnumerable enumeration) { - foreignKeyConstraints.Add( foreignKeyConstraint.Columns[ 0 ].ColumnName, foreignKeyConstraint ); - } - } + var dataTable = enumeration as DataTable; + if (dataTable == null) + { + var dataView = enumeration as DataView; + if (dataView != null) + { + dataTable = dataView.Table; + } + } - return foreignKeyConstraints; - } + if (dataTable != null) + return ItemsSourceHelper.CreateDetailDescriptions(dataTable); - private static DataGridForeignKeyDescription GetDataGridForeignKeyDescriptionForEnum( Type enumType ) - { - if( ( enumType == null ) || !enumType.IsEnum ) - return null; + if (itemType != null) + { + //We do not support automatic Master/Detail detection with an Xml source + if (typeof(XmlNode).IsAssignableFrom(itemType)) + return new List(0); - var description = new DataGridForeignKeyDescription(); + //Unbound mode, we do not support Master/Detail in this scenario. + if (typeof(DataRow).IsAssignableFrom(itemType)) + return new List(0); - // Using "." as default value path will revert to Self when used as SelectedValuePath when bound to a DataGridForeignKeyDictionary or ComboBox (default editor) - description.ValuePath = "."; - description.ItemsSource = Enum.GetValues( enumType ); - description.IsAutoCreated = true; + //we do not support Master/Details when Item is a Value type... + if (ItemsSourceHelper.IsValueType(itemType)) + return new List(0); - return description; - } + //Check if the object is a Entity Framework Entity, before checking for IEnumerable (since Entity Framework does have IEnumerable + //properties, but require special handling )... + if (ItemsSourceHelper.IsEntityFramework(itemType)) + return ItemsSourceHelper.CreateDetailDescriptionsForEntityFramework(itemType); - private static DataTableForeignKeyDescription GetDataGridForeignKeyDescriptionForForeignKeyConstraint( ForeignKeyConstraint foreignKeyConstraint ) - { - if( foreignKeyConstraint == null ) - return null; + //If the first item maps to an object that implements IEnumerable, expand that as a Relation ( and only that )... + if (typeof(IEnumerable).IsAssignableFrom(itemType)) + return ItemsSourceHelper.CreateDetailDescriptionsForEnumerable(); - var columns = foreignKeyConstraint.Columns; - if( ( columns == null ) || ( columns.Length != 1 ) ) - return null; + if (typeof(IListSource).IsAssignableFrom(itemType)) + return ItemsSourceHelper.CreateDetailDescriptionsForListSource(); + } - var description = new DataTableForeignKeyDescription(); - description.ForeignKeyConstraint = foreignKeyConstraint; - description.IsAutoCreated = true; + //If the Source collection implements ITypedList + var typedList = enumeration as ITypedList; + if (typedList != null) + return ItemsSourceHelper.GetDataGridDetailDescriptions(typedList.GetItemProperties(null)); - return description; - } + var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor(enumeration, itemType); + if (customTypeDescriptor != null) + return ItemsSourceHelper.GetDataGridDetailDescriptions(customTypeDescriptor.GetProperties()); - private static DataGridItemPropertyBase CreateItemPropertyFromPropertyDescription( PropertyDescription propertyDescription ) - { - if( propertyDescription == null ) - return null; - - return new DataGridItemProperty( - propertyDescription.Name, - propertyDescription.PropertyDescriptor, - propertyDescription.DisplayName, - propertyDescription.XPath, - propertyDescription.Path, - propertyDescription.DataType, - true, - propertyDescription.IsReadOnly, - propertyDescription.OverrideReadOnlyForInsertion, - propertyDescription.IsDisplayable, - propertyDescription.IsSubRelationship, - propertyDescription.ForeignKeyDescription ); - } + if (itemType != null) + return ItemsSourceHelper.GetDataGridDetailDescriptions(TypeDescriptor.GetProperties(itemType)); - internal static List CreateDetailDescriptions( Type itemType, IEnumerable enumeration ) - { - var dataTable = enumeration as DataTable; - if( dataTable == null ) - { - var dataView = enumeration as DataView; - if( dataView != null ) - { - dataTable = dataView.Table; + return new List(0); } - } - if( dataTable != null ) - return ItemsSourceHelper.CreateDetailDescriptions( dataTable ); - - if( itemType != null ) - { - //We do not support automatic Master/Detail detection with an Xml source - if( typeof( XmlNode ).IsAssignableFrom( itemType ) ) - return new List( 0 ); + internal static List CreateDetailDescriptions(DataTable dataTable) + { + if (dataTable == null) + return new List(0); - //Unbound mode, we do not support Master/Detail in this scenario. - if( typeof( DataRow ).IsAssignableFrom( itemType ) ) - return new List( 0 ); + return ItemsSourceHelper.CreateDetailDescriptionsForDataTable(dataTable); + } - //we do not support Master/Details when Item is a Value type... - if( ItemsSourceHelper.IsValueType( itemType ) ) - return new List( 0 ); + private static List CreateDetailDescriptionsForDataTable(DataTable dataTable) + { + var detailDescriptions = new List(dataTable.ChildRelations.Count); - //Check if the object is a Entity Framework Entity, before checking for IEnumerable (since Entity Framework does have IEnumerable - //properties, but require special handling )... - if( ItemsSourceHelper.IsEntityFramework( itemType ) ) - return ItemsSourceHelper.CreateDetailDescriptionsForEntityFramework( itemType ); + foreach (DataRelation relation in dataTable.ChildRelations) + { + var description = new DataRelationDetailDescription(relation); + description.IsAutoCreated = true; + description.IsInitialized = true; + detailDescriptions.Add(description); + } - //If the first item maps to an object that implements IEnumerable, expand that as a Relation ( and only that )... - if( typeof( IEnumerable ).IsAssignableFrom( itemType ) ) - return ItemsSourceHelper.CreateDetailDescriptionsForEnumerable(); + return detailDescriptions; + } - if( typeof( IListSource ).IsAssignableFrom( itemType ) ) - return ItemsSourceHelper.CreateDetailDescriptionsForListSource(); - } + private static List CreateDetailDescriptionsForEntityFramework(Type type) + { + var detailDescriptions = new List(); - //If the Source collection implements ITypedList - var typedList = enumeration as ITypedList; - if( typedList != null ) - return ItemsSourceHelper.GetDataGridDetailDescriptions( typedList.GetItemProperties( null ) ); + // Gets all the public properties of the type. + var propertyInfos = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); - var customTypeDescriptor = ItemsSourceHelper.GetCustomTypeDescriptor( enumeration, itemType ); - if( customTypeDescriptor != null ) - return ItemsSourceHelper.GetDataGridDetailDescriptions( customTypeDescriptor.GetProperties() ); + // Loop throught the properties to build up the detail descriptions. + foreach (var propertyInfo in propertyInfos) + { + // We must use Reflection to check for the EntityFramework types. + var propertyType = propertyInfo.PropertyType; + + // The property must be of type RelatedEnd and IEnumerable to continue. + if ((propertyType.BaseType != null) + && (propertyType.BaseType.FullName == "System.Data.Objects.DataClasses.RelatedEnd") + && (typeof(IEnumerable).IsAssignableFrom(propertyType))) + { + detailDescriptions.Add(new EntityDetailDescription(propertyInfo.Name)); + } + } - if( itemType != null ) - return ItemsSourceHelper.GetDataGridDetailDescriptions( TypeDescriptor.GetProperties( itemType ) ); + return detailDescriptions; + } - return new List( 0 ); - } + private static List CreateDetailDescriptionsForEnumerable() + { + var detailDescriptions = new List(1); - internal static List CreateDetailDescriptions( DataTable dataTable ) - { - if( dataTable == null ) - return new List( 0 ); + var description = new EnumerableDetailDescription(); + description.IsAutoCreated = true; + description.IsInitialized = true; + detailDescriptions.Add(description); - return ItemsSourceHelper.CreateDetailDescriptionsForDataTable( dataTable ); - } + return detailDescriptions; + } - private static List CreateDetailDescriptionsForDataTable( DataTable dataTable ) - { - var detailDescriptions = new List( dataTable.ChildRelations.Count ); + private static List CreateDetailDescriptionsForListSource() + { + var detailDescriptions = new List(1); - foreach( DataRelation relation in dataTable.ChildRelations ) - { - var description = new DataRelationDetailDescription( relation ); - description.IsAutoCreated = true; - description.IsInitialized = true; - detailDescriptions.Add( description ); - } + var description = new ListSourceDetailDescription(); + description.IsAutoCreated = true; + description.IsInitialized = true; + detailDescriptions.Add(description); - return detailDescriptions; - } + return detailDescriptions; + } - private static List CreateDetailDescriptionsForEntityFramework( Type type ) - { - var detailDescriptions = new List(); + private static List GetDataGridDetailDescriptions(PropertyDescriptorCollection properties) + { + var detailDescriptions = new List(properties.Count); - // Gets all the public properties of the type. - var propertyInfos = type.GetProperties( BindingFlags.Instance | BindingFlags.Public ); + foreach (PropertyDescriptor property in properties) + { + // We only create details for properties that are browsable. + if (!property.IsBrowsable) + continue; + + if (ItemsSourceHelper.IsASubRelationship(property.PropertyType)) + { + var description = new PropertyDetailDescription(property); + description.IsAutoCreated = true; + description.IsInitialized = true; + detailDescriptions.Add(description); + } + } - // Loop throught the properties to build up the detail descriptions. - foreach( var propertyInfo in propertyInfos ) - { - // We must use Reflection to check for the EntityFramework types. - var propertyType = propertyInfo.PropertyType; + return detailDescriptions; + } - // The property must be of type RelatedEnd and IEnumerable to continue. - if( ( propertyType.BaseType != null ) - && ( propertyType.BaseType.FullName == "System.Data.Objects.DataClasses.RelatedEnd" ) - && ( typeof( IEnumerable ).IsAssignableFrom( propertyType ) ) ) + private static bool IsEditableObjectInsertedOrRemovedFromDataSourceAutomatically(IEditableObject item) { - detailDescriptions.Add( new EntityDetailDescription( propertyInfo.Name ) ); + return (item is DataRowView) + || (item is DataRow); } - } - return detailDescriptions; - } + #region DataTablePropertyDescription Private Class - private static List CreateDetailDescriptionsForEnumerable() - { - var detailDescriptions = new List( 1 ); + private sealed class DataTablePropertyDescription : PropertyDescription + { + internal DataTablePropertyDescription(PropertyDescriptor propertyDescriptor, DataColumn column, IDictionary constraints, bool isDisplayable) + { + if (propertyDescriptor == null) + throw new ArgumentNullException("propertyDescriptor"); + + m_propertyDescriptor = propertyDescriptor; + m_column = column; + m_isDisplayable = isDisplayable; + + if (constraints != null) + { + ForeignKeyConstraint constraint; + if (constraints.TryGetValue(propertyDescriptor.Name, out constraint)) + { + m_foreignKeyDescription = ItemsSourceHelper.GetDataGridForeignKeyDescriptionForForeignKeyConstraint(constraint); + } + } + } - var description = new EnumerableDetailDescription(); - description.IsAutoCreated = true; - description.IsInitialized = true; - detailDescriptions.Add( description ); + internal override string Name + { + get + { + return m_propertyDescriptor.Name; + } + } - return detailDescriptions; - } + internal override string DisplayName + { + get + { + if (m_column != null) + return m_column.Caption; - private static List CreateDetailDescriptionsForListSource() - { - var detailDescriptions = new List( 1 ); + return m_propertyDescriptor.DisplayName; + } + } - var description = new ListSourceDetailDescription(); - description.IsAutoCreated = true; - description.IsInitialized = true; - detailDescriptions.Add( description ); + internal override Type DataType + { + get + { + return m_propertyDescriptor.PropertyType; + } + } - return detailDescriptions; - } + internal override PropertyDescriptor PropertyDescriptor + { + get + { + return m_propertyDescriptor; + } + } - private static List GetDataGridDetailDescriptions( PropertyDescriptorCollection properties ) - { - var detailDescriptions = new List( properties.Count ); + internal override bool IsReadOnly + { + get + { + return m_propertyDescriptor.IsReadOnly; + } + } - foreach( PropertyDescriptor property in properties ) - { - // We only create details for properties that are browsable. - if( !property.IsBrowsable ) - continue; + internal override bool SupportDBNull + { + get + { + return (m_column != null) + && (m_column.AllowDBNull); + } + } - if( ItemsSourceHelper.IsASubRelationship( property.PropertyType ) ) - { - var description = new PropertyDetailDescription( property ); - description.IsAutoCreated = true; - description.IsInitialized = true; - detailDescriptions.Add( description ); - } - } + internal override bool IsBrowsable + { + get + { + return m_propertyDescriptor.IsBrowsable; + } + } - return detailDescriptions; - } + internal override bool IsDisplayable + { + get + { + return m_isDisplayable; + } + } - private static bool IsEditableObjectInsertedOrRemovedFromDataSourceAutomatically( IEditableObject item ) - { - return ( item is DataRowView ) - || ( item is DataRow ); - } + internal override bool IsSubRelationship + { + get + { + return (m_column == null) + && (ItemsSourceHelper.IsASubRelationship(this.DataType)); + } + } - #region DataTablePropertyDescription Private Class + internal override DataGridForeignKeyDescription ForeignKeyDescription + { + get + { + return m_foreignKeyDescription; + } + } - private sealed class DataTablePropertyDescription : PropertyDescription - { - internal DataTablePropertyDescription( PropertyDescriptor propertyDescriptor, DataColumn column, IDictionary constraints, bool isDisplayable ) - { - if( propertyDescriptor == null ) - throw new ArgumentNullException( "propertyDescriptor" ); + public override int GetHashCode() + { + return m_propertyDescriptor.GetHashCode(); + } - m_propertyDescriptor = propertyDescriptor; - m_column = column; - m_isDisplayable = isDisplayable; + public override bool Equals(object obj) + { + var target = obj as DataTablePropertyDescription; + if (target == null) + return false; - if( constraints != null ) - { - ForeignKeyConstraint constraint; - if( constraints.TryGetValue( propertyDescriptor.Name, out constraint ) ) - { - m_foreignKeyDescription = ItemsSourceHelper.GetDataGridForeignKeyDescriptionForForeignKeyConstraint( constraint ); - } - } - } + return (object.Equals(target.m_propertyDescriptor, m_propertyDescriptor)) + && (object.Equals(target.m_column, m_column)); + } - internal override string Name - { - get - { - return m_propertyDescriptor.Name; + private readonly PropertyDescriptor m_propertyDescriptor; + private readonly DataColumn m_column; + private readonly bool m_isDisplayable; + private readonly DataGridForeignKeyDescription m_foreignKeyDescription; } - } - internal override string DisplayName - { - get - { - if( m_column != null ) - return m_column.Caption; + #endregion - return m_propertyDescriptor.DisplayName; - } - } + #region ItemPropertyPropertyDescription Private Class - internal override Type DataType - { - get + private sealed class ItemPropertyPropertyDescription : PropertyDescription { - return m_propertyDescriptor.PropertyType; - } - } - - internal override PropertyDescriptor PropertyDescriptor - { - get - { - return m_propertyDescriptor; - } - } + internal ItemPropertyPropertyDescription(DataGridItemPropertyBase itemProperty) + { + if (itemProperty == null) + throw new ArgumentNullException("itemProperty"); - internal override bool IsReadOnly - { - get - { - return m_propertyDescriptor.IsReadOnly; - } - } + m_itemProperty = itemProperty; + m_propertyDescriptor = itemProperty.GetPropertyDescriptorForBinding(); + Debug.Assert(m_propertyDescriptor != null); + } - internal override bool SupportDBNull - { - get - { - return ( m_column != null ) - && ( m_column.AllowDBNull ); - } - } + internal override string Name + { + get + { + return m_itemProperty.Name; + } + } - internal override bool IsBrowsable - { - get - { - return m_propertyDescriptor.IsBrowsable; - } - } + internal override string DisplayName + { + get + { + return m_propertyDescriptor.DisplayName; + } + } - internal override bool IsDisplayable - { - get - { - return m_isDisplayable; - } - } + internal override Type DataType + { + get + { + return m_propertyDescriptor.PropertyType; + } + } - internal override bool IsSubRelationship - { - get - { - return ( m_column == null ) - && ( ItemsSourceHelper.IsASubRelationship( this.DataType ) ); - } - } + internal override PropertyDescriptor PropertyDescriptor + { + get + { + return m_propertyDescriptor; + } + } - internal override DataGridForeignKeyDescription ForeignKeyDescription - { - get - { - return m_foreignKeyDescription; - } - } + internal override bool IsReadOnly + { + get + { + return m_propertyDescriptor.IsReadOnly; + } + } - public override int GetHashCode() - { - return m_propertyDescriptor.GetHashCode(); - } + internal override bool OverrideReadOnlyForInsertion + { + get + { + return m_itemProperty.OverrideReadOnlyForInsertion.GetValueOrDefault(false); + } + } - public override bool Equals( object obj ) - { - var target = obj as DataTablePropertyDescription; - if( target == null ) - return false; + internal override bool IsBrowsable + { + get + { + return m_propertyDescriptor.IsBrowsable; + } + } - return ( object.Equals( target.m_propertyDescriptor, m_propertyDescriptor ) ) - && ( object.Equals( target.m_column, m_column ) ); - } + internal override bool IsDisplayable + { + get + { + return m_itemProperty.IsDisplayable; + } + } - private readonly PropertyDescriptor m_propertyDescriptor; - private readonly DataColumn m_column; - private readonly bool m_isDisplayable; - private readonly DataGridForeignKeyDescription m_foreignKeyDescription; - } + internal override bool IsSubRelationship + { + get + { + return m_itemProperty.IsASubRelationship; + } + } - #endregion + internal override DataGridForeignKeyDescription ForeignKeyDescription + { + get + { + return m_itemProperty.ForeignKeyDescription; + } + } - #region ItemPropertyPropertyDescription Private Class + public override int GetHashCode() + { + return m_itemProperty.GetHashCode(); + } - private sealed class ItemPropertyPropertyDescription : PropertyDescription - { - internal ItemPropertyPropertyDescription( DataGridItemPropertyBase itemProperty ) - { - if( itemProperty == null ) - throw new ArgumentNullException( "itemProperty" ); + public override bool Equals(object obj) + { + var target = obj as ItemPropertyPropertyDescription; + if (target == null) + return false; - m_itemProperty = itemProperty; - m_propertyDescriptor = itemProperty.GetPropertyDescriptorForBinding(); - Debug.Assert( m_propertyDescriptor != null ); - } + return object.Equals(target.m_itemProperty, m_itemProperty); + } - internal override string Name - { - get - { - return m_itemProperty.Name; + private readonly DataGridItemPropertyBase m_itemProperty; + private readonly PropertyDescriptor m_propertyDescriptor; } - } - internal override string DisplayName - { - get - { - return m_propertyDescriptor.DisplayName; - } - } + #endregion - internal override Type DataType - { - get - { - return m_propertyDescriptor.PropertyType; - } - } + #region PropertyDescriptorPropertyDescription Private Class - internal override PropertyDescriptor PropertyDescriptor - { - get + private class PropertyDescriptorPropertyDescription : PropertyDescription { - return m_propertyDescriptor; - } - } + internal PropertyDescriptorPropertyDescription(PropertyDescriptor propertyDescriptor, bool supportDBNull, bool isDisplayable) + { + if (propertyDescriptor == null) + throw new ArgumentNullException("propertyDescriptor"); - internal override bool IsReadOnly - { - get - { - return m_propertyDescriptor.IsReadOnly; - } - } + m_propertyDescriptor = propertyDescriptor; + m_supportDBNull = supportDBNull; + m_isDisplayable = isDisplayable; + m_foreignKeyDescription = ItemsSourceHelper.GetDataGridForeignKeyDescriptionForEnum(propertyDescriptor.PropertyType); + } - internal override bool OverrideReadOnlyForInsertion - { - get - { - return m_itemProperty.OverrideReadOnlyForInsertion.GetValueOrDefault( false ); - } - } + internal override string Name + { + get + { + return m_propertyDescriptor.Name; + } + } - internal override bool IsBrowsable - { - get - { - return m_propertyDescriptor.IsBrowsable; - } - } + internal override string DisplayName + { + get + { + return m_propertyDescriptor.DisplayName; + } + } - internal override bool IsDisplayable - { - get - { - return m_itemProperty.IsDisplayable; - } - } + internal override Type DataType + { + get + { + return m_propertyDescriptor.PropertyType; + } + } - internal override bool IsSubRelationship - { - get - { - return m_itemProperty.IsASubRelationship; - } - } + internal override PropertyDescriptor PropertyDescriptor + { + get + { + return m_propertyDescriptor; + } + } - internal override DataGridForeignKeyDescription ForeignKeyDescription - { - get - { - return m_itemProperty.ForeignKeyDescription; - } - } + internal override bool IsReadOnly + { + get + { + return m_propertyDescriptor.IsReadOnly; + } + } - public override int GetHashCode() - { - return m_itemProperty.GetHashCode(); - } + internal override bool SupportDBNull + { + get + { + return m_supportDBNull; + } + } - public override bool Equals( object obj ) - { - var target = obj as ItemPropertyPropertyDescription; - if( target == null ) - return false; + internal override bool IsBrowsable + { + get + { + return m_propertyDescriptor.IsBrowsable; + } + } - return object.Equals( target.m_itemProperty, m_itemProperty ); - } + internal override bool IsDisplayable + { + get + { + return m_isDisplayable; + } + } - private readonly DataGridItemPropertyBase m_itemProperty; - private readonly PropertyDescriptor m_propertyDescriptor; - } + internal override bool IsSubRelationship + { + get + { + return ItemsSourceHelper.IsASubRelationship(this.DataType); + } + } - #endregion + internal override DataGridForeignKeyDescription ForeignKeyDescription + { + get + { + return m_foreignKeyDescription; + } + } - #region PropertyDescriptorPropertyDescription Private Class + public override int GetHashCode() + { + return m_propertyDescriptor.GetHashCode(); + } - private class PropertyDescriptorPropertyDescription : PropertyDescription - { - internal PropertyDescriptorPropertyDescription( PropertyDescriptor propertyDescriptor, bool supportDBNull, bool isDisplayable ) - { - if( propertyDescriptor == null ) - throw new ArgumentNullException( "propertyDescriptor" ); + public override bool Equals(object obj) + { + var target = obj as PropertyDescriptorPropertyDescription; + if (target == null) + return false; - m_propertyDescriptor = propertyDescriptor; - m_supportDBNull = supportDBNull; - m_isDisplayable = isDisplayable; - m_foreignKeyDescription = ItemsSourceHelper.GetDataGridForeignKeyDescriptionForEnum( propertyDescriptor.PropertyType ); - } + return (object.Equals(target.m_propertyDescriptor, m_propertyDescriptor)) + && (target.m_supportDBNull == m_supportDBNull); + } - internal override string Name - { - get - { - return m_propertyDescriptor.Name; + private readonly PropertyDescriptor m_propertyDescriptor; + private readonly bool m_supportDBNull; + private readonly bool m_isDisplayable; + private readonly DataGridForeignKeyDescription m_foreignKeyDescription; } - } - internal override string DisplayName - { - get - { - return m_propertyDescriptor.DisplayName; - } - } + #endregion - internal override Type DataType - { - get - { - return m_propertyDescriptor.PropertyType; - } - } + #region NamedPropertyDescriptorPropertyDescription Private Class - internal override PropertyDescriptor PropertyDescriptor - { - get + private sealed class NamedPropertyDescriptorPropertyDescription : PropertyDescriptorPropertyDescription { - return m_propertyDescriptor; - } - } + internal NamedPropertyDescriptorPropertyDescription(string name, PropertyDescriptor propertyDescriptor, bool supportDBNull, bool isDisplayable) + : base(propertyDescriptor, supportDBNull, isDisplayable) + { + if (name == null) + throw new ArgumentNullException("name"); - internal override bool IsReadOnly - { - get - { - return m_propertyDescriptor.IsReadOnly; - } - } + m_name = name; + } - internal override bool SupportDBNull - { - get - { - return m_supportDBNull; - } - } + internal override string Name + { + get + { + return m_name; + } + } - internal override bool IsBrowsable - { - get - { - return m_propertyDescriptor.IsBrowsable; - } - } + public override int GetHashCode() + { + return m_name.GetHashCode(); + } - internal override bool IsDisplayable - { - get - { - return m_isDisplayable; - } - } + public override bool Equals(object obj) + { + var target = obj as NamedPropertyDescriptorPropertyDescription; + if (target == null) + return false; - internal override bool IsSubRelationship - { - get - { - return ItemsSourceHelper.IsASubRelationship( this.DataType ); - } - } + return (target.m_name == m_name) + && (base.Equals(target)); + } - internal override DataGridForeignKeyDescription ForeignKeyDescription - { - get - { - return m_foreignKeyDescription; + private readonly string m_name; } - } - public override int GetHashCode() - { - return m_propertyDescriptor.GetHashCode(); - } + #endregion - public override bool Equals( object obj ) - { - var target = obj as PropertyDescriptorPropertyDescription; - if( target == null ) - return false; + #region IndexerDescriptorPropertyDescription Private Class - return ( object.Equals( target.m_propertyDescriptor, m_propertyDescriptor ) ) - && ( target.m_supportDBNull == m_supportDBNull ); - } - - private readonly PropertyDescriptor m_propertyDescriptor; - private readonly bool m_supportDBNull; - private readonly bool m_isDisplayable; - private readonly DataGridForeignKeyDescription m_foreignKeyDescription; - } - - #endregion + private class IndexerDescriptorPropertyDescription : PropertyDescriptorPropertyDescription + { + internal IndexerDescriptorPropertyDescription(DataItemIndexerDescriptor indexerDescriptor, bool supportDBNull, bool isDisplayable) + : base(indexerDescriptor, supportDBNull, isDisplayable) + { + } - #region NamedPropertyDescriptorPropertyDescription Private Class + public override int GetHashCode() + { + return base.GetHashCode(); + } - private sealed class NamedPropertyDescriptorPropertyDescription : PropertyDescriptorPropertyDescription - { - internal NamedPropertyDescriptorPropertyDescription( string name, PropertyDescriptor propertyDescriptor, bool supportDBNull, bool isDisplayable ) - : base( propertyDescriptor, supportDBNull, isDisplayable ) - { - if( name == null ) - throw new ArgumentNullException( "name" ); + public override bool Equals(object obj) + { + return (obj is IndexerDescriptorPropertyDescription) + && (base.Equals(obj)); + } - m_name = name; - } + internal override PropertyRouteSegment ToPropertyRouteSegment() + { + var descriptor = (DataItemIndexerDescriptor)this.PropertyDescriptor; - internal override string Name - { - get - { - return m_name; + return new PropertyRouteSegment(PropertyRouteSegmentType.Indexer, descriptor.IndexerParameters); + } } - } - public override int GetHashCode() - { - return m_name.GetHashCode(); - } + #endregion - public override bool Equals( object obj ) - { - var target = obj as NamedPropertyDescriptorPropertyDescription; - if( target == null ) - return false; + #region JaggedArrayPropertyDescription Private Class - return ( target.m_name == m_name ) - && ( base.Equals( target ) ); - } + private sealed class JaggedArrayPropertyDescription : PropertyDescription + { + internal JaggedArrayPropertyDescription(int index, Type dataType, bool isDisplayable) + { + if (index < 0) + throw new ArgumentException("index"); - private readonly string m_name; - } + if (dataType == null) + throw new ArgumentNullException("dataType"); - #endregion + m_name = ".[" + index.ToString(CultureInfo.InvariantCulture) + "]"; + m_dataType = dataType; + m_isDisplayable = isDisplayable; + m_propertyDescriptor = new JaggedArrayPropertyDescriptor(index, dataType); + m_foreignKeyDescription = ItemsSourceHelper.GetDataGridForeignKeyDescriptionForEnum(dataType); + } - #region IndexerDescriptorPropertyDescription Private Class + internal override string Name + { + get + { + return m_name; + } + } - private class IndexerDescriptorPropertyDescription : PropertyDescriptorPropertyDescription - { - internal IndexerDescriptorPropertyDescription( DataItemIndexerDescriptor indexerDescriptor, bool supportDBNull, bool isDisplayable ) - : base( indexerDescriptor, supportDBNull, isDisplayable ) - { - } - - public override int GetHashCode() - { - return base.GetHashCode(); - } - - public override bool Equals( object obj ) - { - return ( obj is IndexerDescriptorPropertyDescription ) - && ( base.Equals( obj ) ); - } - - internal override PropertyRouteSegment ToPropertyRouteSegment() - { - var descriptor = ( DataItemIndexerDescriptor )this.PropertyDescriptor; - - return new PropertyRouteSegment( PropertyRouteSegmentType.Indexer, descriptor.IndexerParameters ); - } - } + internal override string DisplayName + { + get + { + return m_name; + } + } - #endregion + internal override Type DataType + { + get + { + return m_dataType; + } + } - #region JaggedArrayPropertyDescription Private Class + internal override PropertyDescriptor PropertyDescriptor + { + get + { + return m_propertyDescriptor; + } + } - private sealed class JaggedArrayPropertyDescription : PropertyDescription - { - internal JaggedArrayPropertyDescription( int index, Type dataType, bool isDisplayable ) - { - if( index < 0 ) - throw new ArgumentException( "index" ); + internal override bool IsReadOnly + { + get + { + return false; + } + } - if( dataType == null ) - throw new ArgumentNullException( "dataType" ); + internal override bool IsDisplayable + { + get + { + return m_isDisplayable; + } + } - m_name = ".[" + index.ToString( CultureInfo.InvariantCulture ) + "]"; - m_dataType = dataType; - m_isDisplayable = isDisplayable; - m_propertyDescriptor = new JaggedArrayPropertyDescriptor( index, dataType ); - m_foreignKeyDescription = ItemsSourceHelper.GetDataGridForeignKeyDescriptionForEnum( dataType ); - } + internal override bool IsSubRelationship + { + get + { + return ItemsSourceHelper.IsASubRelationship(this.DataType); + } + } - internal override string Name - { - get - { - return m_name; - } - } + internal override DataGridForeignKeyDescription ForeignKeyDescription + { + get + { + return m_foreignKeyDescription; + } + } - internal override string DisplayName - { - get - { - return m_name; - } - } + public override int GetHashCode() + { + return m_name.GetHashCode(); + } - internal override Type DataType - { - get - { - return m_dataType; - } - } + public override bool Equals(object obj) + { + var target = obj as JaggedArrayPropertyDescription; + if (target == null) + return false; - internal override PropertyDescriptor PropertyDescriptor - { - get - { - return m_propertyDescriptor; - } - } + return (target.m_name == m_name) + && (target.m_dataType == m_dataType); + } - internal override bool IsReadOnly - { - get - { - return false; + private readonly string m_name; + private readonly Type m_dataType; + private readonly bool m_isDisplayable; + private readonly PropertyDescriptor m_propertyDescriptor; + private readonly DataGridForeignKeyDescription m_foreignKeyDescription; } - } - internal override bool IsDisplayable - { - get - { - return m_isDisplayable; - } - } + #endregion - internal override bool IsSubRelationship - { - get - { - return ItemsSourceHelper.IsASubRelationship( this.DataType ); - } - } + #region EntityFrameworkPropertyDescription Private Class - internal override DataGridForeignKeyDescription ForeignKeyDescription - { - get + private sealed class EntityFrameworkPropertyDescription : PropertyDescription { - return m_foreignKeyDescription; - } - } - - public override int GetHashCode() - { - return m_name.GetHashCode(); - } - - public override bool Equals( object obj ) - { - var target = obj as JaggedArrayPropertyDescription; - if( target == null ) - return false; + internal EntityFrameworkPropertyDescription(PropertyDescriptor propertyDescriptor, bool isDisplayable) + { + if (propertyDescriptor == null) + throw new ArgumentNullException("propertyDescriptor"); + + var attribute = propertyDescriptor.Attributes[typeof(EdmScalarPropertyAttribute)] as EdmScalarPropertyAttribute; + if (attribute != null) + { + m_isEntityKey = attribute.EntityKeyProperty; + m_supportDBNull = attribute.IsNullable; + } + else + { + m_isEntityKey = false; + m_supportDBNull = false; + } + + m_isDisplayable = isDisplayable; + m_propertyDescriptor = propertyDescriptor; + } - return ( target.m_name == m_name ) - && ( target.m_dataType == m_dataType ); - } + internal override string Name + { + get + { + return m_propertyDescriptor.Name; + } + } - private readonly string m_name; - private readonly Type m_dataType; - private readonly bool m_isDisplayable; - private readonly PropertyDescriptor m_propertyDescriptor; - private readonly DataGridForeignKeyDescription m_foreignKeyDescription; - } + internal override string DisplayName + { + get + { + return m_propertyDescriptor.DisplayName; + } + } - #endregion + internal override Type DataType + { + get + { + return m_propertyDescriptor.PropertyType; + } + } - #region EntityFrameworkPropertyDescription Private Class + internal override PropertyDescriptor PropertyDescriptor + { + get + { + return m_propertyDescriptor; + } + } - private sealed class EntityFrameworkPropertyDescription : PropertyDescription - { - internal EntityFrameworkPropertyDescription( PropertyDescriptor propertyDescriptor, bool isDisplayable ) - { - if( propertyDescriptor == null ) - throw new ArgumentNullException( "propertyDescriptor" ); + internal override bool IsReadOnly + { + get + { + return (m_isEntityKey) + || (m_propertyDescriptor.IsReadOnly); + } + } - var attribute = propertyDescriptor.Attributes[ typeof( EdmScalarPropertyAttribute ) ] as EdmScalarPropertyAttribute; - if( attribute != null ) - { - m_isEntityKey = attribute.EntityKeyProperty; - m_supportDBNull = attribute.IsNullable; - } - else - { - m_isEntityKey = false; - m_supportDBNull = false; - } + internal override bool OverrideReadOnlyForInsertion + { + get + { + return (m_isEntityKey) + && (!m_propertyDescriptor.IsReadOnly); + } + } - m_isDisplayable = isDisplayable; - m_propertyDescriptor = propertyDescriptor; - } + internal override bool SupportDBNull + { + get + { + return m_supportDBNull; + } + } - internal override string Name - { - get - { - return m_propertyDescriptor.Name; - } - } + internal override bool IsBrowsable + { + get + { + return m_propertyDescriptor.IsBrowsable; + } + } - internal override string DisplayName - { - get - { - return m_propertyDescriptor.DisplayName; - } - } + internal override bool IsDisplayable + { + get + { + return m_isDisplayable; + } + } - internal override Type DataType - { - get - { - return m_propertyDescriptor.PropertyType; - } - } + internal override bool IsSubRelationship + { + get + { + return ItemsSourceHelper.IsASubRelationship(this.DataType); + } + } - internal override PropertyDescriptor PropertyDescriptor - { - get - { - return m_propertyDescriptor; - } - } + public override int GetHashCode() + { + return m_propertyDescriptor.GetHashCode(); + } - internal override bool IsReadOnly - { - get - { - return ( m_isEntityKey ) - || ( m_propertyDescriptor.IsReadOnly ); - } - } + public override bool Equals(object obj) + { + var target = obj as EntityFrameworkPropertyDescription; + if (target == null) + return false; - internal override bool OverrideReadOnlyForInsertion - { - get - { - return ( m_isEntityKey ) - && ( !m_propertyDescriptor.IsReadOnly ); - } - } + return object.Equals(target.m_propertyDescriptor, m_propertyDescriptor); + } - internal override bool SupportDBNull - { - get - { - return m_supportDBNull; + private readonly PropertyDescriptor m_propertyDescriptor; + private readonly bool m_isEntityKey; + private readonly bool m_supportDBNull; + private readonly bool m_isDisplayable; } - } - internal override bool IsBrowsable - { - get - { - return m_propertyDescriptor.IsBrowsable; - } - } + #endregion - internal override bool IsDisplayable - { - get - { - return m_isDisplayable; - } - } + #region ValueTypePropertyDescription Private Class - internal override bool IsSubRelationship - { - get + private sealed class ValueTypePropertyDescription : PropertyDescription { - return ItemsSourceHelper.IsASubRelationship( this.DataType ); - } - } - - public override int GetHashCode() - { - return m_propertyDescriptor.GetHashCode(); - } - - public override bool Equals( object obj ) - { - var target = obj as EntityFrameworkPropertyDescription; - if( target == null ) - return false; + internal ValueTypePropertyDescription(Type dataType, bool supportDBNull, DataGridForeignKeyDescription foreignKeyDescription, bool isDisplayable) + { + if (dataType == null) + throw new ArgumentNullException("dataType"); - return object.Equals( target.m_propertyDescriptor, m_propertyDescriptor ); - } + m_dataType = dataType; + m_supportDBNull = supportDBNull; + m_isDisplayable = isDisplayable; + m_foreignKeyDescription = foreignKeyDescription; + } - private readonly PropertyDescriptor m_propertyDescriptor; - private readonly bool m_isEntityKey; - private readonly bool m_supportDBNull; - private readonly bool m_isDisplayable; - } + internal override string Name + { + get + { + return "."; + } + } - #endregion + internal override string DisplayName + { + get + { + return string.Empty; + } + } - #region ValueTypePropertyDescription Private Class + internal override Type DataType + { + get + { + return m_dataType; + } + } - private sealed class ValueTypePropertyDescription : PropertyDescription - { - internal ValueTypePropertyDescription( Type dataType, bool supportDBNull, DataGridForeignKeyDescription foreignKeyDescription, bool isDisplayable ) - { - if( dataType == null ) - throw new ArgumentNullException( "dataType" ); + internal override string Path + { + get + { + return this.Name; + } + } - m_dataType = dataType; - m_supportDBNull = supportDBNull; - m_isDisplayable = isDisplayable; - m_foreignKeyDescription = foreignKeyDescription; - } + internal override bool SupportDBNull + { + get + { + return m_supportDBNull; + } + } - internal override string Name - { - get - { - return "."; - } - } + internal override bool IsDisplayable + { + get + { + return m_isDisplayable; + } + } - internal override string DisplayName - { - get - { - return string.Empty; - } - } + internal override bool IsSubRelationship + { + get + { + return ItemsSourceHelper.IsASubRelationship(this.DataType); + } + } - internal override Type DataType - { - get - { - return m_dataType; - } - } + internal override DataGridForeignKeyDescription ForeignKeyDescription + { + get + { + return m_foreignKeyDescription; + } + } - internal override string Path - { - get - { - return this.Name; - } - } + public override int GetHashCode() + { + return m_dataType.GetHashCode(); + } - internal override bool SupportDBNull - { - get - { - return m_supportDBNull; - } - } + public override bool Equals(object obj) + { + var target = obj as ValueTypePropertyDescription; + if (target == null) + return false; - internal override bool IsDisplayable - { - get - { - return m_isDisplayable; - } - } + return (target.m_dataType == m_dataType); + } - internal override bool IsSubRelationship - { - get - { - return ItemsSourceHelper.IsASubRelationship( this.DataType ); - } - } + internal override PropertyRouteSegment ToPropertyRouteSegment() + { + return PropertyRouteSegment.Self; + } - internal override DataGridForeignKeyDescription ForeignKeyDescription - { - get - { - return m_foreignKeyDescription; + private readonly Type m_dataType; + private readonly bool m_supportDBNull; + private readonly bool m_isDisplayable; + private readonly DataGridForeignKeyDescription m_foreignKeyDescription; } - } - - public override int GetHashCode() - { - return m_dataType.GetHashCode(); - } - public override bool Equals( object obj ) - { - var target = obj as ValueTypePropertyDescription; - if( target == null ) - return false; - - return ( target.m_dataType == m_dataType ); - } - - internal override PropertyRouteSegment ToPropertyRouteSegment() - { - return PropertyRouteSegment.Self; - } - - private readonly Type m_dataType; - private readonly bool m_supportDBNull; - private readonly bool m_isDisplayable; - private readonly DataGridForeignKeyDescription m_foreignKeyDescription; + #endregion } - - #endregion - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Properties/AssemblyInfo.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Properties/AssemblyInfo.cs deleted file mode 100644 index f32c0d00..00000000 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,78 +0,0 @@ -/************************************************************************************* - - Extended WPF Toolkit - - Copyright (C) 2007-2013 Xceed Software Inc. - - This program is provided to you under the terms of the Microsoft Public - License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license - - For more features, controls, and fast professional support, - pick up the Plus Edition at http://xceed.com/wpf_toolkit - - Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids - - ***********************************************************************************/ - -#region Using directives - -using System; -using System.Globalization; -using System.Reflection; -using System.Resources; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Security; -using System.Windows; -using System.Windows.Markup; - -#endregion - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle( "Xceed Toolkit for WPF - DataGrid" )] -[assembly: AssemblyDescription( "This assembly implements the Xceed.Wpf.DataGrid namespace, a data grid control for the Windows Presentation Framework." )] - -[assembly: AssemblyCompany( "Xceed Software Inc." )] -[assembly: AssemblyProduct( "Xceed Toolkit for WPF - DataGrid" )] -[assembly: AssemblyCopyright( "Copyright (C) Xceed Software Inc. 2007-2017" )] - - -[assembly: CLSCompliant( true )] -[assembly: ComVisible( false )] - -[assembly: XmlnsPrefix( "http://schemas.xceed.com/wpf/xaml/datagrid", "xcdg" )] -[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid")] -[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.Converters")] -[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.Markup")] -[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.Views")] -[assembly: XmlnsDefinition( "http://schemas.xceed.com/wpf/xaml/datagrid", "Xceed.Wpf.DataGrid.ValidationRules")] - - -[assembly: SecurityRules( SecurityRuleSet.Level1 )] -[assembly: AllowPartiallyTrustedCallers] - -//In order to begin building localizable applications, set -//CultureYouAreCodingWith in your .csproj file -//inside a . For example, if you are using US english -//in your source files, set the to en-US. Then uncomment -//the NeutralResourceLanguage attribute below. Update the "en-US" in -//the line below to match the UICulture setting in the project file. - -//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] - -[assembly: ThemeInfo( - ResourceDictionaryLocation.SourceAssembly, //where theme specific resource dictionaries are located - //(used if a resource is not found in the page, - // or application resource dictionaries) - ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located - //(used if a resource is not found in the page, - // app, or any theme specific resource dictionaries) -)] - -#pragma warning disable 1699 -[assembly: AssemblyDelaySign( false )] -[assembly: AssemblyKeyFile( @"..\..\sn.snk" )] -[assembly: AssemblyKeyName( "" )] -#pragma warning restore 1699 diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Wpf/DragDrop/DragSourceManagerBase.cs b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Wpf/DragDrop/DragSourceManagerBase.cs index 3ae1951b..02522557 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Wpf/DragDrop/DragSourceManagerBase.cs +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Utils/Wpf/DragDrop/DragSourceManagerBase.cs @@ -30,681 +30,681 @@ using Xceed.Wpf.DataGrid; namespace Xceed.Utils.Wpf.DragDrop { - internal class DragSourceManagerBase : DependencyObject, INotifyPropertyChanged - { - internal DragSourceManagerBase( UIElement draggedElement, AdornerLayer adornerLayer, UIElement container ) - : this( draggedElement, adornerLayer, container, true ) + internal class DragSourceManagerBase : DependencyObject, INotifyPropertyChanged { - } - - internal DragSourceManagerBase( UIElement draggedElement, AdornerLayer adornerLayer, UIElement container, bool enableAutoScroll ) - : this( draggedElement, adornerLayer, container, enableAutoScroll, true ) - { - } - - internal DragSourceManagerBase( UIElement draggedElement, AdornerLayer adornerLayer, UIElement container, bool enableAutoScroll, bool showGhost ) - { - if( draggedElement == null ) - throw new ArgumentNullException( "draggedElement" ); - - if( container == null ) - throw new ArgumentNullException( "container" ); - - m_draggedElement = draggedElement; - m_container = container; - m_adornerLayer = ( adornerLayer != null ) ? adornerLayer : AdornerLayer.GetAdornerLayer( container ); - m_showGhost = showGhost; - - if( enableAutoScroll ) - { - var scrollViewer = DragSourceManagerBase.GetScrollViewer( draggedElement ); - if( scrollViewer != null ) + internal DragSourceManagerBase(UIElement draggedElement, AdornerLayer adornerLayer, UIElement container) + : this(draggedElement, adornerLayer, container, true) { - m_autoScrollManager = new AutoScrollManager( scrollViewer ); } - } - } - - #region IsDragging Property - internal bool IsDragging - { - get - { - return m_isDragging; - } - private set - { - if( value == m_isDragging ) - return; - - m_isDragging = value; - - this.OnPropertyChanged( "IsDragging" ); - } - } - - private bool m_isDragging; - - #endregion - - #region IsDragStarted Property + internal DragSourceManagerBase(UIElement draggedElement, AdornerLayer adornerLayer, UIElement container, bool enableAutoScroll) + : this(draggedElement, adornerLayer, container, enableAutoScroll, true) + { + } - internal bool IsDragStarted - { - get - { - return m_isDragStarted; - } - private set - { - if( value == m_isDragStarted ) - return; - - m_isDragStarted = value; - - this.OnPropertyChanged( "IsDragStarted" ); - } - } + internal DragSourceManagerBase(UIElement draggedElement, AdornerLayer adornerLayer, UIElement container, bool enableAutoScroll, bool showGhost) + { + if (draggedElement == null) + throw new ArgumentNullException("draggedElement"); + + if (container == null) + throw new ArgumentNullException("container"); + + m_draggedElement = draggedElement; + m_container = container; + m_adornerLayer = (adornerLayer != null) ? adornerLayer : AdornerLayer.GetAdornerLayer(container); + m_showGhost = showGhost; + + if (enableAutoScroll) + { + var scrollViewer = DragSourceManagerBase.GetScrollViewer(draggedElement); + if (scrollViewer != null) + { + m_autoScrollManager = new AutoScrollManager(scrollViewer); + } + } + } - private bool m_isDragStarted; + #region IsDragging Property - #endregion + internal bool IsDragging + { + get + { + return m_isDragging; + } + private set + { + if (value == m_isDragging) + return; + + m_isDragging = value; + + this.OnPropertyChanged("IsDragging"); + } + } - #region ShowGhost Property + private bool m_isDragging; - internal bool ShowGhost - { - get - { - return m_showGhost; - } - set - { - if( value == m_showGhost ) - return; - - m_showGhost = value; - - this.OnPropertyChanged( "ShowGhost" ); - } - } + #endregion - private bool m_showGhost; + #region IsDragStarted Property - #endregion + internal bool IsDragStarted + { + get + { + return m_isDragStarted; + } + private set + { + if (value == m_isDragStarted) + return; + + m_isDragStarted = value; + + this.OnPropertyChanged("IsDragStarted"); + } + } - #region AutoScrollInterval Property + private bool m_isDragStarted; - internal static readonly DependencyProperty AutoScrollIntervalProperty = DependencyProperty.Register( - "AutoScrollInterval", - typeof( TimeSpan ), - typeof( DragSourceManagerBase ), - new FrameworkPropertyMetadata( AutoScrollManager.AutoScrollInterval_DefaultValue, DragSourceManagerBase.OnAutoScrollIntervalChanged ) ); + #endregion - internal TimeSpan AutoScrollInterval - { - get - { - return ( TimeSpan )this.GetValue( DragSourceManagerBase.AutoScrollIntervalProperty ); - } - set - { - this.SetValue( DragSourceManagerBase.AutoScrollIntervalProperty, value ); - } - } + #region ShowGhost Property - private void OnAutoScrollIntervalChanged( TimeSpan oldValue, TimeSpan newValue ) - { - if( m_autoScrollManager == null ) - return; + internal bool ShowGhost + { + get + { + return m_showGhost; + } + set + { + if (value == m_showGhost) + return; + + m_showGhost = value; + + this.OnPropertyChanged("ShowGhost"); + } + } - m_autoScrollManager.AutoScrollInterval = newValue; - } + private bool m_showGhost; - private static void OnAutoScrollIntervalChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - var self = sender as DragSourceManagerBase; - if( self == null ) - return; + #endregion - self.OnAutoScrollIntervalChanged( ( TimeSpan )e.OldValue, ( TimeSpan )e.NewValue ); - } + #region AutoScrollInterval Property - #endregion + internal static readonly DependencyProperty AutoScrollIntervalProperty = DependencyProperty.Register( + "AutoScrollInterval", + typeof(TimeSpan), + typeof(DragSourceManagerBase), + new FrameworkPropertyMetadata(AutoScrollManager.AutoScrollInterval_DefaultValue, DragSourceManagerBase.OnAutoScrollIntervalChanged)); - #region AutoScrollThreshold Property + internal TimeSpan AutoScrollInterval + { + get + { + return (TimeSpan)this.GetValue(DragSourceManagerBase.AutoScrollIntervalProperty); + } + set + { + this.SetValue(DragSourceManagerBase.AutoScrollIntervalProperty, value); + } + } - public static readonly DependencyProperty AutoScrollThresholdProperty = DependencyProperty.Register( - "AutoScrollThreshold", - typeof( int ), - typeof( DragSourceManagerBase ), - new FrameworkPropertyMetadata( AutoScrollManager.AutoScrollThreshold_DefaultValue, DragSourceManagerBase.OnAutoScrollThresholdChanged ) ); + private void OnAutoScrollIntervalChanged(TimeSpan oldValue, TimeSpan newValue) + { + if (m_autoScrollManager == null) + return; - public int AutoScrollThreshold - { - get - { - return ( int )this.GetValue( DragSourceManagerBase.AutoScrollThresholdProperty ); - } - set - { - this.SetValue( DragSourceManagerBase.AutoScrollThresholdProperty, value ); - } - } + m_autoScrollManager.AutoScrollInterval = newValue; + } - private void OnAutoScrollThresholdChanged( int oldValue, int newValue ) - { - if( m_autoScrollManager == null ) - return; + private static void OnAutoScrollIntervalChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + var self = sender as DragSourceManagerBase; + if (self == null) + return; - m_autoScrollManager.AutoScrollThreshold = newValue; - } + self.OnAutoScrollIntervalChanged((TimeSpan)e.OldValue, (TimeSpan)e.NewValue); + } - private static void OnAutoScrollThresholdChanged( DependencyObject sender, DependencyPropertyChangedEventArgs e ) - { - var self = sender as DragSourceManagerBase; - if( self == null ) - return; + #endregion - self.OnAutoScrollThresholdChanged( ( int )e.OldValue, ( int )e.NewValue ); - } + #region AutoScrollThreshold Property - #endregion + public static readonly DependencyProperty AutoScrollThresholdProperty = DependencyProperty.Register( + "AutoScrollThreshold", + typeof(int), + typeof(DragSourceManagerBase), + new FrameworkPropertyMetadata(AutoScrollManager.AutoScrollThreshold_DefaultValue, DragSourceManagerBase.OnAutoScrollThresholdChanged)); - #region AdornerLayer Protected Property + public int AutoScrollThreshold + { + get + { + return (int)this.GetValue(DragSourceManagerBase.AutoScrollThresholdProperty); + } + set + { + this.SetValue(DragSourceManagerBase.AutoScrollThresholdProperty, value); + } + } - protected AdornerLayer AdornerLayer - { - get - { - return m_adornerLayer; - } - } + private void OnAutoScrollThresholdChanged(int oldValue, int newValue) + { + if (m_autoScrollManager == null) + return; - private readonly AdornerLayer m_adornerLayer; + m_autoScrollManager.AutoScrollThreshold = newValue; + } - #endregion + private static void OnAutoScrollThresholdChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) + { + var self = sender as DragSourceManagerBase; + if (self == null) + return; - #region DraggedElement Protected Property + self.OnAutoScrollThresholdChanged((int)e.OldValue, (int)e.NewValue); + } - protected UIElement DraggedElement - { - get - { - return m_draggedElement; - } - } + #endregion - private readonly UIElement m_draggedElement; + #region AdornerLayer Protected Property - #endregion + protected AdornerLayer AdornerLayer + { + get + { + return m_adornerLayer; + } + } - #region Container Protected Property + private readonly AdornerLayer m_adornerLayer; - protected UIElement Container - { - get - { - return m_container; - } - } + #endregion - private readonly UIElement m_container; + #region DraggedElement Protected Property - #endregion + protected UIElement DraggedElement + { + get + { + return m_draggedElement; + } + } - #region IsPopup Protected Property + private readonly UIElement m_draggedElement; - protected bool IsPopup - { - get - { - return m_isPopup; - } - } + #endregion - private bool m_isPopup; + #region Container Protected Property - #endregion + protected UIElement Container + { + get + { + return m_container; + } + } - #region InitialMousePositionToDraggedElement Protected Property + private readonly UIElement m_container; - protected Point? InitialMousePositionToDraggedElement - { - get - { - return m_initialMousePositionToDraggedElement; - } - } + #endregion - private Point? m_initialMousePositionToDraggedElement; + #region IsPopup Protected Property - #endregion + protected bool IsPopup + { + get + { + return m_isPopup; + } + } - #region InitialMousePositionToAdorner Protected Property + private bool m_isPopup; - protected Point? InitialMousePositionToAdorner - { - get - { - return m_initialMousePositionToAdorner; - } - } + #endregion - private Point? m_initialMousePositionToAdorner; + #region InitialMousePositionToDraggedElement Protected Property - #endregion + protected Point? InitialMousePositionToDraggedElement + { + get + { + return m_initialMousePositionToDraggedElement; + } + } - protected virtual void OnDragStart( Func getPosition ) - { - } + private Point? m_initialMousePositionToDraggedElement; - protected virtual void OnDragEnd( Func getPosition, bool drop ) - { - if( drop ) - { - this.OnDrop( getPosition ); - } - else - { - this.OnDragCancel( getPosition ); - } - } + #endregion - protected virtual void OnDragCancel( Func getPosition ) - { - } + #region InitialMousePositionToAdorner Protected Property - protected virtual void OnDragMove( Func getPosition ) - { - } + protected Point? InitialMousePositionToAdorner + { + get + { + return m_initialMousePositionToAdorner; + } + } - protected virtual void OnDrop( Func getPosition ) - { - } + private Point? m_initialMousePositionToAdorner; - protected virtual void UpdateGhost( Func getPosition ) - { - if( m_isPopup || ( m_draggedElementGhost == null ) ) - return; + #endregion - if( m_showGhost != m_draggedElementGhost.IsVisible ) - { - if( m_showGhost ) + protected virtual void OnDragStart(Func getPosition) { - m_draggedElementGhost.Show(); } - else + + protected virtual void OnDragEnd(Func getPosition, bool drop) { - m_draggedElementGhost.Hide(); + if (drop) + { + this.OnDrop(getPosition); + } + else + { + this.OnDragCancel(getPosition); + } } - } - //Find the new ghost position based on the current mouse position. - var mousePosition = getPosition.Invoke( m_container ); - var draggedElementPosition = Point.Subtract( mousePosition, m_draggedElementMouseOffset ); - - if( FrameworkElement.GetFlowDirection( m_container ) != FlowDirection.LeftToRight ) - { - draggedElementPosition.X += m_draggedElement.RenderSize.Width; - } - - var draggedElementPositionOnScreen = m_container.PointToScreen( draggedElementPosition ); - - // When Windows fonts are magnified (via the Control Panel), the position returned by PointToScreen doesn't match perfectly to the coordinate used - // to translate a Window object. We need to multiply the result by a zoom factor in order to place the Window at the mouse location. - var ghostPosition = new Point( draggedElementPositionOnScreen.X * m_mouseToScreenPositionFactor.X, - draggedElementPositionOnScreen.Y * m_mouseToScreenPositionFactor.Y ); - - m_draggedElementGhost.Left = ghostPosition.X; - m_draggedElementGhost.Top = ghostPosition.Y; - } + protected virtual void OnDragCancel(Func getPosition) + { + } - [Conditional( "DEBUG" )] - protected virtual void ValidateMouseEventArgs( MouseEventArgs e ) - { - } + protected virtual void OnDragMove(Func getPosition) + { + } - internal void DragStart( MouseEventArgs e ) - { - if( e.Handled || m_isDragStarted || m_isReentrant || ( e.LeftButton != MouseButtonState.Pressed ) ) - return; - - m_isReentrant = true; - - try - { - this.ValidateMouseEventArgs( e ); - this.DragStart( e.GetPosition ); - } - finally - { - m_isReentrant = false; - } - } + protected virtual void OnDrop(Func getPosition) + { + } - internal void DragCancel( MouseEventArgs e ) - { - if( e.Handled || !m_isDragStarted || m_isReentrant ) - return; - - m_isReentrant = true; - - try - { - this.ValidateMouseEventArgs( e ); - this.DragEnd( e.GetPosition, false ); - } - finally - { - m_isReentrant = false; - } - } + protected virtual void UpdateGhost(Func getPosition) + { + if (m_isPopup || (m_draggedElementGhost == null)) + return; + + if (m_showGhost != m_draggedElementGhost.IsVisible) + { + if (m_showGhost) + { + m_draggedElementGhost.Show(); + } + else + { + m_draggedElementGhost.Hide(); + } + } + + //Find the new ghost position based on the current mouse position. + var mousePosition = getPosition.Invoke(m_container); + var draggedElementPosition = Point.Subtract(mousePosition, m_draggedElementMouseOffset); + + if (FrameworkElement.GetFlowDirection(m_container) != FlowDirection.LeftToRight) + { + draggedElementPosition.X += m_draggedElement.RenderSize.Width; + } + + var draggedElementPositionOnScreen = m_container.PointToScreen(draggedElementPosition); + + // When Windows fonts are magnified (via the Control Panel), the position returned by PointToScreen doesn't match perfectly to the coordinate used + // to translate a Window object. We need to multiply the result by a zoom factor in order to place the Window at the mouse location. + var ghostPosition = new Point(draggedElementPositionOnScreen.X * m_mouseToScreenPositionFactor.X, + draggedElementPositionOnScreen.Y * m_mouseToScreenPositionFactor.Y); + + m_draggedElementGhost.Left = ghostPosition.X; + m_draggedElementGhost.Top = ghostPosition.Y; + } - internal void Drop( MouseEventArgs e ) - { - if( e.Handled || !m_isDragStarted || m_isReentrant ) - return; - - m_isReentrant = true; - - try - { - this.ValidateMouseEventArgs( e ); - this.DragEnd( e.GetPosition, true ); - } - finally - { - m_isReentrant = false; - } - } + [Conditional("DEBUG")] + protected virtual void ValidateMouseEventArgs(MouseEventArgs e) + { + } - internal void DragMove( MouseEventArgs e ) - { - this.DragMove( e, false ); - } + internal void DragStart(MouseEventArgs e) + { + if (e.Handled || m_isDragStarted || m_isReentrant || (e.LeftButton != MouseButtonState.Pressed)) + return; + + m_isReentrant = true; + + try + { + this.ValidateMouseEventArgs(e); + this.DragStart(e.GetPosition); + } + finally + { + m_isReentrant = false; + } + } - internal void DragMove( MouseEventArgs e, bool isCreatingCopy ) - { - if( e.Handled || !m_isDragStarted || m_isReentrant || ( e.LeftButton != MouseButtonState.Pressed ) ) - return; + internal void DragCancel(MouseEventArgs e) + { + if (e.Handled || !m_isDragStarted || m_isReentrant) + return; + + m_isReentrant = true; + + try + { + this.ValidateMouseEventArgs(e); + this.DragEnd(e.GetPosition, false); + } + finally + { + m_isReentrant = false; + } + } - m_isReentrant = true; + internal void Drop(MouseEventArgs e) + { + if (e.Handled || !m_isDragStarted || m_isReentrant) + return; + + m_isReentrant = true; + + try + { + this.ValidateMouseEventArgs(e); + this.DragEnd(e.GetPosition, true); + } + finally + { + m_isReentrant = false; + } + } - try - { - this.ValidateMouseEventArgs( e ); - this.DragMove( e.GetPosition, isCreatingCopy ); + internal void DragMove(MouseEventArgs e) + { + this.DragMove(e, false); + } - if( m_autoScrollManager != null ) + internal void DragMove(MouseEventArgs e, bool isCreatingCopy) { - m_autoScrollManager.HandleMouseMove( e ); + if (e.Handled || !m_isDragStarted || m_isReentrant || (e.LeftButton != MouseButtonState.Pressed)) + return; + + m_isReentrant = true; + + try + { + this.ValidateMouseEventArgs(e); + this.DragMove(e.GetPosition, isCreatingCopy); + + if (m_autoScrollManager != null) + { + m_autoScrollManager.HandleMouseMove(e); + } + } + finally + { + m_isReentrant = false; + } } - } - finally - { - m_isReentrant = false; - } - } - private static ScrollViewer GetScrollViewer( DependencyObject from ) - { - while( from != null ) - { - var scrollViewer = from as ScrollViewer; - if( scrollViewer != null ) - return scrollViewer; + private static ScrollViewer GetScrollViewer(DependencyObject from) + { + while (from != null) + { + var scrollViewer = from as ScrollViewer; + if (scrollViewer != null) + return scrollViewer; - from = VisualTreeHelper.GetParent( from ); - } + from = VisualTreeHelper.GetParent(from); + } - return null; - } + return null; + } - private static FrameworkElement GetPopupOrWindow( DependencyObject from ) - { - while( from != null ) - { - var popup = from as Popup; - if( popup != null ) - return popup; + private static FrameworkElement GetPopupOrWindow(DependencyObject from) + { + while (from != null) + { + var popup = from as Popup; + if (popup != null) + return popup; - var window = from as Window; - if( window != null ) - return window; + var window = from as Window; + if (window != null) + return window; - from = TreeHelper.GetParent( from ); - } + from = TreeHelper.GetParent(from); + } - return null; - } + return null; + } - private static DependencyObject GetPopupParent( DependencyObject from ) - { - while( from != null ) - { - var popup = from as Popup; - if( popup != null ) + private static DependencyObject GetPopupParent(DependencyObject from) { - var parent = popup.Parent; - if( parent != null ) - return parent; - - var target = popup.PlacementTarget; - if( target != null ) - return target; + while (from != null) + { + var popup = from as Popup; + if (popup != null) + { + var parent = popup.Parent; + if (parent != null) + return parent; + + var target = popup.PlacementTarget; + if (target != null) + return target; + } + + from = VisualTreeHelper.GetParent(from); + } + + return null; } - from = VisualTreeHelper.GetParent( from ); - } - - return null; - } - - private static Vector CalculateMouseToScreenPositionFactor( FrameworkElement element ) - { - if( element == null ) - return new Vector( 1d, 1d ); - - var source = PresentationSource.FromVisual( element ); - if( source == null ) - { - var parent = DragSourceManagerBase.GetPopupParent( element ); - while( parent != null ) + private static Vector CalculateMouseToScreenPositionFactor(FrameworkElement element) { - source = PresentationSource.FromDependencyObject( parent ); - if( source != null ) - break; - - parent = DragSourceManagerBase.GetPopupParent( parent ); + if (element == null) + return new Vector(1d, 1d); + + var source = PresentationSource.FromVisual(element); + if (source == null) + { + var parent = DragSourceManagerBase.GetPopupParent(element); + while (parent != null) + { + source = PresentationSource.FromDependencyObject(parent); + if (source != null) + break; + + parent = DragSourceManagerBase.GetPopupParent(parent); + } + } + + double x, y; + + if (source != null) + { + var deviceUnits = source.CompositionTarget.TransformToDevice; + x = deviceUnits.M11; + y = deviceUnits.M22; + } + else + { + using (var hwnd = new HwndSource(new HwndSourceParameters())) + { + var deviceUnits = hwnd.CompositionTarget.TransformToDevice; + x = deviceUnits.M11; + y = deviceUnits.M22; + } + } + + return new Vector((x == 0d) ? 1d : 1d / x, (y == 0d) ? 1d : 1d / y); } - } - - double x, y; - if( source != null ) - { - var deviceUnits = source.CompositionTarget.TransformToDevice; - x = deviceUnits.M11; - y = deviceUnits.M22; - } - else - { - using( var hwnd = new HwndSource( new HwndSourceParameters() ) ) + private static Window CreateDraggedElementGhost(UIElement element, bool isCreatingCopy) { - var deviceUnits = hwnd.CompositionTarget.TransformToDevice; - x = deviceUnits.M11; - y = deviceUnits.M22; + if (element == null) + return null; + + TileBrush brush = null; + + // Draw a copy of the element to make sure it won't be modified. + // Used in MergedColumnEditor when recycling is active while dragging a cell far away. + if (isCreatingCopy) + { + var drawingVisual = new DrawingVisual(); + using (var drawingContext = drawingVisual.RenderOpen()) + { + var visualBrush = new VisualBrush(element); + drawingContext.DrawRectangle(visualBrush, null, new Rect(new Point(), new Size(element.RenderSize.Width, element.RenderSize.Height))); + } + + float dpiX = 0f, dpiY = 0f; + //using( System.Drawing.Graphics graphics = System.Drawing.Graphics.FromHwnd( IntPtr.Zero ) ) + //{ + // dpiX = graphics.DpiX; + // dpiY = graphics.DpiY; + //} + var bitmapTarget = new RenderTargetBitmap((int)element.RenderSize.Width, (int)element.RenderSize.Height, dpiX, dpiY, PixelFormats.Default); + bitmapTarget.Render(drawingVisual); + brush = new ImageBrush(bitmapTarget); + } + else + { + brush = new VisualBrush(element); + } + + brush.Opacity = 0.75d; + brush.Stretch = Stretch.None; + brush.AlignmentX = AlignmentX.Left; + brush.AlignmentY = AlignmentY.Top; + + var rectangle = new Rectangle(); + rectangle.Width = element.DesiredSize.Width; + rectangle.Height = element.DesiredSize.Height; + rectangle.Fill = brush; + + var window = new Window(); + window.Topmost = true; + window.WindowStyle = WindowStyle.None; + window.AllowsTransparency = true; + window.Background = null; + window.SizeToContent = SizeToContent.WidthAndHeight; + window.ShowInTaskbar = false; + window.IsHitTestVisible = false; + window.ShowActivated = false; + window.Focusable = false; + window.Left = 0; + window.Top = 0; + window.Content = rectangle; + + //This will make sure the window follows what has been set on the parent grid. + var dataGridContext = DataGridControl.GetDataGridContext(element); + if (dataGridContext != null) + { + window.FlowDirection = dataGridContext.DataGridControl.FlowDirection; + } + + return window; } - } - return new Vector( ( x == 0d ) ? 1d : 1d / x, ( y == 0d ) ? 1d : 1d / y ); - } - - private static Window CreateDraggedElementGhost( UIElement element, bool isCreatingCopy ) - { - if( element == null ) - return null; - - TileBrush brush = null; - - // Draw a copy of the element to make sure it won't be modified. - // Used in MergedColumnEditor when recycling is active while dragging a cell far away. - if( isCreatingCopy ) - { - var drawingVisual = new DrawingVisual(); - using( var drawingContext = drawingVisual.RenderOpen() ) - { - var visualBrush = new VisualBrush( element ); - drawingContext.DrawRectangle( visualBrush, null, new Rect( new Point(), new Size( element.RenderSize.Width, element.RenderSize.Height ) ) ); - } - - float dpiX, dpiY; - using( System.Drawing.Graphics graphics = System.Drawing.Graphics.FromHwnd( IntPtr.Zero ) ) - { - dpiX = graphics.DpiX; - dpiY = graphics.DpiY; - } - var bitmapTarget = new RenderTargetBitmap( (int)element.RenderSize.Width, (int)element.RenderSize.Height, dpiX, dpiY, PixelFormats.Default ); - bitmapTarget.Render( drawingVisual ); - brush = new ImageBrush( bitmapTarget ); - } - else - { - brush = new VisualBrush( element ); - } - - brush.Opacity = 0.75d; - brush.Stretch = Stretch.None; - brush.AlignmentX = AlignmentX.Left; - brush.AlignmentY = AlignmentY.Top; - - var rectangle = new Rectangle(); - rectangle.Width = element.DesiredSize.Width; - rectangle.Height = element.DesiredSize.Height; - rectangle.Fill = brush; - - var window = new Window(); - window.Topmost = true; - window.WindowStyle = WindowStyle.None; - window.AllowsTransparency = true; - window.Background = null; - window.SizeToContent = SizeToContent.WidthAndHeight; - window.ShowInTaskbar = false; - window.IsHitTestVisible = false; - window.ShowActivated = false; - window.Focusable = false; - window.Left = 0; - window.Top = 0; - window.Content = rectangle; - - //This will make sure the window follows what has been set on the parent grid. - var dataGridContext = DataGridControl.GetDataGridContext( element ); - if( dataGridContext != null ) - { - window.FlowDirection = dataGridContext.DataGridControl.FlowDirection; - } - - return window; - } + private void DragStart(Func getPosition) + { + var parent = DragSourceManagerBase.GetPopupOrWindow(m_draggedElement); + var draggedElementPosition = getPosition.Invoke(m_draggedElement); - private void DragStart( Func getPosition ) - { - var parent = DragSourceManagerBase.GetPopupOrWindow( m_draggedElement ); - var draggedElementPosition = getPosition.Invoke( m_draggedElement ); + m_isPopup = (parent is Popup); + m_initialMousePositionToAdorner = (m_adornerLayer != null) ? getPosition.Invoke(m_adornerLayer) : default(Point?); + m_initialMousePositionToDraggedElement = draggedElementPosition; + m_mouseToScreenPositionFactor = DragSourceManagerBase.CalculateMouseToScreenPositionFactor(parent); + m_draggedElementMouseOffset = new Vector(draggedElementPosition.X, draggedElementPosition.Y); - m_isPopup = ( parent is Popup ); - m_initialMousePositionToAdorner = ( m_adornerLayer != null ) ? getPosition.Invoke( m_adornerLayer ) : default( Point? ); - m_initialMousePositionToDraggedElement = draggedElementPosition; - m_mouseToScreenPositionFactor = DragSourceManagerBase.CalculateMouseToScreenPositionFactor( parent ); - m_draggedElementMouseOffset = new Vector( draggedElementPosition.X, draggedElementPosition.Y ); + if (m_autoScrollManager != null) + { + m_autoScrollManager.Start(); + } - if( m_autoScrollManager != null ) - { - m_autoScrollManager.Start(); - } + this.IsDragStarted = true; + } - this.IsDragStarted = true; - } + private void DragEnd(Func getPosition, bool drop) + { + if (m_isDragging) + { + this.OnDragEnd(getPosition, drop); + this.IsDragging = false; + } + + if (m_draggedElementGhost != null) + { + m_draggedElementGhost.Hide(); + m_draggedElementGhost.Content = null; + m_draggedElementGhost.Close(); + m_draggedElementGhost = null; + } + + if (m_autoScrollManager != null) + { + m_autoScrollManager.Stop(); + } + + m_initialMousePositionToAdorner = default(Point?); + m_initialMousePositionToDraggedElement = default(Point?); + + this.IsDragStarted = false; + } - private void DragEnd( Func getPosition, bool drop ) - { - if( m_isDragging ) - { - this.OnDragEnd( getPosition, drop ); - this.IsDragging = false; - } - - if( m_draggedElementGhost != null ) - { - m_draggedElementGhost.Hide(); - m_draggedElementGhost.Content = null; - m_draggedElementGhost.Close(); - m_draggedElementGhost = null; - } - - if( m_autoScrollManager != null ) - { - m_autoScrollManager.Stop(); - } - - m_initialMousePositionToAdorner = default( Point? ); - m_initialMousePositionToDraggedElement = default( Point? ); - - this.IsDragStarted = false; - } + private void DragMove(Func getPosition, bool isCreatingCopy) + { + if (!m_initialMousePositionToAdorner.HasValue) + return; + + if (!m_isDragging) + { + var position = getPosition.Invoke(m_adornerLayer); + + if (DragDropHelper.IsMouseMoveDrag(m_initialMousePositionToAdorner.Value, position)) + { + m_draggedElementGhost = DragSourceManagerBase.CreateDraggedElementGhost(m_draggedElement, isCreatingCopy); + + this.OnDragStart(getPosition); + this.IsDragging = true; + } + } + + if (m_isDragging) + { + this.OnDragMove(getPosition); + this.UpdateGhost(getPosition); + } + } - private void DragMove( Func getPosition, bool isCreatingCopy ) - { - if( !m_initialMousePositionToAdorner.HasValue ) - return; + #region INotifyPropertyChanged Members - if( !m_isDragging ) - { - var position = getPosition.Invoke( m_adornerLayer ); + public event PropertyChangedEventHandler PropertyChanged; - if( DragDropHelper.IsMouseMoveDrag( m_initialMousePositionToAdorner.Value, position ) ) + protected virtual void OnPropertyChanged(string propertyName) { - m_draggedElementGhost = DragSourceManagerBase.CreateDraggedElementGhost( m_draggedElement, isCreatingCopy ); + var handler = this.PropertyChanged; + if (handler == null) + return; - this.OnDragStart( getPosition ); - this.IsDragging = true; + handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); } - } - if( m_isDragging ) - { - this.OnDragMove( getPosition ); - this.UpdateGhost( getPosition ); - } - } - - #region INotifyPropertyChanged Members - - public event PropertyChangedEventHandler PropertyChanged; - - protected virtual void OnPropertyChanged( string propertyName ) - { - var handler = this.PropertyChanged; - if( handler == null ) - return; + protected sealed override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) + { + base.OnPropertyChanged(e); + this.OnPropertyChanged(e.Property.Name); + } - handler.Invoke( this, new PropertyChangedEventArgs( propertyName ) ); - } + #endregion - protected sealed override void OnPropertyChanged( DependencyPropertyChangedEventArgs e ) - { - base.OnPropertyChanged( e ); - this.OnPropertyChanged( e.Property.Name ); + private readonly AutoScrollManager m_autoScrollManager; + private Window m_draggedElementGhost; //null + private Vector m_mouseToScreenPositionFactor = new Vector(1d, 1d); + private Vector m_draggedElementMouseOffset; + private bool m_isReentrant; //false } - - #endregion - - private readonly AutoScrollManager m_autoScrollManager; - private Window m_draggedElementGhost; //null - private Vector m_mouseToScreenPositionFactor = new Vector( 1d, 1d ); - private Vector m_draggedElementMouseOffset; - private bool m_isReentrant; //false - } } diff --git a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Xceed.Wpf.DataGrid.csproj b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Xceed.Wpf.DataGrid.csproj index 74743f09..fd0a9e87 100644 --- a/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Xceed.Wpf.DataGrid.csproj +++ b/ExtendedWPFToolkitSolution/Src/Xceed.Wpf.DataGrid/Xceed.Wpf.DataGrid.csproj @@ -1,1071 +1,113 @@ - - - - Debug - AnyCPU - {63648392-6CE9-4A60-96D4-F9FD718D29B0} - {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Xceed.Wpf.DataGrid - Xceed.Wpf.DataGrid - 4 - library - - v4.0 - - - 3.5 - - - false - Client - false - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - true - full - false - .\bin\Debug\ - TRACE;DEBUG;XBAP_FRIENDLY - - - 1699 - 125829120 - AllRules.ruleset - prompt - - - true - true - .\bin\Release\ - TRACE;CODE_ANALYSIS;XBAP_FRIENDLY - - - 1699 - false - - - 125829120 - AllRules.ruleset - prompt - pdbonly - - - - - - - - - 3.5 - - - - 3.5 - - - - - - - 3.0 - - - 3.0 - - - 3.0 - - - 3.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CustomItemContainerGenerator.cs - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - DataGridControlBackgroundBrushesResources.xaml - - - - - - - - - - - - - - - - - - - - Code - - - Code - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Code - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - MSBuild:Compile - Designer - - - Designer - MSBuild:Compile - MSBuild:Compile - Designer - - - - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 Client Profile - false - - - False - .NET Framework 3.5 SP1 - false - - - False - Microsoft Visual Basic PowerPacks 10.0 - true - - - False - Windows Installer 3.1 - true - - - - - {72e591d6-8f83-4d8c-8f67-9c325e623234} - Xceed.Wpf.Toolkit - - - - - - - - - - - - - - - + + + net8.0-windows + Library + false + + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + true + false + true + true + disable + + + .\bin\Debug\ + TRACE;DEBUG;XBAP_FRIENDLY + + + 1699 + 125829120 + AllRules.ruleset + + + true + .\bin\Release\ + TRACE;CODE_ANALYSIS;XBAP_FRIENDLY + + + 1699 + false + + + 125829120 + AllRules.ruleset + + + + 3.5 + + + 3.0 + + + + + + + + + + + False + Microsoft .NET Framework 4 %28x86 and x64%29 + true + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + False + Microsoft Visual Basic PowerPacks 10.0 + true + + + False + Windows Installer 3.1 + true + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ExtendedWPFToolkitSolution/Xceed.Wpf.Toolkit.sln b/ExtendedWPFToolkitSolution/Xceed.Wpf.Toolkit.sln index fe9bc896..c6f8a6e9 100644 --- a/ExtendedWPFToolkitSolution/Xceed.Wpf.Toolkit.sln +++ b/ExtendedWPFToolkitSolution/Xceed.Wpf.Toolkit.sln @@ -5,7 +5,7 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xceed.Wpf.Toolkit.LiveExplo EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xceed.Wpf.Toolkit", "Src\Xceed.Wpf.Toolkit\Xceed.Wpf.Toolkit.csproj", "{72E591D6-8F83-4D8C-8F67-9C325E623234}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xceed.Wpf.DataGrid", "Src\Xceed.Wpf.DataGrid\Xceed.Wpf.DataGrid.csproj", "{63648392-6CE9-4A60-96D4-F9FD718D29B0}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xceed.Wpf.DataGrid", "Src\Xceed.Wpf.DataGrid\Xceed.Wpf.DataGrid.csproj", "{63648392-6CE9-4A60-96D4-F9FD718D29B0}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Xceed.Wpf.AvalonDock", "Src\Xceed.Wpf.AvalonDock\Xceed.Wpf.AvalonDock.csproj", "{DB81988F-E0F2-45A0-A1FD-8C37F3D35244}" EndProject