2016-10-31 16 views
1

나는 일종의 그룹화 기능이 켜져있을 때 WPF DataGrid 정렬을 해제하는 방법?

MyCollectionViewSource.GroupDescriptions.Add(new PropertyGroupDescription("Table")); 

뷰 모델

에서의 그룹화 (ItemsSource는 CollectionViewSource에 바인딩) 및 턴 데이터 그리드에서 한 열이 나는 예외를 얻을 경우 : 명령 핸들러 'GroupDataGrid'시스템에

처리되지 않은 예외. InvalidOperationException : 배열의 두 요소를 비교하지 못했습니다. ---> System.ArgumentException : 적어도 하나의 개체 IComparable 구현해야합니다.

는 그러나 GroupDescription을 추가하기 전에 나는 정렬을 제거하려고 :

MyCollectionViewSource.SortDescriptions.Clear(); 

이 충분하지 않습니다 어떤 이유. 스택 추적 :

at System.Collections.Comparer.Compare(Object a, Object b) 
    at MS.Internal.Data.SortFieldComparer.Compare(Object o1, Object o2) 
    at System.Array.SorterGenericArray.SwapIfGreaterWithItems(Int32 a, Int32 b) 
    at System.Array.SorterGenericArray.PickPivotAndPartition(Int32 lo, Int32 hi) 
    at System.Array.SorterGenericArray.IntroSort(Int32 lo, Int32 hi, Int32 depthLimit) 
    at System.Array.SorterGenericArray.IntrospectiveSort(Int32 left, Int32 length) 
    --- End of inner exception stack trace --- 
    at System.Array.SorterGenericArray.IntrospectiveSort(Int32 left, Int32 length) 
    at System.Array.Sort(Array keys, Array items, Int32 index, Int32 length, IComparer comparer) 
    at System.Array.Sort(Array array, IComparer comparer) 
    at MS.Internal.Data.SortFieldComparer.SortHelper(ArrayList al, IComparer comparer) 
    at MS.Internal.Data.DataExtensionMethods.Sort(IList list, IComparer comparer) 
    at System.Windows.Data.ListCollectionView.PrepareLocalArray() 
    at System.Windows.Data.ListCollectionView.RefreshOverride() 
    at System.Windows.Data.CollectionView.RefreshInternal() 
    at System.Windows.Data.CollectionView.RefreshOrDefer() 
    at System.Windows.Data.ListCollectionView.SortDescriptionsChanged(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.ComponentModel.SortDescriptionCollection.OnCollectionChanged(NotifyCollectionChangedAction action, Object item, Int32 index) 
    at System.ComponentModel.SortDescriptionCollection.InsertItem(Int32 index, SortDescription item) 
    at System.Collections.ObjectModel.Collection`1.Insert(Int32 index, T item) 
    at System.Windows.Controls.ItemCollection.SynchronizeCollections[T](NotifyCollectionChangedEventArgs e, Collection`1 origin, Collection`1 clone) 
    at System.Windows.Controls.ItemCollection.SortDescriptionsChanged(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.ComponentModel.SortDescriptionCollection.OnCollectionChanged(NotifyCollectionChangedAction action, Object item, Int32 index) 
    at System.ComponentModel.SortDescriptionCollection.InsertItem(Int32 index, SortDescription item) 
    at System.Collections.ObjectModel.Collection`1.Insert(Int32 index, T item) 
    at System.Windows.Controls.DataGrid.AddGroupingSortDescriptions() 
    at System.Windows.Controls.DataGrid.OnItemsGroupDescriptionsChanged(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    at System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item) 
    at System.Collections.ObjectModel.Collection`1.Insert(Int32 index, T item) 
    at System.Windows.Controls.ItemCollection.SynchronizeCollections[T](NotifyCollectionChangedEventArgs e, Collection`1 origin, Collection`1 clone) 
    at System.Windows.Controls.ItemCollection.OnInnerGroupDescriptionsChanged(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Windows.WeakEventManager.ListenerList`1.DeliverEvent(Object sender, EventArgs e, Type managerType) 
    at System.Windows.WeakEventManager.DeliverEvent(Object sender, EventArgs args) 
    at System.Collections.Specialized.CollectionChangedEventManager.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 
    at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChange(NotifyCollectionChangedEventArgs e) 
    at System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item) 
    at System.Collections.ObjectModel.Collection`1.Add(T item) 

EDIT : reaquest가 추가 한 코드. BindingSource/ViewModel 클래스의 SetValue는 PropertyChanged 이벤트를 발생시킵니다. 행

클래스 :

public class SelectedNetObjectBindingSource : NetObjectBindingSource 
{ 
    public SelectedObjectsTableGroupBindingSource Table { get; set; } 

    public SelectedNetObjectBindingSource(NetObject netObject, SelectedObjectsTableGroupBindingSource table) 
     : base(netObject) 
    { 
     Table = table; 
    } 
} 

부모 클래스 : groupheader에 대한

public class NetObjectBindingSource : BindingSource 
{ 
    public NetObject Data { get; protected set; } 

    public NetObjectBindingSource(NetObject netObject) 
    { 
     Data = netObject; 
    } 
} 

클래스 :

public class SelectedObjectsTableGroupBindingSource : GroupHeaderBindingSource 
{ 
    public NetObjectTableId TableId { get; private set; } 

    public SelectedObjectsTableGroupBindingSource(NisTable nisTable, GroupHeadersInfo headersInfo) 
     : base(nisTable.TableId.ToString(), nisTable.Description, headersInfo) 
    { 
     TableId = nisTable.TableId; 
    } 
} 

그것의 부모 클래스 :

public class GroupHeaderBindingSource : BindingSource, IGroupHeader, IComparable 
{ 
    public string Name { get; private set; } 
    public string Description { get; private set; } 
    public int GroupedCount { get; set; } 

    private GroupHeadersInfo _headersInfo; 

    private bool _isExpanded; 
    public bool IsExpanded 
    { 
     get { return _isExpanded; } 
     set 
     { 
      if (SetValue(ref _isExpanded, value)) 
      { 
       NisDllInterface.SetUserSetting(_headersInfo.GroupSection, Name, value ? "True" : "False"); 
       _headersInfo.UpdateExpandedInfo(value); 
      } 
     } 
    } 

    public GroupHeaderBindingSource(string name, string description, GroupHeadersInfo headersInfo) 
    { 
     _headersInfo = headersInfo; 
     Name = name; 
     Description = description; 
     var value = UserSettings.Instance.GetSetting(headersInfo.GroupSection, Name); 
     if (value != null) 
     { 
      if (value.Equals("False")) 
      { 
       IsExpanded = false; 
      } 
      else 
      { 
       IsExpanded = true; 
      } 
     } 
     else 
     { 
      IsExpanded = true;  
     } 
    } 

    public int CompareTo(object obj) 
    { 
     if (obj != null && obj is GroupHeaderBindingSource) 
     { 
      var groupHeader = (GroupHeaderBindingSource) obj; 
      return Description.CompareTo(groupHeader.Description); 
     } 
     return 0; 
    } 
} 
,536,913,632 10

뷰 모델 :

public ICollectionView SelectedObjectItems 
    { 
     get 
     { 
      return _selectedObjectsView; 
     } 
     set 
     { 
      this.SetValue(ref _selectedObjectsView, value); 
     } 
    } 


    public bool AreSelectedObjectsGroupedByTable 
    { 
     get 
     { 
      return _areSelectedObjectsGroupedByTable; 
     } 
     set 
     { 
      this.SetValue(ref _areSelectedObjectsGroupedByTable, value); 
      if (_areSelectedObjectsGroupedByTable) 
       SelectedObjectItems.GroupDescriptions.Add(new PropertyGroupDescription("Table")); 
      else 
       SelectedObjectItems.GroupDescriptions.Clear(); 

      SaveObjectsSetting(GroupedSettingName, _areSelectedObjectsGroupedByTable ? "True" : "False"); 
      SelectedObjectsGroupHeaders.IsGrouped = value; 
      SelectedObjectItems.Refresh(); 
      CallAfterSelectedObjectsRefresh(new GroupedRowsRefreshedEventArgs(
       _areSelectedObjectsGroupedByTable ? GroupedGrid.Grouped : GroupedGrid.Ungrouped)); 
     } 
    } 

// in viewmodel constructor 
SelectedObjectItems = CollectionViewSource.GetDefaultView(new List<NetObject>()); 


    public void RefreshSelection() 
    { 
     RefreshSelectionObjects(); 
     Selection = GetSelectedObjects(); 

     // Selected objects 
     if (SelectedObjectsExpanded) 
     { 
      IsFetchObjectsAnywayVisible = false; 
      bool isTooManyObjects = SelectedObjectsInstance.Count > MaxSelectedObjectCount; 
      if (isTooManyObjects && !_fetchObjectsAnyway) 
      { 
       SelectedObjectsInfoPanelText = App.Current.Resources["MmsMsgTooManyObjectsSelectd"].ToString(); 
       SelectedObjectItems = CollectionViewSource.GetDefaultView(new List<NetObject>()); 
       ShowSelectedObjectsInfoPanel = true; 
       IsFetchObjectsAnywayVisible = true; 
      } 
      else if (SelectedObjectsInstance.Count == 0) 
      { 
       SelectedObjectsInfoPanelText = App.Current.Resources["NisStrNoObjectsSelected"].ToString(); 
       SelectedObjectItems = CollectionViewSource.GetDefaultView(new List<NetObject>()); 
       ShowSelectedObjectsInfoPanel = true; 
      } 
      else 
      { 
       SelectedObjectItems = CollectionViewSource.GetDefaultView(GetSelectedObjects().ToList()); 
       if (_areSelectedObjectsGroupedByTable) 
        SelectedObjectItems.GroupDescriptions.Add(new PropertyGroupDescription("Table")); 
       else 
        SelectedObjectItems.GroupDescriptions.Clear(); 
       ShowSelectedObjectsInfoPanel = false; 
      } 
      _selectedObjectsRefreshSkipped = false; 
     } 
     else 
     { 
      _selectedObjectsRefreshSkipped = true; 
     } 
    } 

XAML

:

public class NetObject : IComparable 
{ 
    // Your Items implementation .... 

    public int CompareProperty { get; set; } 

    public int CompareTo(object obj) 
    { 
     if(!(obj is NetObject)) throw new Exception("The Object can't been compared"); 

     if (this.CompareProperty > ((NetObject)obj).CompareProperty) return 1; 
     if (this.CompareProperty < ((NetObject)obj).CompareProperty) return -1; 
     return 0; 
    } 
} 

CompareTo는 각각에 집중할 수 :

  <DataGrid Name="SelectedObjectsGrid" 
         Visibility="{Binding ShowSelectedObjectsInfoPanel, Converter={StaticResource ReverseBoolToVisibilityConverter}}" 
         ItemsSource="{Binding SelectedObjectItems}" 
         SelectionMode="Extended" 
         CanUserAddRows="False" 
         AutoGenerateColumns="False" 
         VirtualizingPanel.IsVirtualizing="True" 
         VirtualizingPanel.IsVirtualizingWhenGrouping="True" 
         VirtualizingPanel.VirtualizationMode="Standard" 
         IsReadOnly="True" 
         Grid.Row="0" Margin="0,0,4,0"> 
       <DataGrid.Resources> 
        <ContextMenu x:Key="SelectedObjectRowContextMenu" 
     DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> 
         <MenuItem Header="{DynamicResource XpStrKeepSelectionTableShort}" Command="{ui:CommandHandler KeepTable}" CommandParameter="{Binding}"/> 
         <MenuItem Header="{DynamicResource XpStrRemoveSelectionTableShort}" Command="{ui:CommandHandler RemoveTable}" CommandParameter="{Binding}"/> 
         <MenuItem Header="{DynamicResource XpStrList}" Command="{ui:CommandHandler ToggleSelectedObjectsGrouping}" CommandParameter="False" 
            Visibility="{Binding DataContext.AreSelectedObjectsGroupedByTable, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}" > 
          <MenuItem.Icon> 
           <Image> 
            <Image.Source> 
             <DrawingImage> 
              <DrawingImage.Drawing> 
               <GeometryDrawing Brush="Black" 
                   Geometry="{Binding DataContext.AreSelectedObjectsGroupedByTable, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource ReverseBoolToGeometryConverter}}" /> 
              </DrawingImage.Drawing> 
             </DrawingImage> 
            </Image.Source> 
           </Image> 
          </MenuItem.Icon> 
         </MenuItem> 
         <MenuItem Header="{DynamicResource XpStrGroup}" Command="{ui:CommandHandler ToggleSelectedObjectsGrouping}" CommandParameter="True" 
            Visibility="{Binding DataContext.AreSelectedObjectsGroupedByTable, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource ReverseBoolToVisibilityConverter}}" > 
           <MenuItem.Icon> 
           <Image> 
            <Image.Source> 
             <DrawingImage> 
              <DrawingImage.Drawing> 
               <GeometryDrawing Brush="Black" 
                   Geometry="{Binding DataContext.AreSelectedObjectsGroupedByTable, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToGeometryConverter}}" /> 
              </DrawingImage.Drawing> 
             </DrawingImage> 
            </Image.Source> 
           </Image> 
          </MenuItem.Icon> 
         </MenuItem> 
         <Separator Visibility="{Binding DataContext.AreSelectedObjectsGroupedByTable, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}" /> 
         <MenuItem Header="{DynamicResource XpStrHintTreeExpandAll}" Command="{ui:CommandHandler ExpandOrCollapseAll}" CommandParameter="True" 
            Visibility="{Binding DataContext.SelectedObjectsGroupHeaders.DoCollapsedGroupsExist, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}"> 
          <MenuItem.Icon> 
           <Image Source="{Binding Converter={StaticResource nameToBitmapSource}}" DataContext="BmpTreeExpandAll"/> 
          </MenuItem.Icon> 
         </MenuItem> 
         <MenuItem Header="{DynamicResource XpStrHintTreeCollapseAll}" Command="{ui:CommandHandler ExpandOrCollapseAll}" CommandParameter="False" 
            Visibility="{Binding DataContext.SelectedObjectsGroupHeaders.DoExpandedGroupsExist, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}"> 
          <MenuItem.Icon> 
           <Image Source="{Binding Converter={StaticResource nameToBitmapSource}}" DataContext="BmpTreeCollapseAll"/> 
          </MenuItem.Icon> 
         </MenuItem> 
        </ContextMenu> 
       </DataGrid.Resources> 
       <DataGrid.RowStyle> 
        <Style TargetType="DataGridRow" BasedOn="{StaticResource Theme.DataGrid.Row.Style}"> 
         <Setter Property="ContextMenu" Value="{StaticResource SelectedObjectRowContextMenu}" /> 
         <EventSetter Event="MouseDoubleClick" Handler="SelectedObjectsRow_DoubleClick" /> 
        </Style> 
       </DataGrid.RowStyle> 
       <i:Interaction.Triggers> 
        <i:EventTrigger EventName="SelectionChanged"> 
         <i:InvokeCommandAction Command="{ui:CommandHandler ObjectsGridSelectionChangedCommand}" CommandParameter="{Binding SelectedItems,ElementName=SelectedObjectsGrid}"> 
         </i:InvokeCommandAction> 
        </i:EventTrigger> 
       </i:Interaction.Triggers> 
       <DataGrid.GroupStyle> 
        <!-- Style for groups at top level. --> 
        <GroupStyle> 
         <GroupStyle.ContainerStyle> 
          <Style TargetType="{x:Type GroupItem}"> 
           <Setter Property="Margin" Value="0,0,0,5"/> 
           <Setter Property="Template"> 
            <Setter.Value> 
             <ControlTemplate TargetType="{x:Type GroupItem}"> 
              <Expander IsExpanded="{Binding Path=Name.IsExpanded}" 
                 Tag="{Binding Path=Name}" 
                 Background="#FF112255" BorderBrush="#FF002255" 
                 Foreground="#FFEEEEEE" BorderThickness="1,1,1,5"> 
                            <Expander.ContextMenu> 
                <ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}"> 
                 <MenuItem Header="{DynamicResource XpStrKeepSelectionTableShort}" Command="{ui:CommandHandler KeepTable}" CommandParameter="{Binding Name}" /> 
                 <MenuItem Header="{DynamicResource XpStrRemoveSelectionTableShort}" Command="{ui:CommandHandler RemoveTable}" CommandParameter="{Binding Name}" /> 
                 <MenuItem Header="{DynamicResource XpStrList}" Command="{ui:CommandHandler ToggleSelectedObjectsGrouping}" CommandParameter="False" > 
                  <MenuItem.Icon> 
                   <Image> 
                    <Image.Source> 
                     <DrawingImage> 
                      <DrawingImage.Drawing> 
                       <GeometryDrawing Brush="Black" Geometry="{Binding DataContext.AreSelectedObjectsGroupedByTable, 
                        Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource ReverseBoolToGeometryConverter}}" /> 
                      </DrawingImage.Drawing> 
                     </DrawingImage> 
                    </Image.Source> 
                   </Image> 
                  </MenuItem.Icon> 
                 </MenuItem> 
                 <Separator Visibility="{Binding DataContext.AreSelectedObjectsGroupedByTable, Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}" /> 
                 <MenuItem Header="{DynamicResource XpStrHintTreeExpandAll}" Command="{ui:CommandHandler ExpandOrCollapseAll}" CommandParameter="True" 
                    Visibility="{Binding DataContext.SelectedObjectsGroupHeaders.DoCollapsedGroupsExist, 
                  Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}"> 
                  <MenuItem.Icon> 
                   <Image Source="{Binding Converter={StaticResource nameToBitmapSource}}" DataContext="BmpTreeExpandAll"/> 
                  </MenuItem.Icon> 
                 </MenuItem> 
                 <MenuItem Header="{DynamicResource XpStrHintTreeCollapseAll}" Command="{ui:CommandHandler ExpandOrCollapseAll}" CommandParameter="False" 
                    Visibility="{Binding DataContext.SelectedObjectsGroupHeaders.DoExpandedGroupsExist, 
                  Source={x:Reference SelectedObjectsGrid}, Converter={StaticResource BoolToVisibilityConverter}}"> 
                  <MenuItem.Icon> 
                   <Image Source="{Binding Converter={StaticResource nameToBitmapSource}}" DataContext="BmpTreeCollapseAll"/> 
                  </MenuItem.Icon> 
                 </MenuItem> 
                </ContextMenu> 
               </Expander.ContextMenu> 
               <Expander.Header> 
                <DockPanel> 
                 <TextBlock FontWeight="Bold" Margin="5,0,0,0" IsHitTestVisible="False"> 
                  <Run Text="{Binding Path=Name.Description, Mode=OneWay}" /> 
                  <Run Text=" ("/> 
                  <Run Text="{Binding Path=Name.GroupedCount, Mode=OneWay}" /> 
                  <Run Text=")"/> 
                 </TextBlock> 
                </DockPanel> 
               </Expander.Header> 
               <Expander.Content> 
                <ItemsPresenter/> 
               </Expander.Content> 
              </Expander> 
             </ControlTemplate> 
            </Setter.Value> 
           </Setter> 
          </Style> 
         </GroupStyle.ContainerStyle> 
        </GroupStyle> 
       </DataGrid.GroupStyle> 
       <DataGrid.Columns> 
        <DataGridTextColumn Header="{DynamicResource XpStrLabel}" Binding="{Binding Data.Label}" /> 
        <DataGridTextColumn Header="{DynamicResource XpStrClass}" Binding="{Binding Data.Class.Name}" /> 
       </DataGrid.Columns> 
      </DataGrid> 
+0

당신이 배열의 요소에'IComparable'을 구현하려고 했습니까? 어떤 배열인지 알 수 있다고 가정합니다. 그러나 시계 창을 보면서 많은 것을 볼 수 있습니다. –

+0

그룹화 및 정렬은보기가 아닌보기 모델에 속하므로 코드 숨김 대신 'xaml'과 함께 사용할 수 있습니다. List 및 DataTables와 함께 사용했으며 항상 효과가있었습니다. 처음부터'Binding' 포인트까지'CVS'를 만드는 방법을 보여줄 수 있습니까? – XAMlMAX

+0

정렬 할 수있는 여러 열이 있기 때문에 IComparable을 구현하지 않았습니다. 거기에 그룹을 나타내는 행과 클래스를 나타내는 클래스가 있습니다. 나는 단지 DataGrid가 그룹화 될 때 정렬을 제거하고 싶었다. –

답변

0

이 컬렉션 소스가 ObservableCollection<NetObject>이라고 가정은 다음과 같은 구현해야 귀하의 propertys 또는 필드 .....

반환 값은 다음과 같다이 인스턴스는 정렬 순서에서 OBJ 앞에 :

  • 이하

    0보다.
  • 0 :이 인스턴스는 obj와 같은 정렬 순서로 나타납니다.
  • 0보다 큼 :이 인스턴스는 정렬 순서에서 obj를 따릅니다.

편집 : 당신은 또한 사용할 수 HeaderBindingSource의 경우

:

public GroupHeaderBindingSource(string name, string description, GroupHeadersInfo headersInfo) : BindingSource, IGroupHeader, IComparable 
{ 
    return 0; 
} 
+0

감사합니다. 그러나 5 열이있는 경우 어떻게 비교해야하는 속성을 알 수 있습니까? 그 위에는 DataGrid가 IComparable을 구현하지 않고 이미 비교할 수 있습니다. 그것은 예외를 일으키는 그룹핑입니다. –

+0

적어도 그룹화 또는 정렬을 원하는 각 속성은 ICompareable을 구현해야한다고 생각합니다. 표준 타입 (이것을하는 int 등). 다른 클래스 유형 (사용자 정의 클래스 ...)의 일부 특성을 사용합니까? 'TestItem'에있는'IComparable' 구현은 일종의 기본 정렬입니다 (속성이 선택되지 않은 경우). 아마 그것은 누락되어 있고 당신이 :'MyCollectionViewSource.SortDescriptions.Clear();'항목들은 TestItem이 그것의'IComparable' 구현에 의해 정렬 될 때 정렬 될 것입니다. – WPFGermany

+0

MyCollectionViewSource.SortDescriptions.Clear();를 수행하지 않아도 동일한 예외가 발생합니다. 것은 내가 사용자 지정 정렬을 구현하지 않은 것입니다. 그것은 xaml에서 비활성화되어 있지 않습니다. 아무도 xaml에서 비활성화해야하는 경우도 있습니다. WPF 및 특히 WPF DataGrid에는 모든 기본/기본 기능이 없습니다. 그룹화가 정렬을 중단해서는 안됩니다. –