none
WPF: программное изменение ItemsSource, в какой момент дерево визуальных элементов уже построено? Как это поймать?

    Общие обсуждения

  • Есть DataGrid, у которой ItemsSource ссылается на View объекта CollectionViewSource. Я использую группировки, поэтому на основе своей коллекции (List<MyObject>) и создаю CollectionViewSource. Еще есть ListBox, который содержит в качестве данных объекты, по которым я группирую DataGrid (одна из колонок состоит из данных этого типа).

    Состоянием (свернуто/развернуто) групп я управляю через VisualTree окна. Если выбираю элемент списка, то нахожу нужный Expander в гриде, его открываю, остальные закрываю. Это работает.

    Однако, например, я хочу реализовать копирование строк. Для этого я использую событие KeyUp самой DataGrid. Если кнопка Inser нажата совместно с Cntrl, то запоминаем текущую строку, если совместно с Shift - то добавляю в свою коллекцию (это MyCollection типа List<MyObject>) и дальше выполняю такие строки:

    CollViewSource = new CollectionViewSource() { Source = MyCollection };
    CollViewSource.GroupDescriptions.Add(new PropertyGroupDescription("LayerDescription"));
    ICollectionView listView = CollViewSource.View;
    dgData.ItemsSource = listView;

    - т.е. я создаю представление заново и заново присваиваю свойству ItemsSource.

    Но, если так делать, то происходит следующее:

    1. DataGrid теряет фокус. т.е. последующие Shift + Insert уже не обрабатываются и добавления строк не получается.

    2. Все группы свернуты, приходится снова открывать нужную.

    Дело в том, что после "dgData.ItemsSource = listView;" новых визуальных объектов дерева еще нет, оно не отрисовано, что ли... И попытка найти элементы группировок ничего не дает. Это как асинхронный режим? :) Отсюда вопросы:

    1. К какому событию мне привязываться, чтобы после обновления ItemsSource уже работать с созданными визуальными элементами?

    2. Как имитировать возвращение фокуса гриду?

    Скорее всего будут советы использовать MVVM, свою коллекцию создавать там от чего-то с реализацией интерфейса INotifyCollectgionChanged... Проще, пожалуйста проще, я этого сейчас не осилю. Есть грид, обновляю данные простым переприсваиванием свойства ItemsSource, надо отловить момент, когда после обновления источника данных дерево визуальных элементов уже создано. Все - примерно так :).

Все ответы

  • Нашел workaround (обход), не прямо ответ на мой свой вопрос, но то, что приводит к тем же результатам. В общем пришлось создать свой класс MyGrid: DataGrid, в котором переписать метод:

    protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)

    с простым содержимым:

                base.OnRender(drawingContext);
                //
                MainWindow parentWindow = (this as DependencyObject).Ancestors<MainWindow>().First() as MainWindow;

                if (parentWindow != null)
                {
                    if (parentWindow.GLayers.SelectedItem != null)
                        parentWindow.OnCurrentLayerChanged(parentWindow.GLayers,
                            parentWindow.GLayers.SelectedItem as GeologycalLayer);
                }

    После строки base.OnRenders(...) все визуальные элементы уже присутствуют и ими можно управлять.

    Это не отвечает на вопрос о событиях, которые можно перехватить, но может это и есть то самое решение?

  • Оказалось, что не каждый раз вызывается событие OnRender() DataGrid. Например, если я обрабатываю нажатие кнопок в пределах грида и при этом копирую строку, а именно:

    - создаю новый объект CollectionViewSource

    - dgData.ItemsSource = (объект CollectionViewSource).View. Т.е. как бы создаю представление заново, а OnRender() не получает управления. Почему? При этом все группировки сворачиваются. Это происходит автоматически, но без затрагивания OnRender() грида.

    Какая процедура (какого объекта) делает перерисовку? Как хоть это найти?