Аннотация:
Основная задача приложений Windows Forms – манипулирование данными. В определенный момент времени приложение получает данные из некоторого источника, отображает их пользователю, пользователь изменяет данные, затем измененные данные помещаются в источник (в тот же самый или иной). В некоторых приложениях может не быть некоторых из вышеперечисленных этапов, но в целом эта картина характерна для большинства приложений.
В приложении, работающем с данными, существует логическая взаимосвязь между уровнем данных и представлением, хотим мы этого или нет. Вопрос в том, сколько рутинной работы ложится на ваши плечи. Механизм привязки данных в Windows Forms в значительной степени упрощает создание приложений, работающих с данными. Понимание основных концепций, на которых строится привязка данных, может в значительной степени упростить построение таких приложений, а также помочь в решении различных проблем, которые неизменно преследуют каждого разработчика.
Здравствуйте, WaSh, Вы писали:
WS>Не запоздалая ли статья-то ??? Да еще и в печатном журнале только...
WS>Уже давно пора написать что-то подобное для WPF с учетом новшевств 3.5 SP1 (чтоб было всё в одном месте). WS>Думаю, было бы актуальнее...
Ты считаешь, что после выхода WPF все перестали писать WinForms приложения?
Лично я в этом сомневаюсь...
Промышленная разработка ПО вещь крайне инерционная...
К тому же сейчас крайне мало коммерческих компонентов WPF (посмотри на тот же DevExpress). Поэтому мир WinForms будет жить еще долго, очень долго
Здравствуйте, SergeyT., Вы писали:
ST>Здравствуйте, WaSh, Вы писали:
WS>>Не запоздалая ли статья-то ??? Да еще и в печатном журнале только...
WS>>Уже давно пора написать что-то подобное для WPF с учетом новшевств 3.5 SP1 (чтоб было всё в одном месте). WS>>Думаю, было бы актуальнее...
ST>Ты считаешь, что после выхода WPF все перестали писать WinForms приложения? ST>Лично я в этом сомневаюсь... ST>Промышленная разработка ПО вещь крайне инерционная... ST>К тому же сейчас крайне мало коммерческих компонентов WPF (посмотри на тот же DevExpress). Поэтому мир WinForms будет жить еще долго, очень долго
Не спорю...
Но на то, что "сейчас крайне мало коммерческих компонентов WPF" и вообще WPF мало используется, влияет отсутствие подобных статей...
Здравствуйте, WaSh, Вы писали:
WS>Не спорю... WS>Но на то, что "сейчас крайне мало коммерческих компонентов WPF" и вообще WPF мало используется, влияет отсутствие подобных статей...
Тебе же уже предложили восполнить этот досадный пробел. Не хватает статей — вперед за перо!
Ну а рассматривать влияние статей (причем именно русскоязычных) о WPF и наличие коммерческих компонентов вообще забавно, причем здесь одно к другому На английском доступно масса материала по WPF вообще и по привязке данных в частности!
Это что получается, DevExpress не решается выпускать дополнительные компоненты только из-за того, что мало русскоязычных статей?
Здравствуйте, SergeyT., Вы писали:
ST>К тому же сейчас крайне мало коммерческих компонентов WPF (посмотри на тот же DevExpress). Поэтому мир WinForms будет жить еще долго, очень долго
Не вижу логики. Думаю это как раз показатель более совершенной системы, сторонние контролы практически не нужны.
Подход DM-V-VM мне кажется самым логичным и правильным способом работы с гуями.
А у сторонних разработкиков можно покупать только наборы стилей.
Здравствуйте, AK85, Вы писали:
ST>>К тому же сейчас крайне мало коммерческих компонентов WPF (посмотри на тот же DevExpress). Поэтому мир WinForms будет жить еще долго, очень долго
AK>Не вижу логики. Думаю это как раз показатель более совершенной системы, сторонние контролы практически не нужны. AK>Подход DM-V-VM мне кажется самым логичным и правильным способом работы с гуями. AK>А у сторонних разработкиков можно покупать только наборы стилей.
Это вы сейчас о чем?
Я всего лишь писал об актуальности тематики данной статьи для программиста, аргументируя это тем, что на данный момент большая часть приложений создается с использованием именно технологии Windows Forms. Кроме того, была замечена некомпетентность многих моих коллег в этом вопросе, отсюда и возникло желание в написание этой статьи.
При этом я не коим образом не собираюсь спорить о том, какая технология лучше или хуже.
Поэтому, о чем вы пишите, для меня совершенно не понятно?
Вероятно вы не совсем поняли суть нашего диалога
прочитал статью и задумался: насколько неудобными средствами порой приходиться оперировать. привязать форму к объекту? пишем код. привязать объект к форме? пишем код. не хотим больше писать код привязки — опять пишем код, да такой, что без поллитра не разберешься.
я уже скоро год как разрабатываю программы для MacOS, тамошний фреймворк Cocoa тоже умеет делать биндинг данных. интереса ради решил повторить пример с книгами из статьи — сделал почти весь мышкой. клавиатуру трогал только чтобы названия полей вписать.
там есть типовые контроллеры для привязки объектов, массивов, деревьев итп. указываешь тип хранимого объекта, привязываешь практически любой контрол и говоришь с каким из полей объекта он будет связан. все — мышкой. вместро хранимого объекта можно использовать словарь — даже класс данных описывать не придется. вещи типа главной и второстепенной таблицы (авторы — книги) делаются на раз: создаются два контроллера массивов, один привязывается к выбранному элементу другого.
если привязываешься к массиву данных, то становятся доступными аттрибуты аггрегирования — можно привязать текстовое поле к массиву и попросить его отображать кол-во записей в массиве. или сумму, среднее, минимум, максимум итп. мелочи, в принципе... но насколько все становится проще. особенно учитывая то, что все делается мышкой — код писать не надо (он и "автоматически" не пишется, в отличие от "делания мышкой" в студии).
механизм, лежащий в основе этого всего, достаточно прост. базовый объект, от которого все наследуются, позволяет:
1. поменять значение проперти по ее имени
2. подписаться на уведомления о таких изменениях какого-либо объекта
и то и другое осуществимо и в дотнете, но не без геморроя. думаю, фреймворку к пятому нам-таки будет предложен более-менее нормальный механизм биндинга
Здравствуйте, ov, Вы писали:
ov>и то и другое осуществимо и в дотнете, но не без геморроя. думаю, фреймворку к пятому нам-таки будет предложен более-менее нормальный механизм биндинга
Вряд ли. На осеннем PDC небыло ни одного доклада посвященного WinForms. Доработок каких то уже давно не видно и о новинках ничего не слышно. Похоже MS забили на винформс в угоду WPF.
С одной стороны WPF более правильный путь, но с другой, например, в моем случае аппаратное обеспечение большинства клиентов не позволяет использовать WPF для разработки приложений.
ov>>и то и другое осуществимо и в дотнете, но не без геморроя. думаю, фреймворку к пятому нам-таки будет предложен более-менее нормальный механизм биндинга A>С одной стороны WPF более правильный путь, но с другой, например, в моем случае аппаратное обеспечение большинства клиентов не позволяет использовать WPF для разработки приложений.
в Cocoa биндинг никак не завязан на интерфейс. вообще. интерфейс лишь пользуется этой возможностью фреймворка, не более того. если майкрософт на уровне класса System.Object это сделает — это можно будет использовать и в винформсе и в WPF и где угодно.
Здравствуйте, ov, Вы писали:
ov>в Cocoa биндинг никак не завязан на интерфейс.
Дык и в .NET практически аналогично. Механизмы связанные с обсуждаемым binding'ом только живут в сборках WPF ( + второй "экземпляр" в WWF ), но от UI им особо-то ничего и не нужно. В принципе можно использовать везде где хочется, только понимать механику надо, разумеется А так... Лишь бы target-свойство было DependencyProperty (и, соответственно, target-объект — наследником DependencyObject). Source же вообще может быть кем/чем/где угодно.
Конечно, хочется всё это прямо в язык запихать, но, полагаю, "малой кровью" не получится. Вообще надо будет подумать на досуге, как бы это провернуть с минимальными "потерями"... Ну а для начала, хотя бы просто отпилить всё это добро от WPF/WWF, и сделать нормальный более-менее универсальный механизм в том же стиле, что существует сейчас.
По ходу у меня становится традицией отписываться на статьи...
В нарушение традициии эта приятно порадовала — умеют же если захотят. Как всегда — пустые придирки к коду. Ничего серьёзного — это ж сампл, не продакшн. Не обращяйте внимания и пишите ещё
1) Мелочь:
public event EventHandler<EventArgs> AuthorChanged;
Зачем здесь генерик-версия? Кстати, правило хорошего тона — заодно реализовать INotifyPropertyChanged.
2) Совсем пустая придирка:
if (AuthorChanged != null)
AuthorChanged(this, EventArgs.Empty);
Выносится в отдельный метод. Да, проверка на нулл может не сработать при многопоточности. Перед проверкой кэшируйте в локальной переменной.
Во-первых, поаккуратнее с исключениями в конструкторе — лучше Factory сделать. Во-вторых сначала стоит проверить на свойства сорс и таргет, и только потом подписываться на события. Опять, где отписка?И почему CustomBinder не IDisposable?
5) А кто лайфтаймом биндингов управлять будет? Не, я понимаю, что оно будет жить вечно...
private void Bind()
{
CustomBinder authorPropertyManager =
new CustomBinder(authorTextBox, "Text", bookInfo, "Author");
CustomBinder titlePropertyManager =
new CustomBinder(titleTextBox, "Text", bookInfo, "Title");
CustomBinder isbnPropertyManager =
new CustomBinder(isbnTextBox, "Text", bookInfo, "ISBN");
CustomBinder pageCountPropertyManager =
new CustomBinder(pageCountTextBox, "Text", bookInfo, "PageCount");
CustomBinder publisherPropertyManager =
new CustomBinder(publisherTextBox, "Text", bookInfo, "Publisher");
}
Дальше есть ещё пара мелких косяков, наподобие непроверки IndexOf(...) на -1, если интересно — найдёте сами.
Здравствуйте, Sinix, Вы писали:
S>Выносится в отдельный метод. Да, проверка на нулл может не сработать при многопоточности. Перед проверкой кэшируйте в локальной переменной.
Проверка на null нафиг не нужна, делегаты неизменяемые объекты.
Здравствуйте, Sinix, Вы писали:
S>Доброго дня вам!
И вам!
S>По ходу у меня становится традицией отписываться на статьи...
S>В нарушение традициии эта приятно порадовала — умеют же если захотят. Как всегда — пустые придирки к коду. Ничего серьёзного — это ж сампл, не продакшн. Не обращяйте внимания и пишите ещё
Спасибо за отзыв, будем писать еще!
S>1) Мелочь: S>
S>Зачем здесь генерик-версия? Кстати, правило хорошего тона — заодно реализовать INotifyPropertyChanged.
По поводу generic-версии, не знаю ... как-то само собой получилось!
По поводу INotifyPropertyChanged. Этим примером я хотел показать двойственность привязки данных. Т.е. для того, чтобы работала двусторонняя привязка нужно реализовать события PropertyNameChanged или реализовать интерфейс INotifyPropertyChanged. Здесь вначале я выполняю только один из шагов, потом реализую и другой вариант, с реализацией интерфейса INotifyPropertyChanged.
S>2) Совсем пустая придирка: S>
S>Выносится в отдельный метод. Да, проверка на нулл может не сработать при многопоточности. Перед проверкой кэшируйте в локальной переменной.
Вы правильно заметили, что это не продакш код, поэтому отдельный метод только затруднит понимание кода. Опять же в контексте Windows Forms иногда точно известно, что подписка к событию и отписка от него происходит в потоке GUI, поэтому иногда такая проверка является излишней даже в продакш коде.
S>4) И ещё: S>
S>Во-первых, поаккуратнее с исключениями в конструкторе — лучше Factory сделать. Во-вторых сначала стоит проверить на свойства сорс и таргет, и только потом подписываться на события. Опять, где отписка?И почему CustomBinder не IDisposable?
Опять же код не продакшен, а educational
S>5) А кто лайфтаймом биндингов управлять будет? Не, я понимаю, что оно будет жить вечно... S>
Нет, вечно он жить не будет. Просто без студии, анализируя код статьи очень тяжело заметить управление временем жизни.
В конструкторе CusomBinder-а происходит следующий вызов:
if (dataSourcePropertyDescriptor.SupportsChangeEvents)
dataSourcePropertyDescriptor.AddValueChanged(dataSource, DataSourcePropertyChanged);
Т.е. this подписывается на событие, ссылка на this осталась в цепочке делегатов dataSourcePropertyDescriptor-а. Т.о. время жизни CustomBinder-а определяется временем жизни propertyDescriptor-а, время жизни которого, соответственно, определяется временем жизни соответствующего контролла. Грохнется контрол, все остальные объекты станут не достижимы и попадут под сборку мусора.
S>Дальше есть ещё пара мелких косяков, наподобие непроверки IndexOf(...) на -1, если интересно — найдёте сами.
Здравствуйте, Sinix, Вы писали:
S>Зачем здесь генерик-версия? Кстати, правило хорошего тона — заодно реализовать INotifyPropertyChanged.
"Заодно" неправильно, можно реализовать только один из подходов.
S>4) И ещё:
… S>Во-первых, поаккуратнее с исключениями в конструкторе — лучше Factory сделать.
А что такого плохого в "исключениях в конструкторе", что замена на фабрику исправит?
Help will always be given at Hogwarts to those who ask for it.
Здравствуйте, SergeyT!
ST>Нет, вечно он жить не будет. Просто без студии, анализируя код статьи очень тяжело заметить управление временем жизни. ST>В конструкторе CusomBinder-а происходит следующий вызов:
ST>
Если не отписываться, ссылка на подписчика живёт в эвент хандлере данных. Если данные живут дольше формы — вызываются обработчики событий на сдохшей форме с весьма вероятным эксепшном.
А код лучше сразу привыкать писать аккуратно, не переучишься...
2 _FRED_:
Насколько помню, МС Guidelines наоборот советуют реализовать и то и то. Прямые эвенты — для простых смертных, INotifyPropertyChanged — для биндинга. Ссылки не приведу — искать лень. Возможно и не прав...
Насчёт фабрик вместо конструктора — хз даже. Больше религия чем что либо ещё. В теории эксепшны низзя только ынутри статик конструкторов, что никак не затрагивает обычные... А, кажется дошло. Такой подход заставляет проверки делать до создания объекта, т.е. в теории кинуть эксепшн и оставить объект врассогласованном состоянии не получится. С другой стороны, даже если объект останется в рассогласованном указатель на него не ляжет в стек... Так что по-видимому просто религия