powered by simpleCommunicator - 2.0.35     © 2025 Programmizd 02
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / ContainerFromItem
7 сообщений из 7, страница 1 из 1
ContainerFromItem
    #39884194
ЧитательX
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Исходная задача: Есть набор данных класса CItem подключенных через ListCollectionView к DataGrid:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
static public ObservableCollection<CItem> Items = new ObservableCollection<CItem>();
static public ListCollectionView View = new ListCollectionView(Items);
...
private void Window_Loaded(object sender, RoutedEventArgs e)
{
  Items.Add(new CItem() { ID = 1, Name = "aaa" });
  Items.Add(new CItem() { ID = 1, Name = "bbb" });
  Grid1.DataContext = View;
}


Зная конкретный элемент этого набора я пытаюсь получить объект строки этого грида:
Код: c#
1.
2.
3.
4.
5.
CItem item = Items[0] as CItem;

DependencyObject dob1 = Grid1.ItemContainerGenerator.ContainerFromItem(item);
View.Refresh();
DependencyObject dob2 = Grid1.ItemContainerGenerator.ContainerFromItem(item);


Первая операция (dob1) работает
Вторая операция (dob2) не хочет работать
Почему безобидная операция освежения вьюхи приводит к такому результату?

(Тестовый проектик приложен)
...
Рейтинг: 0 / 0
ContainerFromItem
    #39884225
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
скорее всего дело в виртуализации

Grid1.ItemContainerGenerator.ContainerFromItem(item); возвращает элемент контейнера, который в момент обновления не существует.
Refresh() вьюхи вызывает событие изменения с аргументом NotifyCollectionChangedAction.Reset и все элементы списка представления удаляются и заполняются по новой, по сути происходит пересоздание всех списка к исходной коллекции, вообще само обновление может содержать в себе другие элементы, я часто оборачиваю элементы представления, то есть представление возвращает не оригинальные объекты модели, а обёртку над ними, которую сама создает или элементы другого типа (типа NewItemPlaceholder'ы) и те, которые возможно я как разработчик хочет добавить.

static public ObservableCollection<CItem> Items = new ObservableCollection<CItem>();
static public ListCollectionView View = new ListCollectionView(Items);

делать такие поля статическими плохая практика, хоть компилятор и может разобраться, что Items нужно инициализировать до, а не после View. Лучше вообще такие объекты с событиями не использовать в статике.

Вашего сценария лучше избегать, на самом деле, не надо пытаться из ViewModel или ICollectionView взаимодействовать с представлением, получать ссылки на объекты управления. DataGrid должен быть просто отражением состояния вашего представления, а в случае если вы используйте ICollectionView даже на уровне представления коллекции. А вот DataGrid может управлять представлением по средствам интерфейсов. Что он и делает когда вы управляется фильтрацией и сортировкой, группировкой и так далее, на сколько я помню для DataTable DataGrid использует не ListCollectionView, а если вы создадите свое представление коллекции, то будет использовать вашу, ну или которые вы задаете в сорс.

Либо попробуйте отключить виртуализацию, но опять же так делать не стоит даже потому, что виртуализация может быть Recycled и вы получите вообще элемент другого объекта и т.д.
...
Рейтинг: 0 / 0
ContainerFromItem
    #39884229
Roman Mejtes
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ну и забыл сказать, что пересоздание всех этих элементов произойдет через Dispatcher с каким то приоритетом Loaded (на счет приоритета не уверен, но у виртуализируемых объектов при создание срабатывает событие Loaded).
Как вариант после View.Refresh() попробуйте вызвать await Dispatcher.Yield(); не факт, что поможет, я не пробовал ваш код, мне лень и это вообще не безопасно, какие то файлы качать
...
Рейтинг: 0 / 0
ContainerFromItem
    #39884238
Фотография Shocker.Pro
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
граммарнаци )Извини, Роман, наболело


Посредством , кого – чего – это производный предлог, который используется при управлении родительным падежом. Предлог – служебная часть речи, служит для выражения связи между словами. К предлогу нельзя поставить никакой вопрос. Образован от существительного “посредство” со значением “посредничество“. Посредник, посредничать, посредничество – это однокоренные слова, в конечном счете отнесенные к лицу, стоящему “посередине” – между двумя сторонами – и призывающее их к миру, согласию или взаимной выгоде при совершении сделки.

Есть в русском языке и сочетание « по средствам » – предлог с существительным в дательном падеже, имеет значение: согласно достатку . Если допустить ошибку в окончании, получится сходство с предлогом по звучанию. Отличить это сочетание от предлога “посредством” достаточно легко: в сочетании предлога и существительного между ними можно вставить другое слово, например, “По моим, скромным средствам”.

Подробнее: https://obrazovaka.ru/kak-pishetsya/posredstvom.html#ixzz641I7xOcz
...
Рейтинг: 0 / 0
ContainerFromItem
    #39884424
ЧитательX
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо Роман за развернутый ответ. Приложенный проектик можно и не открывать.
Я его создал для того, чтобы, при желании, можно было посмотреть на полную схему
создаваемых данных и списков.
...
Рейтинг: 0 / 0
ContainerFromItem
    #39884528
Сон Веры Павловны
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Roman Mejtesну и забыл сказать, что пересоздание всех этих элементов произойдет через Dispatcher с каким то приоритетом Loaded (на счет приоритета не уверен, но у виртуализируемых объектов при создание срабатывает событие Loaded).
Как вариант после View.Refresh() попробуйте вызвать await Dispatcher.Yield(); не факт, что поможет, я не пробовал ваш код, мне лень и это вообще не безопасно, какие то файлы качать
Поможет-поможет. Непосредственно после ICollectionView.Refresh никаких контейнеров еще не существует, их создание в очереди диспетчера.
Вот это:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
CItem item = _items[0] as CItem;
DependencyObject dob1 = Grid1.ItemContainerGenerator.ContainerFromItem(item);
Console.WriteLine(dob1==null);
_view.Refresh();
Dispatcher.BeginInvoke((Action) (() =>
{
  DependencyObject dob2 = Grid1.ItemContainerGenerator.ContainerFromItem(item);
  Console.WriteLine(dob2 == null);
}), DispatcherPriority.ContextIdle);


выводит False и False - приоритет ContextIdle ставит операцию после всего, что может влиять на компоновку визуального дерева.
...
Рейтинг: 0 / 0
ContainerFromItem
    #39884560
ЧитательX
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Спасибо
...
Рейтинг: 0 / 0
7 сообщений из 7, страница 1 из 1
Форумы / WPF, Silverlight [игнор отключен] [закрыт для гостей] / ContainerFromItem
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]