Урок 3: User Control, Forms(модальные и не модальные) и Drag&Drop
Сначало немного разъяснения. В Silverlight’e отсутствуют формы (диалоговые окна). Поэтому мы получим их функциональность, используюя юзер контролы и драгндроп.
Создадим проект Silverlight и файл страницы приведем к следующему виду:
Думаю, что тут недолжно вознуть никаих трудностей, не забудьте – поменяйте родительсктй класс страницы.
А вот далее, мы создадим Silverlight user control, а именно: зайдем в меню Project->Add New Item->Silverlight user control, и назовем новый файл Form.xaml.
Среда Вам создала юзер контрол ну ОЧЕНЬ похожий с тем, который нам генерится при новом Silverlight проекте. Поэтому не долго думаюя, и поменяв родительский класс, мы слегка рихтуем сгенерированый файл xaml, до необходимого нам вида:
Этим мы придали нашему Silverlight user contol’у внешний вид формы. Создали две таблицы – строчки 1-22 и 10-18.
1-22 Это вся наша форма разделенная на header(заголовок) и клиентское место под контролы.
В строках 10-18 мы заголовок нашей таблицы разбиваем на две части (вставив новую таблицу), и добавляем туда название формы и кнопку. обратите внимание, что в строке 9 мы определили рамку с синим цветом заливки заголовка формы и назначили ей имя. Это нам понадобится для перетаскивания формы, чтобы мы могли таскать форму ТОЛЬКО за заголовок.
Если мы сейчас сбилдим проект мы ничего не увидим, т.к. на основную страницу мы не добавили наш контрол( форму). Для этого делаем следующее:
1) ОБЯЗАТЕЛЬНО сохраним или сбилдим проект иначе мы из основной формы не увидим нашу новую форму
2) В файл page.xaml мы должны добавить область видимости всей программы. Для этого в заголовок надо добавить:
Просто советую – начнете набирать – после xmlns выберите из выпадающего списка область видимости, а уже ПОТОМ добавлаете имя области видимости, в нашем случае это My_Namespace (кстати можете назвать как вам будет удобно).
3) И, собственно, добавление контрола на основную форму, для этого просто начинаете набирать тег нашей области видимости и если Вы все правильно сделали и сохранились перед этим – Вам выпадет название класса нашего юзер контрола в качестве возможного тега:
Собственно и все. Правда, видите, мы не указывали координаты нашего контрола, поэтому он расположился в начале координат нашей страницы. И кроме того мы его пока скрыли – добавив свойство Visibility=”Collapsed”.
А вот теперь, мы сделаем так, чтобы при нажатии на кнопку у нас высвечивалась наша новая форма.
Кнопочу зарытия на нашей форме помните? Сделаем так чтобы она закрывала нашу форму (в файле Forms.xaml.cs):
Теперь наша форма показывается и скрывается. Обратите внимание на ТРИ момента с формами такого типа:
1) Они создаются при старте приложения и уничтожаются при зарытии приложения. Они находятся в памяти – их просто НЕ ВИДНО.
2) В функции закрытия скрывать по логике должно объект sender, то есть – кнопку, а закрывает весь контрол. Пока не разобрался почему – может кто объяснит? Зарание спасибо
3) Обратите внимаение с каким Z ордером у вас вводится на страницу ваша форма чтобы не было перекрытия.
Собственно, осталось только добавить нам перетаскивание нашей формы мышкой. Очень подробно это описано в документации SDK. Нам же просто достаточно добавить к нашей форме три фунции:
И собственно тела функций обработки этих событий. (ДОБАВТЕ ВЫСОТУ ДЛЯ КОНТРОЛА С ИМЕНЕМ Header – иначе не заработает):
Собственно билдим и наслаждаемся нашей маленькой формочкой:
Если у Вас возникнет желание сделать ресайз формы – просто добавте по контуру формы патч. И обработайте событие аналогично драгндропу.
А что же делать если нам необходима модальная форма? Очень просто добавте просто прямоугольник который не даст доступа к основной странице. подробности здесь. Добавлю просто, что можно сделать полную прозрачность и добавить перетаскивание – очень не плохо смотрится.
7 comments so far
Ответить









