Эта статья будет
посвящена двум совершенно разным подходам к разработке прикладных программ на
основании WPF
(Windows Presentation Foundation) и Windows Forms (WinForms). Идея написания
статьи возникла после наблюдения за начинающими разработчиками, которые решают,
переходить им на WPF/XAML
или
нет. Основное их стремление изучать WPF основывается на том,
что эта технология становится сейчас очень популярной. А язык декларативной
разметки XAML (eXtensible
Application Markup
Language) позволяет писать код
как для WPF,
так и, например, к тому же Silverlight
или
для Windows
Phone.
Будучи ярым поклонником WPF
и
языка декларативной разметки XAML,
в данном контексте не буду прибегать к субъективизму, расхваливая некую
технологию, а постараюсь описать, в каких случаях применять тот или иной способ
разработки. Почему-то многие разработчики после перехода с Windows Forms на
WPF начинают критиковать Windows
Forms,
часто наблюдается и обратная реакция. Мне приходилось бывать в шкуре как
первых, так и вторых.
В первую очередь, стоит охладить пыл новичков, которые, увидев возможности визуального интерфейса WPF, начинают максимально использовать его, не думая о последствиях. Во-первых, использовать WPF или
Windows
Form
нужно
исходя из решаемой задачи. Если у Вас простой интерфейс на парочку кнопочек и
форм, то делайте задачу на том, на чем у Вас выйдет быстрее. В первую очередь анализируем то, что нужно реализовать, а затем делаем.
В этой статье, в отличие
от предыдущих, код будет приводиться по минимуму, а в основном текстовое
описание и рисунки для объяснения сути. Так как проверено на практике, что
пользователи и разработчики лучше воспринимают графическую информацию, нежели программный
код и текстовую информацию. Для примера отличия использования технологий WPF приведу пример создания кнопки со скругленными краями. Пример для Windows Forms взят
с книги “Чарльз Петцольд, Программирование с использованием Microsoft Windows forms”. Для WPF пример взят с книги Adam Nathan, Windows Presentation
Foundation Unleashed (WPF).
Пример круглой кнопки
на Windows
Forms:
namespace RoundButtonDemo
{
//-------------------------------------------
//
RoundButton.cs (c) 2005 by Charles Petzold
//-------------------------------------------
class RoundButton : Button
{
public RoundButton()
{
SetStyle(ControlStyles.UserPaint, true);
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
}
public override Size GetPreferredSize(Size szProposed)
{
// Base size on text string to be
displayed.
var grfx = CreateGraphics();
var szf = grfx.MeasureString(Text,
Font);
var iRadius = (int)Math.Sqrt(Math.Pow(szf.Width / 2, 2) +
Math.Pow(szf.Height / 2, 2));
return new Size(2 * iRadius, 2 * iRadius);
}
protected override void OnResize(EventArgs args)
{
base.OnResize(args);
// Circular region makes button
non-rectangular.
var path = new GraphicsPath();
path.AddEllipse(ClientRectangle);
Region = new Region(path);
}
protected override void OnPaint(PaintEventArgs args)
{
var grfx = args.Graphics;
grfx.SmoothingMode = SmoothingMode.AntiAlias;
var rect = ClientRectangle;
// Draw interior (darker if
pressed).
bool bPressed = Capture &
((MouseButtons & MouseButtons.Left) != 0) &
ClientRectangle.Contains(PointToClient(MousePosition));
var path = new GraphicsPath();
path.AddEllipse(rect);
var pgbr = new PathGradientBrush(path);
int k = bPressed ? 2 : 1;
pgbr.CenterPoint = new PointF(k * (rect.Left + rect.Right) / 3,
k * (rect.Top +
rect.Bottom) / 3);
pgbr.CenterColor = bPressed ? Color.Blue : Color.White;
pgbr.SurroundColors = new Color[] { Color.SkyBlue };
grfx.FillRectangle(pgbr, rect);
// Display border (thicker for default button)
Brush br = new LinearGradientBrush(rect,
Color.FromArgb(0, 0, 255), Color.FromArgb(0, 0, 128),
LinearGradientMode.ForwardDiagonal);
var pn = new Pen(br, (IsDefault ? 4 : 2) * grfx.DpiX / 72);
grfx.DrawEllipse(pn, rect);
// Draw the text centered in the
rectangle (grayed if disabled).
var strfmt = new StringFormat();
strfmt.Alignment =
strfmt.LineAlignment = StringAlignment.Center;
br = Enabled ? SystemBrushes.WindowText : SystemBrushes.GrayText;
grfx.DrawString(Text, Font, br,
rect, strfmt);
// Draw dotted line around text if
button has input focus.
if (Focused)
{
var szf = grfx.MeasureString(Text,
Font, PointF.Empty,
StringFormat.GenericTypographic);
pn = new Pen(ForeColor);
pn.DashStyle = DashStyle.Dash;
grfx.DrawRectangle(pn,
rect.Left + rect.Width / 2
- szf.Width / 2,
rect.Top + rect.Height / 2
- szf.Height / 2,
szf.Width, szf.Height);
}
}
}
}
Как это
выглядит на экране:
Пример круглой кнопки
на WPF:
<Window x:Class="RoundButtonWpfDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<Grid.Resources>
<ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
<Grid>
<Ellipse x:Name="outerCircle" Width="100" Height="100">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="Blue"/>
<GradientStop Offset="1" Color="Red"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Ellipse Width="80" Height="80">
<Ellipse.Fill>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Offset="0" Color="White"/>
<GradientStop Offset="1" Color="Transparent"/>
</LinearGradientBrush>
</Ellipse.Fill>
</Ellipse>
<Viewbox>
<ContentControl Margin="30" Content="{TemplateBinding Content}"/>
</Viewbox>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="outerCircle" Property="Fill" Value="Orange"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX=".9" ScaleY=".9"/>
</Setter.Value>
</Setter>
<Setter Property="RenderTransformOrigin" Value=".5,.5"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Grid.Resources>
<Button Template="{StaticResource buttonTemplate}">OK</Button>
</Grid>
</Window>
Результат:
Больше
примеров кода не будет. Только рисунки и диаграммы. Для начала рассмотрим, в
чем отличие этих двух подходов.
На рисунке изображены
подходы с использованием WPF
и
Windows
Forms.
Описание этих двух подходов будет основываться на собственном опыте написания
корпоративных приложений на основе паттернов MVP/MVVM. Если у Вас большой промышленный проект,
написанный на WPF
или
Windows
Forms, и вся логика написана во view
и
представляет собой несколько тысяч строк кода, подумайте о том, чтобы
использовать паттерны MVP
для Windows
Forms
и
MVVM
для
WPF. Если Вы просто перейдете с таким
подходом с Windows
Forms
на WPF, у Вас появится множество возможностей существенно подпортить репутацию проекта. На WPF написать
плохой интерфейс и код намного легче, чем на Windows Forms. Поэтому еще раз настоятельно
рекомендую: если Вы не знакомы с одним из этих паттернов, при программировании
для используемой в данный момент технологии, то при переходе на другую
технологию пробелы в знаниях и корявый код перенесутся на другую технологию.
Приведу цитату Мартина Голдинга: «Всегда пишите код так,
будто сопровождать его будет склонный к насилию психопат, который знает, где вы
живете». Итак, надеясь, что Вы осознанно подходите к выбору новой
технологии, приступим к дальнейшему описанию технологий, описанных выше.
Рассмотрим для начала подход для разработки прикладных приложений на Windows Forms.
Windows
Forms
Подход
к разработке прикладных программ на Windows Forms основывается
на графическом интерфейсе GDI
(Graphics
Device Interface, Graphical Device Interface) - это интерфейс
Windows для представления графических объектов и передачи их на устройства
отображения, такие как мониторы и принтеры.
GDI
отвечает за отрисовку линий и кривых, отображение шрифтов и обработку палитры.
Он не отвечает за отрисовку окон, меню и т.п., эта задача закреплена за
пользовательской подсистемой, располагающейся в user32.dll и основывающейся на
GDI.
Одно
из преимуществ Windows
Forms
-
в том, что на нем можно писать коссплатформенные приложения. Простые проекты,
написанные на Windows
Forms,
можно довольно легко перенести на другую операционную систему, если на ней
установлен .Net
Framework
нужной
модели, на котором написан Ваш проект. Выглядит это действительно впечатляюще,
но на практике очень часто проект не будет работать. Особенно при использовании
посторонних контролов, написанных другой компанией. Например, DevExpress, Telerik, MailBee и
т.д. С вероятностью 90% Ваш проект не заработает с первого раза. Возможно, у Вас
получится со временем привести проект к нужному виду. Но это будет стоить очень
много времени. Поэтому если вдруг Вы решили все-таки писать кроссплатформенное
приложение на С#,
посмотрите в сторону Mono,
Gtk
или
новый фреймворк, который сейчас становится популярным -
Xamarin(для мобильных приложений). Поэтому лучше
остановить выбор на QT/C++ или Java. Но если Вы не знакомы с этими
языками, вам останется выбрать один из вариантов, предложенных мной выше, либо
использовать какой-то другой известный Вам подход.
Рассмотрим
паттерн Model-View-Presenter (MVP), который часто используют для Windows Forms. MVP -
шаблон проектирования пользовательского интерфейса, который был разработан для
облегчения автоматического модульного тестирования и улучшения разделения ответственности в
презентационной логике (отделения логики от отображения):
- Модель (Model) представляет собой интерфейс, определяющий данные для отображения или участвующие в пользовательском интерфейсе иным образом.
- Представление (View) - это интерфейс, который отображает данные (Модель) и маршрутизирует пользовательские команды (или события) Presenter-у, чтобы тот действовал над этими данными.
- Presenter действует над Моделью и Представлением. Он извлекает данные из хранилища (Модели) и форматирует их для отображения в Представлении.
На схемее ниже показано графическое
представление MVP.
На данный момент
контролы для Windows
Forms
по
количеству превосходят WPF
контролы
в несколько раз. Это связано, в первую очередь, с тем, что Windows Forms появился
в .Net
Framework
2.0
, а WPF
-
в .Net
Framework
3.0. Разрабатывать приложения на Windows Forms очень
просто. Для визуального интерфейса в основном большая часть логики связана с
перетаскиванием нужных контролов на форму.
WPF
Подход
к разработке прикладных программ на Windows Presentation Foundation (WPF) основан на DirectX. Весь код
транслируется в код для трансляции в DirectX с помощью библиотеки milcore.dll. В основе WPF лежит векторная
система визуализации, не зависящая от разрешения устройства вывода и созданная
с учётом возможностей современного графического оборудования. WPF предоставляет
средства для создания визуального интерфейса, включая язык XAML (Extensible
Application Markup Language), элементы управления, привязку данных, макеты,
двухмерную и трёхмерную графику, анимацию, стили, шаблоны, документы, текст,
мультимедиа и оформление.
Графической
технологией, лежащей в основе WPF, является DirectX, в
отличие от Windows Forms, где используется GDI/GDI+.
Производительность WPF
выше, чем у GDI+,
за счёт использования аппаратного ускорения графики через DirectX. С помощью XAML мы
можем создавать визуальное
представление
(view),
по сути, на xml
-
подобном
языке с мощными возможностями. Приложения на WPF не
являются переносимыми и могут быть использованы только в операционной системе Windows. Для написания
корпоративных решений используется паттерн MVVM (Model-View-ViewModel) предназначен для
создания приложений для WPF/Silverlight. Основная особенность
данного паттерна заключается в том, что весь код с View(представления) выносится в ViewModel (модель
представления), а вся привязка осуществляется черед байндинг, прописанный в XAML-разметке. Для простоты работы с MVVM был
разработан MVVM Toolkit , который включает шаблон для Visual Studio и
позволяет использовать данный паттерн без особых усилий. Если Вы не знакомы с
данным паттерном, рекомендую ознакомиться с моей статьей "Основы паттерна MVVM". Благодаря этому
паттерну в приложении WPF
можно
разделить реализацию интерфейса и логики. Реализаций интерфейса могут
заниматься дизайнеры на инструменте Expression Blend (либо
во встроенном редакторе студии), а программисты будут заниматься исключительно
логикой работы программы. Как выглядит представление паттерна MVVM, можно увидеть ниже на рисунке.
WPF предоставляет
мощную систему байндинга, которая намного мощнее используемой в Windows Forms. Сейчас пришла пора объяснить код
с овальной кнопкой, приведенный в начале статьи. В отличие от Windows Forms, для того, чтобы сделать
нестандартный интерфейс в каком либо существующем контроле, не нужно создавать
новый контрол. Достаточно для этой кнопки сделать новый стиль и привязать его к
данному контролу через свойство Template.
Это намного удобнее, чем в WPF.
Но в большинстве случаев не нужно перерисовывать внешний вид контрола, в таких
случаях полностью подойдет Windows
Forms.
WPF
имеет
также преимущество перед Windows
Forms
в
поддержке 2D/3D объектов. Также WPF имеется
мощный инструмент для работы с анимацией через XAML код.
В Windows
Forms
простая
анимация обычно требует
объект таймер и отрисовки нужной информации по событию tick этого
таймера. Еще одно достоинство -
работа
с аудио, видео и голосом.
Итоги
В данной статье я
постарался описать сравнение двух подходов к разработке прикладного
программного обеспечения, основываясь на подходе с использованием Windows Forms и WPF. При усилиях быть объективным к этим
технологиям разработки, WPF
в
материале получилась все же более восхваленная, чемWindows Forms. Возможно, аргументом в пользу
этого будет тот факт, что WPF
имеет
намного больше возможностей по написанию программ, чем Windows Forms. Прежде чем выбрать какую то
технологию для разработки, нужно проанализировать, что Вам больше подходит по
дизайну. Если в Вашем приложении простой дизайн, то WPF в этом случае, по сути, незачем.
Также нужно учитывать скорость разработки продукта на первой и второй
технологии. Если на Windows
Forms
это займет у Вас 3 дня, а наWPF
-
7 дней, то не имеет смысла использовать WPF. То же самое касается паттернов MVP/MVVM: если у Вас приложение, которое
занимает несколько дней для разработки, и если Вы неопытный разработчик, то
применение данных паттернов только отсрочит написание проекта. У опытных
разработчиков же либо есть наработки, либо они могут взять какой-то из MVVM-тулкитов для построения своего
приложения.
No comments:
Post a Comment