На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
Модераторы: maxim84_, juice
  
> переход с WindowsForms на WPF, зачем это надобыло мне на примерах
    По просьбам товарищей с форума приведу некоторые аргументы, сугубо по моему мнению, почему WPF более удобней и функциональней чем WindowsForms. А начну я свое сравнений с небольшой цитаты с форума RSDN, ибо лучше и лаконичней выразиться вероятно у меня не получиться.
    Цитата

    Преимущества для меня:
    1. Декларативность. Писать в XAML реально нагляднее и удобнее.
    2. Свойства зависимостей и маршрутизируемые события. Такого хотелось очень давно, наконец оно есть.
    3. Шаблоны. Здесь лучше смотреть примеры. На, мой взгляд, уже одна эта фича кладет WinForms и WinAPI на обе лопатки.
    4. Простая и в то же время мощная система биндингов с возможностью соединять большинство свойств в обе стороны.
    5. Встроенная анимация на основе свойств. Оно действительно работает классно.
    Вообще можно перечислить еще много чего. Лучше глянуть какой-нибудь Overview и понять, подходит или нет. Лично я еще ни разу не пожалел о переходе на WPF и обратно на WinForms не тянет соооовсем.

    А теперь попробую долить воды на эту раскручивающуюся мельницу. Во первых я не хочу в этой статье рассказывать про то как происходит отрисовка элементов форм в GDI и WPF так как этому посвящено множество слов в различной литературе и статьях посвященных WPF, а попробую рассмотреть все с практической стороны.
    Во первых одна из основных целей при разработке приложений я считаю что это разработка масштабируемого и понятного кода. Что нам дает с этой стороны WindowsForms? Ну во первых это широко принятый стиль смешивать в коде формы все на свете: логику и обработку данных, работу с источниками данных, заполнение полей и контролов. В итоге мы получаем полную кашу из кода взглянув на который спустя некоторое время приходишь в ужас, потому как добавление дополнительного функционала приводит к переписыванию кучи кода. Возможно я немного преувеличиваю, но из всего что я видел так и не увидел красивого и масштабируемого кода, да и у самого не особо получалось. А WPF с другой стороны решает часть этих проблем. Рассмотрим пример:

    WindowsForms
    ExpandedWrap disabled
      namespace WinFormsSample
      {
          public partial class MainForm : Form
          {
              public MainForm()
              {
                  InitializeComponent();
                  textBox1.Text = "test";
              }
          }
      }


    и WPF
    ExpandedWrap disabled
      <Window x:Class="WPF_Sample.Window1"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="WPF_Sample" Height="300" Width="300"
          >
          <Grid>
              <Grid.RowDefinitions>
                  <RowDefinition Height="Auto"/>
                  <RowDefinition Height="*"/>
                  <RowDefinition Height="Auto"/>
              </Grid.RowDefinitions>
              <TextBox Text="{Binding TextData}"/>
          </Grid>
      </Window>

    ExpandedWrap disabled
      namespace WPF_Sample
      {
          public partial class Window1
          {
              public string TextData { get; set; }
              public Window1()
              {
                  InitializeComponent();
                  TextData = "test";
                  DataContext = this;
              }
          }
      }

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

    ExpandedWrap disabled
      <?xml version="1.0" encoding="utf-8"?>
      <Window
          x:Class="WPF_Sample.Window1"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="WPF_Sample"
          Height="300"
          Width="300">
          <Grid>
              <Grid.Resources>
                  <!--заготовка детализованного отображения списка-->
                  <ControlTemplate x:Key="Selected" TargetType="{x:Type ListViewItem}">
                      <Border Background="LightYellow" BorderBrush="Black"
                          BorderThickness="1" CornerRadius="5">
                          <StackPanel>
                              <GridViewRowPresenter
                                  TextBlock.FontWeight="Bold"
                                  Content="{TemplateBinding Content}"
                                  Columns="{TemplateBinding GridView.ColumnCollection}" />
                              <StackPanel
                                  Orientation="Vertical">
                                  <DockPanel>
                                      <TextBlock FontWeight="Bold" Margin="5">Длина</TextBlock>
                                      <TextBlock Text="{Binding Param1}" VerticalAlignment="Center"/>
                                  </DockPanel>
                                  <DockPanel>
                                      <TextBlock FontWeight="Bold" Margin="5">Материал</TextBlock>
                                      <TextBlock Text="{Binding Param2}" VerticalAlignment="Center"/>
                                  </DockPanel>
                              </StackPanel>
                          </StackPanel>
                      </Border>
                  </ControlTemplate>
              </Grid.Resources>
              <Grid.RowDefinitions>
                  <RowDefinition Height="Auto" />
                  <RowDefinition Height="*" />
                  <RowDefinition Height="Auto" />
              </Grid.RowDefinitions>
              <TextBox
                  Text="{Binding TextData}" />
              <!--описываем таблицу и указываем связь с коллекцией данных-->
              <ListView Grid.Row="1" ItemsSource="{Binding Data}">
                  <ListView.View>
                      <!--задатем тип отображения списка-->
                      <GridView>
                          <!--описываем колонки таблицы и указываем связи с полями объекта-->
                          <GridViewColumn Width="160" DisplayMemberBinding="{Binding Name}" Header="Наименование" />
                          <GridViewColumn Width="80" DisplayMemberBinding="{Binding Qty}" Header="Кол-во" />
                          <GridViewColumn Width="80" DisplayMemberBinding="{Binding Price, StringFormat=c, ConverterCulture='Ru-ru'}" Header="Цена" />
                      </GridView>
                  </ListView.View>
                  <ListView.ItemContainerStyle>
                      <Style
                          TargetType="{x:Type ListViewItem}">
                          <Style.Triggers>
                              <!--стили отображения описанные в простеньком триггере-->
                              <Trigger Property="IsSelected" Value="True">
                                  <!--триггер показывающий детализацию объекта при выборе в списке-->
                                  <Setter Property="Template" Value="{StaticResource Selected}" />
                              </Trigger>
                              <!--триггеры разукрашивающие строки в зависимости от способа поставки, в упаковке или нет-->
                              <DataTrigger Binding="{Binding IsPackaged}" Value="True">
                                  <Setter Property="Background">
                                      <Setter.Value>
                                          <LinearGradientBrush EndPoint="0.494,0.889" StartPoint="0.494,0.028">
                                              <GradientStop Color="#2299FF99" Offset="0" />
                                              <GradientStop Color="#FF99FF99" Offset="1" />
                                          </LinearGradientBrush>
                                      </Setter.Value>
                                  </Setter>
                              </DataTrigger>
                              <DataTrigger Binding="{Binding IsPackaged}" Value="False">
                                  <Setter Property="Background">
                                      <Setter.Value>
                                          <LinearGradientBrush EndPoint="0.494,0.889" StartPoint="0.494,0.028">
                                              <GradientStop Color="#3FFF1111" Offset="0" />
                                              <GradientStop Color="#FFFF9999" Offset="1" />
                                          </LinearGradientBrush>
                                      </Setter.Value>
                                  </Setter>
                              </DataTrigger>
                          </Style.Triggers>
                      </Style>
                  </ListView.ItemContainerStyle>
              </ListView>
          </Grid>
      </Window>

    ExpandedWrap disabled
      namespace WPF_Sample
      {
          public partial class Window1 : Window
          {
              public string TextData { get; set; }
              
              public ObservableCollection<SomeData> Data { get; set; }
              
              public Window1()
              {
                  InitializeComponent();
                  TextData = "test";
                  //здесь мы эмулируем генерацию и обработку данных
                  Data = new ObservableCollection<SomeData>
                  {
                      new SomeData {Name = "Винт М8", Qty = 100, Price = 5, Param1 = "20 mm", Param2 = "Сталь", IsPackaged = true},
                      new SomeData {Name = "Винт М8", Qty = 100, Price = 7, Param1 = "25 mm", Param2 = "Нержавейка", IsPackaged = true},
                      new SomeData {Name = "Винт М10", Qty = 100, Price = 7, Param1 = "30 mm", Param2 = "Сталь", IsPackaged = false},
                      new SomeData {Name = "Винт М10", Qty = 100, Price = 12, Param1 = "40 mm", Param2 = "Нержавейка", IsPackaged = true},
                      new SomeData {Name = "Винт М12", Qty = 100, Price = 14, Param1 = "30 mm", Param2 = "Сталь", IsPackaged = false},
                      new SomeData {Name = "Винт М12", Qty = 100, Price = 16, Param1 = "60 mm", Param2 = "Нержавейка", IsPackaged = false},
                      new SomeData {Name = "Винт М14", Qty = 100, Price = 44, Param1 = "50 mm", Param2 = "Сталь", IsPackaged = false},
                      new SomeData {Name = "Винт М14", Qty = 100, Price = 67, Param1 = "55 mm", Param2 = "Нержавейка", IsPackaged = true}
                  };
                  DataContext = this;
              }
          }
          
          public class SomeData
          {
              public string Name { get; set; }
              public int Qty { get; set; }
              public decimal Price { get; set; }
              
              public string Param1 { get; set; }
              public string Param2 { get; set; }
              
              public bool IsPackaged { get; set; }
          }
      }


    Как видно из приведенного примера в XAML коде мы можем уместить все описание представления, а в коде формы остается чистая работа с данными. Код данного примера я прикреплю к топику чтобы вы сами могли поэкспериментировать. Пока этим примером я завершу данную статью, потому как рассказать еще много чего хочется но сваливать все в одну кучу не очень хочется. Далее хотелось бы описать принцип паттерна MVC и рассмотреть пример его использования в WindowsForms и WPF. Скажу еще одно, в данном примере я немного схитрил (лишь ради того чтобы не загромождать код), те кто читал мою статью про WPF Binding поймут о чем я, а кто не читал рекомендую прочитать, там описывается интерфейс INotifyPropertyChanged и динамическое обновление данных.
    Истина где-то рядом!?!
      Спасибо, Pit-Bul, за статью.
      А теперь пара слов о том, почему НЕ надо переходить на WPF, в качестве дежурной ложки дёгтя. :)
      Кратко, осовываясь на собственном опыте.

      1. Нужен дизайнер. У "чистого" программиста, как правило, больше шансов сделать плохой интерфейс на WPF, чем на WinForms.
      2. Меньше сторонних контролов. Под WinForms разработаны тонны, тонны контролов всяких полезных, а под WPF - чуть поменьше. Ситуация выправляется со временем - причём, с платными контролами она выправляется быстрее, чем с бесплатными.
      3. Требование .Net 3.5. Это ужастно, но он ещё неу всех есть. Реально массовый, увы, пока второй. Тоже со временем исправится, конечно.

      Не буду разжовывать эти пункты, но предлагаю читателю просто поразмыслить над ними.
      Сам я считаю, что плюсы WPF с лихвой перевешивают перечисленные (и забытые) мной минусы, но если задумаетесь о переходе - обязательно оцените, не являются ли эти минусы критичными в вашем проекте.
      Сообщение отредактировано: Alexus -
      ... А сегодня что для завтра сделал я?

      Brainbench Transcript ID#: 7848137
        прикрепляю забытые примеры

        Прикреплённый файлПрикреплённый файлWPF_Sample_F4.zip (45,25 Кбайт, скачиваний: 353)
        Прикреплённый файлПрикреплённый файлWPF_Sample_F3.5.zip (71,51 Кбайт, скачиваний: 265)
        Истина где-то рядом!?!
          жду про паттерн!
          скайп чат свободных людей Обсуждние стопхама, льва против без страха блокировки. Найди друзей с соуркеса у нас!!! ...И нет никаких истеричных женщин. Беша, я знаю, ты читаешь подпись. Сообщи свои требования!!11
            Alexus, не подумай что развожу холивар, желания такого нет. Но сказать стоит.

            Цитата Alexus @
            1. Нужен дизайнер. У "чистого" программиста, как правило, больше шансов сделать плохой интерфейс на WPF, чем на WinForms.

            Это все таки только на первый взгляд, потому как никто не мешает сделать такой же интерфейс как у WinForms на WPF если нет уверенности что оформление окажется не очень, но зато останутся преимущества в виде байндингов и прочей радости.

            Цитата Alexus @
            2. Меньше сторонних контролов. Под WinForms разработаны тонны, тонны контролов всяких полезных, а под WPF - чуть поменьше. Ситуация выправляется со временем - причём, с платными контролами она выправляется быстрее, чем с бесплатными.

            С 2008 года пишу на WPF еще ни разу не возникало желания воспользоваться сторонними контролами. Скажу даже более, недавно помогал товарищу привести проект на WinForms к более или менее нормальному виду, короче говоря затеяли большой рефакторинг. Так в энтом проекте куча DevExpress'овских гридов и прочего было полно. Скажу честно, после этого рефакторинга от DevExpress'овского грида просто воротит, ибо это монстр на все случаи жизни, не контрол а одно сплошное мучение, у него один функционал налагает ограничения на другой, да и чтобы что то реально функциональное на нем сделать придется попотеть. В WPF человеку который хтябы несколько месяцев имел с ним дело это же сделать получиться за какой то час, просто есть с кем сравнивать :).

            Цитата Alexus @
            3. Требование .Net 3.5. Это ужастно, но он ещё неу всех есть. Реально массовый, увы, пока второй. Тоже со временем исправится, конечно.

            а вот с этим вынужден согласиться, сам пару раз сталкивался. И не смотря что WPF есть уже с 3.0 фреймворка, почемуто всегда хочется все делать на 4.0 даже если функционал того не требует.
            Сообщение отредактировано: Pit-Bul -
            Истина где-то рядом!?!
              Цитата Alexus @
              Кратко, осовываясь на собственном опыте.

              + на икспи текст криво отображается. нужно ставить какой-то там тюнинг на каждый клиент.
              скайп чат свободных людей Обсуждние стопхама, льва против без страха блокировки. Найди друзей с соуркеса у нас!!! ...И нет никаких истеричных женщин. Беша, я знаю, ты читаешь подпись. Сообщи свои требования!!11
              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script Execution time: 0,1092 ]   [ 19 queries used ]   [ Generated: 25.09.17, 20:46 GMT ]