2011-11-03 98 views
1

在分組後,我正面臨着WPF數據網格中的奇怪問題。組內的行開始重新排序。我從codeplex使用.net 3.5框架的數據網格。WPF數據網格 - 按可編輯列編組的數據網格進行分組當可編輯單元格「打開」或編輯時,組中的行

該問題已被msdn論壇詢問。請找到下面的鏈接。

http://social.msdn.microsoft.com/Forums/en/wpf/thread/3f915bf9-2571-43e8-8560-3def1d0d65bb

MSDN的用戶說,在線程結束,有可能是沒有變通方法。但我非常需要一個!

+0

您可以將DataGrid ItemsSource綁定到CollectionViewSource,並使用SortDescription指定您的排序順序,使得項目不會被重新排序。 – whoisthis

+0

@bjoshi - 我也在做同樣的事情,但它是重新排序! – GuruC

回答

1

編輯:

對於本當單元格編輯發生,我們刪除組和重新添加他們。這使細胞保持其預定的秩序。但是這帶來了另一個問題,就是所有的擴張者都崩潰了。因此,如果我們記得重新組合後哪些擴展器仍然擴展,我們將實現您所尋求的。


有幾個事件,可以幫助你實現這個功能...

  1. DataGrid.CellEditEnding事件
  2. Expander.InitializedExpander.ExpandedExpander.Collpased事件
  3. ICollectionView.CurrentChanging事件

所有你需要的請記住擴展器擴展或摺疊時的狀態。每個擴展器表示由Name屬性表示的分組值。這些分組值是唯一的。所以Dictionary.Key是這個Name值的字典和Dictionary.ValueExpander.IsExpanded標誌就足夠了。

有了這個原料下面的代碼做你追求的是什麼...

模型類:我代表DataGrid中的鍵值對象的簡單列表。

public class MyKeyValuePair<TKey, TValue> : INotifyPropertyChanged 
{ 
    private TKey key; 
    private TValue value; 

    public MyKeyValuePair(TKey k, TValue v) 
    { 
     key = k; 
     value = v; 
    } 

    public TKey Key 
    { 
     get { return key; } 
     set { 
      key = value; 
      OnPropertyChanged("Key"); 
     } 
    } 

    public TValue Value 
    { 
     get { return value; } 
     set { 
      this.value = value; 
      OnPropertyChanged("Value"); 
     } 
    } 

