2014-10-16 80 views
3

我有一個非常基本的DataGrid與一些測試數據。數據提供爲ObservableCollection<T>Clientobjects,其包含Organization,FirstNameLastName特性。我通過Organization對項目進行分組,並且希望能夠通過FirstNameLastName在特定組內排序(此部分功能正常),並按Organization排序組。最後一部分是我遇到的問題。Sorting DataGrid groups

如果我不指定任何排序屬性,或者如果我指定CollectionViewSource.SortDescriptions屬性(見下文),如PropertyName="Name"PropertyName="CompleteNonsense",除了PropertyName="Organization",這將讓我做一個初步的排序。如果您查看下面的圖片,公司名稱會亂序顯示,因爲這是集合初始化的方式。如果我點擊Organization標題,它會按升序對它進行排序,但不會讓我在此之後再進行排序。如果我再次點擊標題,它會改變箭頭,它表示排序的方向,但不會發生實際的排序。無論我指定什麼排序屬性,即使是完全任意的屬性,除非它是PropertyName="Organization",或者沒有指定屬性,否則這是完全相同的。

如果我在PropertyName="Organization"上指定排序,它將從升序開始排序,但如果單擊標題則不排序。所以,看起來該屬性名稱確實會觸發排序,但只是第一次。

截圖:

這裏的XAMLDataGrid

<DataGrid ItemsSource="{Binding Source={StaticResource GroupedData}}" 
      AutoGenerateColumns="False" IsReadOnly="True" 
      GridLinesVisibility="None" HeadersVisibility="Column" 
      CanUserAddRows="False" CanUserDeleteRows="False" 
      CanUserResizeRows="False" Background="White"> 
    <DataGrid.CellStyle> 
     <Style TargetType="DataGridCell"> 
      <Setter Property="BorderThickness" Value="0"/> 
     </Style> 
    </DataGrid.CellStyle> 
    <DataGrid.RowStyle> 
     <Style TargetType="DataGridRow"> 
      <Setter Property="Margin" Value="10,0,0,0"/> 
     </Style> 
    </DataGrid.RowStyle> 
    <DataGrid.GroupStyle> 
     <GroupStyle> 
      <GroupStyle.HeaderTemplate> 
       <DataTemplate> 
        <DockPanel Background="LightBlue" DataContext="{Binding Items}"> 
         <TextBlock Text="{Binding Path=Organization}" 
            Foreground="Blue" Margin="5,0,0,0" Width="100"/> 
         <TextBlock Text="Employee Count:" Foreground="Blue" Margin="40,0,0,0"/> 
         <TextBlock Text="{Binding Path=Count}" Foreground="Blue" 
            Margin="5,0,0,0"/> 
        </DockPanel> 
       </DataTemplate> 
      </GroupStyle.HeaderTemplate> 
     </GroupStyle> 
    </DataGrid.GroupStyle> 
    <DataGrid.Columns> 
     <DataGridTextColumn Header="Organization" Binding="{Binding Organization}"/> 
     <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/> 
     <DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/> 
     <DataGridTextColumn Width="*"/> 
    </DataGrid.Columns> 
</DataGrid> 

而這裏的XAMLGroupingSorting

<CollectionViewSource Source="{Binding Data}" x:Key="GroupedData"> 
    <CollectionViewSource.GroupDescriptions> 
     <PropertyGroupDescription PropertyName="Organization"/> 
    </CollectionViewSource.GroupDescriptions> 
    <CollectionViewSource.SortDescriptions> 
     <scm:SortDescription PropertyName="Organization"/> 
    </CollectionViewSource.SortDescriptions> 
</CollectionViewSource> 

有沒有人知道我可以通過Organization超出最初的排序組?

編輯:

我一直用這個亂搞(真的需要弄清楚了這一點),並創建了頭Click事件的快速代碼隱藏事件處理程序:

<DataGrid.ColumnHeaderStyle> 
    <Style TargetType="DataGridColumnHeader"> 
     <EventSetter Event="Click" Handler="ColumnHeader_Click"/> 
    </Style> 
</DataGrid.ColumnHeaderStyle> 


private void ColumnHeader_Click(object sender, RoutedEventArgs e) 
{ 
    var columnHeader = sender as DataGridColumnHeader; 
    if (columnHeader != null && columnHeader.Content.ToString().Equals("Organization")) 
    { 
     if (columnHeader.Column.SortDirection == ListSortDirection.Descending) 
     { 
      columnHeader.Column.SortDirection = ListSortDirection.Ascending; 
      MessageBox.Show("Ascending"); 
     } 
     else 
     { 
      columnHeader.Column.SortDirection = ListSortDirection.Descending; 
      MessageBox.Show("Descending"); 
     } 
    } 
} 

Organization每次點擊後,"Descending"彈出,將箭頭向下排序,點擊OK後立即恢復向上。這些組的實際排序不會在視覺上發生。有些東西讓它卡在Ascending訂單。

回答

1

注意:請參閱編輯獲取最新的代碼。

這有點棘手,但我能夠找出答案。以下代碼適用於Sorting事件的代碼隱藏處理程序,但可以輕鬆調整以放入ViewModelView(取決於您的操作方式)。

代碼:

<DataGrid Sorting="DataGrid_Sorting" ... > ... </DataGrid> 


