Я разрабатываю приложение WinForms (.Net 3.5, без WPF), где я хочу иметь возможность отображать запросы внешнего ключа в DataGridView с привязкой к данным.
Примером такого рода отношений является то, что у меня есть таблица OrderLines. Строки заказов имеют отношение внешнего ключа к продуктам, а продукты, в свою очередь, имеют отношение внешнего ключа к ProductTypes.
Я хотел бы иметь привязку к данным DataGridView, где каждая строка представляет строку заказа, отображающую продукт и тип продукта линии.
Пользователи могут добавлять или редактировать строки заказа прямо в сетку и выбирать продукт для строки заказа из comboBoxColumn - это должно затем обновить столбец producttype, показывающий тип продукта для выбранного продукта в той же строке.
Наиболее близким к хорошему подходу, который я нашел до сих пор, является введение объекта домена, представляющего строку заказа, а затем привязку DataGridView к коллекции этих строк заказа. Затем я добавляю свойства к объекту строки заказа, которые раскрывают продукт и тип продукта, и вызываю соответствующие события notifypropertychanged, чтобы все было в актуальном состоянии. В моем репозитории строки заказа я могу затем связать сопоставления между этим объектом строки заказа и тремя таблицами в моей базе данных.
Это работает со стороны привязки данных, но необходимость передачи кода для всего этого OR-сопоставления в репозитории кажется плохой. Я думал, что nHibernate сможет помочь с этим подключением, но я борюсь с сопоставлениями через все внешние ключи - они, похоже, работают нормально (поиск внешнего ключа для продукта строки заказа создает правильный объект продукта на основе внешнего ключа), пока я не попытаться выполнить привязку данных, я не могу получить столбцы идентификатора привязки данных для обновления моего продукта или объектов типа продукта.
Верен ли мой общий подход? Если да, то каково хорошее решение проблемы отображения?
Или есть лучшее решение для привязки строк данных, включая поиск внешнего ключа, которое я даже не рассматривал?





добро пожаловать в StackOverflow :)
Обычно вы бы основывали информацию в раскрывающемся списке на двух значениях ValueMember и DisplayMember.
ValueMember является источником фактического значения элементов управления (это будет значение ключа в строке заказа), элемент отображения - это значение, которое отображается пользователю вместо значения (это будет значение FK).
Нет ли особой причины, по которой вы не можете просто вернуть все необходимые данные и установить эти свойства?
Вот хорошее видео "Как мне сделать", демонстрирующее привязку данных:
Мой первоначальный вопрос, очевидно, был непонятен, извините за это.
Проблема заключалась не в привязке данных к DataGridView в целом или в реализации DataGridViewComboBoxColumn - как люди, которые уже правильно ответили, это хорошо задокументировано в Интернете.
Проблема, которую я пытался решить, заключается в обновлении свойств, которые детализируются через отношения.
В моем примере заказов, когда я изменяю значение столбца «Продукт», столбец «Тип продукта» не обновляется, хотя в коде я устанавливаю свойство и запускаю событие NotifyPropertyChanged. (В отладке я хожу во все нужные места)
После долгих поисков я понял, что это даже не работает, когда я напрямую установил свойство «Тип продукта» источника данных, а не установил его в установщике «Продукт».
Еще одна вещь, которая, как мне кажется, вернула меня на правильный путь, заключается в том, что когда я предоставляю имитацию уровня доступа к данным, созданную в основной форме, все работает нормально.
Кроме того, когда я копирую IList, созданный nHibernate, в IBindingList - все снова появляется нормально.
Так проблема в том, что, я думаю, потоки и события NotifyPropertyChanged теряются при использовании определенных источников данных определенными способами (желаю, чтобы я мог быть более определенным, чем это!)
Я собираюсь продолжить поиск лучших способов решения этой проблемы, чем копирование IList в IBindingList - возможно, мне нужно узнать о маршалинге потоков.
Редактировать
Теперь я разработал решение, которое решает эту проблему, и думаю, что понимаю, что меня смущало - похоже, что что-либо, кроме базовой привязки данных свойств, не подходит для списков, которые не являются производными от BindingList - как только я пытался привязка данных к свойствам, которые запускали связанные события NotifyPropertyChanged, все пошло наперекосяк, и мои события потерялись.
В решении для доступа к данным, которое у меня есть сейчас, используется вариант шаблона Роба Конери IRepository, возвращающий мои коллекции для привязки в качестве созданного мной настраиваемого класса, SortableBindingLazyList, производного от BindingList, реализует методы Sort Core и также сохраняет свой внутренний список как запрос, задерживающий материализацию списка.
Ну, я не знаю, поддерживается ли это DataGridView, но когда вы выполняете обычную привязку данных WinForms (скажем, к обычному TextBox), вы можете использовать пути к собственности для навигации по отношениям объектов.
Что-то вроде этого:
myTextBox.DataBindings.Add("Text", anOrderLine, "OrderedPart.PartNumber");
Стоит посмотреть, работает ли это и в вашей ситуации.
Я думаю, что проблема, с которой вы столкнулись, заключается в том, что при привязке к сетке недостаточно поддерживать INotifyPropertyChanged, но вы должны запускать события ListChanged в своей реализации IBindingList и убедиться, что вы переопределяете и возвращаете true для SupportsChangeNotification свойство. Если вы не вернете true для этого, сетка не будет искать его, чтобы узнать, изменились ли данные.
В .NET 2.0+ вы можете создать общую коллекцию, используя класс BindingList, это позаботится о большей части неприятностей (просто не забудьте переопределить и вернуть true для свойства SupportsChangeNotification).
Если класс, который вы используете для привязки данных, имеет свойство, которое является коллекцией (например, IBindingList или BindingList), вы можете напрямую привязать сетку внешнего ключа к этому свойству. При настройке привязок в конструкторе форм просто выберите свойство коллекции в качестве источника данных для сетки. Он должен «просто работать». Единственная хитрость - убедиться, что вы правильно обрабатываете пустые или нулевые коллекции.
Спасибо, Гаро, это прекрасно покрывает то, что я обнаружил. Единственное отличие в том, что у меня есть столбец внешнего ключа, а не сетка. Я также собираюсь обновить свой выигранный ответ, пояснив, что вызывает у меня проблемы - я думаю, что причины, по которым я изначально неправильно диагностировал проблему, могут быть полезны