    public void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
     { 
      this.PropertyChanged 
       (this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
} 

XAML:

<tk:DataGrid 
    ItemsSource="{Binding}" 
    CellEditEnding="MyDataGrid_CellEditEnding"> 
    <tk:DataGrid.GroupStyle> 
     <GroupStyle> 
      <GroupStyle.HeaderTemplate> 
      <DataTemplate> 
       <StackPanel> 
        <TextBlock Text="{Binding Path=Name}" /> 
       </StackPanel> 
      </DataTemplate> 
      </GroupStyle.HeaderTemplate> 
     <GroupStyle.ContainerStyle> 
     <Style TargetType="{x:Type GroupItem}"> 
      <Setter Property="Template"> 
       <Setter.Value> 
       <ControlTemplate TargetType="{x:Type GroupItem}"> 
        <Expander 
         Initialized="Expander_Initialized" 
         Expanded="Expander_Expanded" 
         Collapsed="Expander_Expanded"> 
         <Expander.Header> 
          <StackPanel Orientation="Horizontal"> 
           <TextBlock 
            Text="{Binding Path=Name}" /> 
           <TextBlock Text=" (" /> 
           <TextBlock 
            Text="{Binding Path=ItemCount}"/> 
           <TextBlock Text="(" /> 
           <TextBlock Text="Items"/> 
          </StackPanel> 
         </Expander.Header> 
         <ItemsPresenter /> 
        </Expander> 
       </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 
    </GroupStyle.ContainerStyle> 
    </GroupStyle> 
</tk:DataGrid.GroupStyle> 
</tk:DataGrid> 

Window.cs代碼背後:

public partial class Window8 : Window 
{ 
    private Dictionary<string, bool> _dict; 
    public Window8() 
    { 
     InitializeComponent(); 

     _dict = new Dictionary<string, bool>(); 

     var list1 = new List<MyKeyValuePair<string, int>>(); 
     var random = new Random(); 
     for (int i = 0; i < 50; i++) 
     { 
      list1.Add(new MyKeyValuePair<string, int>(
       i.ToString(), random.Next(300) % 3)); 
     } 

     var colView = new ListCollectionView(list1); 
     colView.GroupDescriptions.Add(
      new PropertyGroupDescription("Value")); 
     this.DataContext = colView; 
    } 

    private void MyDataGrid_CellEditEnding 
     (object sender, DataGridCellEditEndingEventArgs e) 
    { 
     var dg = sender as DataGrid; 
     var cellInfo = dg.CurrentCell; 
     var mySource = dg.ItemsSource as ListCollectionView; 
     var oldDlg 
      = new CurrentChangingEventHandler((obj, args) => { return; }); 
     var dlg = new CurrentChangingEventHandler(
      (obj, args) => 
      { 
       if (cellInfo.Item == mySource.CurrentItem) 
       { 
        var grpDescs = mySource.GroupDescriptions; 
        var oldGrpDescs 
         = grpDescs.Cast<PropertyGroupDescription>().ToList(); 
        mySource.Dispatcher.BeginInvoke(
         new Action(
          () => 
          { 
           grpDescs.Clear(); 

           foreach (var grdpDesc in oldGrpDescs) 
           { 
            grpDescs.Add(grdpDesc); 
           } 

           mySource.CurrentChanging -= oldDlg; 
          })); 
       } 
      }); 

     oldDlg = dlg; 
     mySource.CurrentChanging -= oldDlg; 
     mySource.CurrentChanging += oldDlg; 
    } 

    private void Expander_Expanded(object sender, RoutedEventArgs e) 
    { 
     var exp = sender as Expander; 
     var dc = exp.DataContext as CollectionViewGroup; 
     _dict[dc.Name.ToString()] = exp.IsExpanded; 
    } 

    private void Expander_Initialized(object sender, EventArgs e) 
    { 
     var exp = sender as Expander; 
     var dc = exp.DataContext as CollectionViewGroup; 
     if (_dict != null 
      && _dict.ContainsKey(dc.Name.ToString()) 
      && _dict[dc.Name.ToString()]) 
     { 
      exp.IsExpanded = true; 
     } 
    } 
} 

但有兩個權衡。

  1. 這會使每個單元格編輯嘗試數據網格中的大量項目的速度變慢。因爲重新編組發生在每次單元編輯嘗試之後。
  2. 由於字典中的Name鍵可能會/可能不會保持唯一性,可能不適用於多個組說明。例如。假設僱員名單如果你在FirstName上組,並且還通過LastName gropup將有嵌套擴展。現在,某些名字分組可能會與某些姓氏分組匹配,例如George。所以字典將陷入詭計,並且不會正常工作。

希望這會有所幫助。

+0

我的問題和你的答案似乎並不符合我的想法。我不是在問如何分組或如何保持擴展。我的問題是如何防止重新排序。 ! – GuruC

+0

那就是這段代碼正在做什麼。你測試了這個代碼嗎? –

2

您是否嘗試過通過CustomSort進行排序?我看到這張貼在某個地方,它爲我工作。它需要一點點的發現,但它可以通過ListCollectionView課程獲得。因此,像:

ListCollectionView lcv = 
    (ListCollectionView)CollectionViewSource.GetDefaultView(YourObjectCollection); 

lcv.CustomSort = new YourObjectComparer(); 

YourObjectComparer實現上要的屬性IComparer和排序。