Спонсор: Microsoft
Опубликован: 13.12.2011 | Доступ: свободный | Студентов: 982 / 29 | Оценка: 4.29 / 4.57 | Длительность: 13:56:00
Лекция 10:

Проектирование приложения с учетом использования единого опыта разработки для настольных и Web-проектов

Конструкторы по умолчанию для геометрий

Первое, на что придется обратить внимание при работе с геометриями в Silverlight после WPF – отсутствие перегруженных конструкторов. Поэтому, если в WPF было возможно написать:

RectangleGeometry rectangle = new RectangleGeometry(new Rect(10, 10, 50, 40));

то для совместимости WPF/Silverlight данный код придется изменить на:

   1: RectangleGeometry rectanble = new RectangleGeometry()
   2: {
   3:     Rect = new Rect(10, 10, 50, 40)
   4: };

что занимает не намного больше строк в файле, но зато работает как в Silverlight, так и в WPF.

Отсутствие свойства PathSegment.IsStroked

IsStroked позволяет указать, что данный сегмент последовательности линий не должен отображаться. Так, в WPF можно задать следующую последовательность:

Простая последовательность линий

Рис. 15.7. Простая последовательность линий

при помощи данной XAML разметки:

   1: <Path Stroke="Black" StrokeThickness="3">
   2:     <Path.Data>
   3:         <PathGeometry>
   4:             <PathFigure StartPoint="0,20">
   5:                 <LineSegment Point="20,0" />
   6:                 <LineSegment Point="40,20" />
   7:                 <LineSegment Point="60,20" IsStroked="False" />
   8:                 <LineSegment Point="80,0" />
   9:                 <LineSegment Point="100,20" />
  10:             </PathFigure>
  11:         </PathGeometry>
  12:     </Path.Data>
  13: </Path>

Несложно догадаться, что в Silverlight данная разметка будет некорректной. Для простых случаев, таких как приведенный выше, возможно обойти это ограничение при помощи простого разделения PathFigure на несколько фигур (по одной на каждый сегмент без разрывов):

   1: <Path Stroke="Black" StrokeThickness="3">
   2:     <Path.Data>
   3:         <PathGeometry>
   4:             <PathFigure StartPoint="0,20">
   5:                 <LineSegment Point="20,0" />
   6:                 <LineSegment Point="40,20" />
   7:             </PathFigure>
   8:             <PathFigure StartPoint="60,20">
   9:                 <LineSegment Point="80,0" />
  10:                 <LineSegment Point="100,20" />
  11:             </PathFigure>
  12:         </PathGeometry>
  13:     </Path.Data>
  14: </Path>

Для эмуляции поведения IsStroked в коде можно воспользоваться методом-расширением, имеющим различные реализации в Silverlight и WPF:

   1: public static void AddLineSegment
   2:	(this PathGeometry pathGeometry, Point point, bool isStroked)
   3: {
   4:     PathFigure figure = 
   5:		pathGeometry.Figures[pathGeometry.Figures.Count - 1];
   6:  
   7: #if SILVERLIGHT
   8:     if (isStroked)
   9:     {
  10:         figure.Segments.Add(new LineSegment { Point = point });
  11:     }
  12:     else
  13:     {
  14:         // Silverlight has no IsStroked property on LineSegment
  15:         // so we create a new PathFigure to imitate non-stroked
  16:	 	// line segment
  17:         figure = new PathFigure();
  18:         figure.StartPoint = point;
  19:         pathGeometry.Figures.Add(figure);
  20:     }
  21: #else
  22:     figure.Segments.Add(new LineSegment(point, isStroked));
  23: #endif
  24: }

Такой метод удобен при создании последовательностей линий в коде:

myPathGeometry.AddLineSegment(myPoint, true);

Этот метод может также быть обобщен на другие типы PathSegment, что можно считать небольшим дополнительным заданием.

Таким приемом можно пользоваться в достаточно простых случаях, однако проблему в следующем примере обойти уже не так тривиально:

 Последовательность линий с заливкой

Рис. 15.8. Последовательность линий с заливкой

В случае WPF такая фигура задается разметкой:

   1: <Path HorizontalAlignment="Center" VerticalAlignment="Center"
   2:     Stroke="Black" Fill="LightGreen" StrokeThickness="3">
   3:     <Path.Data>
   4:         <PathGeometry>
   5:             <PathFigure StartPoint="0,40">
   6:                 <LineSegment Point="0,20" IsStroked="False" />
   7:                 <LineSegment Point="20,0" />
   8:                 <LineSegment Point="40,20" />
   9:                 <LineSegment Point="60,20" IsStroked="False" />
  10:                 <LineSegment Point="80,0" />
  11:                 <LineSegment Point="100,20" />
  12:                 <LineSegment Point="100,40" IsStroked="False" />
  13:             </PathFigure>
  14:         </PathGeometry>
  15:     </Path.Data>
  16: </Path>

К сожалению, для достижения такого же эффекта в Silverlight приходится использовать 2 независимые пересекающиеся последовательности – одну для заливки, и другую для собственно отображения линий:

   1: <Path Fill="LightGreen" StrokeThickness="3">
   2:     <Path.Data>
   3:         <PathGeometry>
   4:             <PathFigure StartPoint="0,40">
   5:                 <LineSegment Point="0,20"/>
   6:                 <LineSegment Point="20,0" />
   7:                 <LineSegment Point="40,20" />
   8:                 <LineSegment Point="60,20"/>
   9:                 <LineSegment Point="80,0" />
  10:                 <LineSegment Point="100,20" />
  11:                 <LineSegment Point="100,40" />
  12:             </PathFigure>
  13:         </PathGeometry>
  14:     </Path.Data>
  15: </Path>
  16:  
  17: <Path Stroke="Black" StrokeThickness="3">
  18:     <Path.Data>
  19:         <PathGeometry>
  20:             <PathFigure StartPoint="0,20">
  21:                 <LineSegment Point="20,0" />
  22:                 <LineSegment Point="40,20" />
  23:             </PathFigure>
  24:             <PathFigure StartPoint="60,20">
  25:                 <LineSegment Point="80,0" />
  26:                 <LineSegment Point="100,20" />
  27:             </PathFigure>
  28:         </PathGeometry>
  29:     </Path.Data>
  30: </Path>

Очевидно, что для написания совместимой WPF/Silverlight разметки во всех подобных случаях придется использовать Silverlight вариант.

Краткие итоги

В данной теме были рассмотрены рекомендации к организации проектов, позволяющих разделять Silverlight и WPF код, разобраны особенности архитектуры таких приложений, а также описаны наиболее часто встречающиеся проблемы и способы их решения. Написание кроссплатформенного WPF/Silverlight приложения, безусловно, требует больших усилий, чем раздельная разработка, однако отсутствие необходимости поддерживать 2 различные версии приложения позволяет существенно упростить дальнейшую доработку и сопровождение.

Набор для практики

Вопросы:

  1. Подходы к решению вопроса о разработке Silverlight/WPF приложений с максимальным разделением общего кода. Плюсы и минусы каждого.
  2. Создание ссылок в Visual Studio
  3. Директивы препроцессора
  4. Способы решения проблем недостающего функционала
Игорь Ключников
Игорь Ключников
Россия
Михаил Ковязо
Михаил Ковязо
Россия, Москва, ВЗМИ, 1982