private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e) 
{ 
    var headerName = "Organization"; 

    var column = e.Column; 
    if (!column.Header.ToString().Equals(headerName)) 
    { 
     return; 
    } 

    var source = (sender as System.Windows.Controls.DataGrid).ItemsSource as ListCollectionView; 
    if (source == null) 
    { 
     return; 
    } 

    e.Handled = true; 
    var sortDirection = column.SortDirection == ListSortDirection.Ascending ? 
     ListSortDirection.Descending : ListSortDirection.Ascending; 

    using (source.DeferRefresh()) 
    { 
     source.SortDescriptions.Clear(); 
     source.SortDescriptions.Add(new SortDescription(headerName, sortDirection)); 
    } 
    source.Refresh(); 
    column.SortDirection = sortDirection; 
} 

與上面的代碼,羣體本身由Organization得到整理和項目各組內FirstNameLastName得到排序。希望這段代碼能夠幫助別人。我一直在四處搜尋,這似乎是人們在處理DataGrid中的羣組時遇到的常見問題。

唯一的缺點是,當組項目按除分組屬性之外的任何其他項目排序時,它會將組的排序重置爲默認值。在嘗試了很多代碼之後,我一直無法找出解決方案。如果有人找到該部分的解決方案,我會很樂意給他們「正確的答案」。

一些資源,幫助我了:

How to force DataGrid group order in WPF?
WPF Datagrid group and sort

編輯:

想通了關於跨組排序由被重置的最後一部分組內分類。這是一個有點亂,因爲我還沒有把它清理乾淨的時候,但我想我會分享我的代碼:

<CollectionViewSource.GroupDescriptions> 
    <PropertyGroupDescription PropertyName="Organization"/> 
</CollectionViewSource.GroupDescriptions> 
<CollectionViewSource.SortDescriptions> 
    <scm:SortDescription PropertyName="Organization" Direction="Ascending"/> 
    <scm:SortDescription PropertyName="FirstName" Direction="Ascending"/> 
    <scm:SortDescription PropertyName="LastName" Direction="Ascending"/> 
</CollectionViewSource.SortDescriptions> 


private void DataGrid_Sorting(object sender, DataGridSortingEventArgs e) 
{ 
    SortGroupedDataGrid("Organization", sender, e); 
} 

private void SortGroupedDataGrid(string groupHeader, object sender, DataGridSortingEventArgs e) 
{ 
    // Get the main ListCollectionView and make sure it's not null. 
    var source = (sender as System.Windows.Controls.DataGrid).ItemsSource as ListCollectionView; 
    if (source == null) 
    { 
     return; 
    } 

    // Mark event as handled, so that automated sorting would not take place. 
    e.Handled = true; 
    // Main header which was used for the grouping. I'm only using one, but more can be added. 
    var headerName = groupHeader; 
    // Get the column that was being sorted on. 
    var column = e.Column; 
    // Check if the column was the same as the one being used for the grouping. 
    // I remove spaces so that any properties I use match the headers. Regex would probably 
    // work just as well, but it's an overkill for me at this time. 
    var isMainHeader = column.Header.ToString().Replace(" ", "").Equals(headerName); 
    // Because I set the initial sorting for all the properties in the XAML to be 
    // be sorted in Ascending order, I set these ones to Descending. One is for 
    // the main column and the other is for the secondary column. This does not account 
    // for a case where user Shift + Clicks multiple columns to chain sort. 
    var mainSortDirection = ListSortDirection.Descending; 
    var secondarySortDirection = ListSortDirection.Descending; 

    // If this is a main column sort event... 
    if (isMainHeader) 
    { 
     // Check its sorting direction and set it as opposite. 
     mainSortDirection = column.SortDirection == ListSortDirection.Descending ? 
      ListSortDirection.Ascending : mainSortDirection; 
    } 
    else 
    { 
     // ...else, get the sorting direction of the main column, because we want 
     // it to stay the same, and get the opposite sorting direction for the 
     // secondary column. 
     mainSortDirection = source.SortDescriptions[0].Direction; 
     secondarySortDirection = column.SortDirection == ListSortDirection.Descending ? 
      ListSortDirection.Ascending : secondarySortDirection; 
    } 

    // Defer refreshing of the DataGrid. 
    using (source.DeferRefresh()) 
    { 
     // Clear any existing sorts. I've had some issues trying to alter existing ones. 
     source.SortDescriptions.Clear(); 
     // Since we want main column to either alter if its sort event was called, or 
     // stay the same if secondary column event was called, we always set it first. 
     source.SortDescriptions.Add(new SortDescription(headerName, mainSortDirection)); 

     // If this was not a main column event... 
     if (!isMainHeader) 
     { 
      // ...then set sorting for that other column. Since it'll be at index 1, 
      // after the main one, it'll only sort within each group, as I wanted. 
      source.SortDescriptions.Add(new SortDescription(column.Header.ToString().Replace(" ", ""), secondarySortDirection)); 
      // Set the header direction as well. 
      column.SortDirection = secondarySortDirection; 
     } 
     else 
     { 
      // Otherwise, it's a main event and we want to show the error for its header. 
      // If you want primary sorting direction to always display, then simply take 
      // it outside of else scope, so that it's always assigned. 
      column.SortDirection = mainSortDirection; 
     } 
    } 
    // Now we can refresh and post changes. 
    source.Refresh(); 
} 
+0

如果我已經兩組樣'組織'和'部門'?並對'Department'進行排序。 – nag 2017-01-17 11:00:57