C интересом читаю все уроки по сервелату
Однако, в случае с модельными окнами возникает интересная бага: если в главном окне существует DataGrid и в него добавляются данные, то свойство Collapced модельного окна – не работает, и оно отображается сразу после загрузки данных в ДатаГрид. Причем, не работает даже явное указание сокрытия окна сразу после закрытия данных.
Привожу проект на котором удалось выловить багу: http://dump.ru/file_catalog/674940
Может кто знает как это обойти?
МодАльного, конечно же… Извините, кажется автозамена срабатывает
.
Однозначно это не баг. Скорее всего дело вот в этом: GotFocus=”LongersMain_Loaded” в теге Grid page.xaml
Суть в чем – когда ваш Grid получает фокус вы заполняете его данными, а я не знаю как на это реагирует заполняемый контрол DataGrid, вполне возможно что он АВТОМАТИЧЕСКИ выбирает селектед итемз, а у вас в следующей строке присвоена функия показывать окно при смене селектед итемза в дата гриде.
Дело в том, что это логически не правельно выстроеная “силвелат” программа. Xaml это сборка интерфейса, поэтому Xaml и С# файлы выполняются НЕОДНОВРЕМЕННО! Вам надо ДИНАМИЧЕСКИ, в файле page.xaml.cs назначить фунцию для обработки смены фокуса в датагриде(см. делегаты). Но я не сильный советчик
– все таки как ни как чайник.
Или пересмотреть логику самой программки.
Назначать делегат надо после загрузки данных.
И попробуйте для удобства в теги основного контрола страницы добавить MinWidth=”400″ MinHeight=”300″, убрав при этом просто высоту и ширину. Это позволит в дизайне нормально работать, а рантайме растягивать на весь браузер. – Всплывет баг(масенький такой), просто у Вас немодальная форма – за ней на гриде селектятся строки. Надо еще полупрозрачный прямоугольник натянуть: http://ruspiegel.net/?p=509.
То что было выложено – это лишь тестовый пример для отлова бага. В рабочем проекте с модальным окном и областью доступности все в порядке
Проведенные изыскания обнаружили, что бага существует, но несколько иного рода, и, конечно же, отношения к Collapsed не имеет. Суть заключается в том, что в ДатаГриде не меняется свойство . Что бы не выбиралось – все равно будет -1. Вот что удалось нарыть: http://silverlight.net/forums/p/18353/61732.aspx
Видимо по этой причине динамическая подписка на события не помогает. Событие возникает всегда, вне зависимости от того, было ли значение DataGrid.SelectedItem изменено.
GridLongers.ItemsSource = source;
GridLongers.SelectionChanged += new EventHandler(GridLongers_SelectionChanged);
Как следствие, использовать следующий код (который первым приходит в голову) невозможно.
if(GridLongers.SelectedIndex !=-1)
Detail.Visibility = Visibility.Visible;
(Detail – модальная форма)
Однако, это еще не все сюрпризы которые имеются в связке DataGrid и модальных формах. Сейчас модифицирую проект, чтоб продемонстрировать странный эффект.
http://dump.ru/file_catalog/680430
В этот тестовом проекте генерируется список телефонов, выводится в DataGrid на главную форму. При изменении выделенной записи происходит вызов модального окна.
Обратите внимание, что в TexBox актуальные значения из выделенной записи отображаются сразу после вызова окна, а в DataGrid вызываются “старые значения”, и обновление происходит только после нажатия и удерживания кнопки закрытия модального окна (при потере фокуса?).
Не знаю с чем связано но мне победить баг не удалось – остальные контролы коректно отрабатывают связывание данных. Побовал даже принудительно фокус вешать на ворму и дочерние контролы – не помогло. Будем надеятся, что в релизе исправят.
А реализовывать через лист бокс не пробовали? Мне почему-то кажется что должно выличить.