WPF datagrid - Группировка по сетке данных с редактируемым столбцом, перезаписывает строки в группе, когда редактируемая ячейка «открыта» или отредактирована. - PullRequest
1 голос
/ 03 ноября 2011

После группировки я столкнулся со странной проблемой в сетке данных WPF.Строки внутри групп начинают переупорядочиваться.Я использую сетку данных .net 3.5 из codeplex.

Проблема была задана на форуме msdn.Пожалуйста, найдите ссылку ниже.

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

В конце цепочки пользователь msdn сказал, что обходных путей может не быть.Но мне он очень нужен !!

Ответы [ 2 ]

2 голосов
/ 10 апреля 2012

Вы пытались выполнить сортировку через CustomSort? Я видел это где-то опубликовано, и это сработало для меня. Потребовалось немного поиска, но он доступен через класс ListCollectionView. Так что-то вроде:

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

lcv.CustomSort = new YourObjectComparer();

Где YourObjectComparer реализует IComparer и сортирует по свойствам, которые вы хотите.

1 голос
/ 03 ноября 2011

РЕДАКТИРОВАНИЕ:

Для этого, когда происходит редактирование ячейки, мы удаляем группы и добавляем их снова.Это заставляет клетку оставаться в заданном порядке.Но это создает еще одну проблему, которая заключается в том, что все расширители рухнули.Поэтому, если мы помним, какие расширители остаются развернутыми после перегруппировки, мы достигаем того, что вы ищете.


Есть несколько событий, которые могут помочь вам в достижении этой функциональности ...

  1. DataGrid.CellEditEnding событие
  2. Expander.Initialized, Expander.Expanded и Expander.Collpased события
  3. ICollectionView.CurrentChanging событие

Все, что вам нужно запомнитьэто состояние расширителей, когда они развернуты или свернуты.Каждый расширитель представляет сгруппированное значение, представленное свойством Name.Эти сгруппированные значения являются уникальными.Поэтому достаточно словаря, в котором Dictionary.Key - это значение Name, а Dictionary.Value - флаг Expander.IsExpanded.

С этим raw * следующий код выполняет то, что вы ищете...

Класс модели: Я представляю простой список объектов Key-Value в 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 вложенные расширители.Теперь некоторая группировка имен может совпадать с некоторой группировкой фамилий, например George.Таким образом, словарь впадет в уловку и не будет работать правильно.

Надеюсь, это поможет.

...