На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: maxim84_
  
> Введение в WPF 2 , Анатомия Window
    Первая часть

    Пришла очередь препарировать окна. Вспомним минимальный код, из прошлой статьи, который позволил нам с Вами, отобразить программно окно с использованием WPF:

    ExpandedWrap disabled
      using System;
      using System.Windows;
       
      namespace Juice.HelloWpf
      {
          class Program
          {
              [STAThread]
              static void Main(string[] args)
              {
                  Application app = new Application();
                  Window windows = new Window();
                  windows.Show();
                  app.Run();
              }
          }
      }


    Что происходит в момент создания окна? Начнем с конструктора. Конструируя окно WPF, поступает примерно следующим образом. Перво-наперво устанавливает ряду полей значения по умолчанию. Во вторых проверяет, существование Application. Зачем? Ну просто для того, что бы не заставлять нас с Вами, выполнять лишние телодвижения. Если мы посмотрим еще раз на код приведеный Выше и вспомним о том, что приложение имеет главное окно, то можем задать вопрос, где мы его установили? Попробуем провести эксперемент. Перепишем код так:

    ExpandedWrap disabled
      using System;
      using System.Windows;
       
      namespace Juice.HelloWpf
      {
          class Program
          {
              [STAThread]
              static void Main(string[] args)
              {
                  Application app = new Application();
                  Window windows = new Window();
                  app.MainWindow.Show();
                  app.Run();
              }
          }
      }



    Код также отлично отработал. Следствие этого не сложного эксперемента, следующие: окно само сделало себя главным и добавило в коллекцию Windows класса Application. А теперь попробуем поменять местами две строчки кода:

    ExpandedWrap disabled
      using System;
      using System.Windows;
       
      namespace Juice.HelloWpf
      {
          class Program
          {
              [STAThread]
              static void Main(string[] args)
              {
                  Window windows = new Window();
                  Application app = new Application();
                  app.MainWindow.Show();
                  app.Run();
              }
          }
      }


    И убедимся, что от перестановки слагаемых, в нашем случае, сумма изменяется.
    На момент создание окна, не существовало экземпляра Application, окно выяснив это не «смогло» себя добавить в соответствующее свойство. A объект Application сможет установить корректные значения только в методе Run(). Именно по этому app.MainWindow вырнуло null в программу и попытка вызвать метод Show() привела к исключению.

    Каждый экземпляр окна иммеет внутреннее свойство App, которое позволяет ему получить ссылку на экземпляр приложения. Окно пользуется им в двух ситуациях. Первую мы уже рассмотрели, вторая ситуация возникает когда окно закрывается, оно удаляет себя из коллекции Windows экземпляра приложения и обнуляет MainWindow, только в том случае если окно было главным окном приложения. Именно поэтому коллекция Windows у Application всегда поддерживается в актуальном состоянии.

    Разберемся с позиционированием окнон. В отличие от WindowsForms где у Form было свойство Location, Window такого свойства не имеет. Зато присутствуют известные нам по WindwosForm свойства Left и Top.

    Left - отступ от левого, края рабочего стола.
    Top - отступ от верхнего, края рабочего стола.

    Используя эти свойства мы можем позиционировать окно.

    Первое, что вызывает удивление это использование типа double для хранения этих значений. Но удивление быстро проходит. Оказывается в WPF, размеры исчесляются не в обычных пикселах, а в логических пикселах. Которые, на самом деле, не зависят от разрешения монитора. В англоязычной литературе часто встречается сокращение DIP (Device Independent Pixel). 96 DIP = 1 дюйму = 2.54 сантиметра. А так как разрешающая способность для большинства современных мониторов это 96 DPI, то в подавляющем большинстве случаев 1 DIP = 1 физическому пикселу.

    По этой ссылке http://www.codeplex.com/perspective находится один интересный проект с открытым исходным кодом и в нем есть класс DipHelper который позволяет легко оперировать DIP в метрической и дюймовой системах счисления.

    Основное преимущество от использования DIP это сохранение исходных размеров при использовании других устройств вывода или устройств с другими разрешающими характеристиками, например принтеров.

    Для управления размером окон мы можем использовать свойства Width и Height. Тем не менее их поведение отличается от привычного нам по модели WindowsForms. Поставим простой эксперемент.

    ExpandedWrap disabled
      using System;
      using System.Windows;
       
      namespace HelloWPFNew
      {
          public class HeloWPF
          {
              [STAThread]
              public static void Main()
              {
                  Application app = new Application();
                  Window window = new Window();
                  window.Title = String.Format("Width: {0}; Height: {1};", window.Width, window.Height);
                  app.Run(window);
              }
          }
      }

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

    Например так:

    ExpandedWrap disabled
      using System;
      using System.Windows;
       
      namespace HelloWPFNew
      {
          public class HeloWPF
          {
              [STAThread]
              public static void Main()
              {
                  Application app = new Application();
                  Window window = new Window();
                  window.Width = 320;
                  window.Height = 240;
                  window.Show();
                  app.Run();
              }
          }
      }


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

    Для того, что бы узнать действительные размеры окна мы можем воспользоваться свойствами ActualWidth и ActualHeight, которые мы можем использовать после того как окно уже было отображено.

    Что б посмотреть на эти свойства в действии посмотрите на следующую, не сложную, программу:

    ExpandedWrap disabled
      using System;
      using System.Windows;
       
      namespace HelloWPFNew
      {
          public class HeloWPF
          {
              [STAThread]
              public static void Main()
              {
                  Application app = new Application();
                  Window window = new Window();
                  Console.WriteLine("ActualWidth: {0}; ActualHeight: {1};", window.ActualWidth, window.ActualHeight);
                  window.Show();
                  Console.WriteLine("ActualWidth: {0}; ActualHeight: {1};", window.ActualWidth, window.ActualHeight);
                  app.Run();
              }
          }
      }


    Результат работы:

    ActualWidth: 0; ActualHeight: 0;
    ActualWidth: 960; ActualHeight: 559;

    Еще одним способом позиционирования окон является свойство WindowsStartupLocation, класса Window, которое может принимать значения:

    WindowStartupLocation.Manual (по умолчанию) – выбирается операционной системой, или переопределяется программистом.

    WindowStartupLocation.CenterScreen – выравнивание по центру рабочей области

    WindowStartupLocation.CenterOwner – используется при выравнивании относительно родительского окна.

    Для того, что бы закрепить сегодняшний материалл, напишем простую программу, когда созданое нами окно, будет по нажатию соответствующих клавиш, «прикреплять» к краям рабочей области. При этом окно будет занимать ровно половину рабочей области. Отлавливать мы будем нажатия следующих клавиш T (Top), B(Bottom), L(Left), R(Right).

    ExpandedWrap disabled
      using System;
      using System.Windows;
      using System.Windows.Input;
       
      namespace HelloWPFNew
      {
          public class HeloWPF
          {
              [STAThread]
              public static void Main()
              {
                  Application app = new Application();
       
                  // создаем окно
                  Window window = new Window();
                  window.Width = 320;
                  window.Height = 240;
       
                  // позиционируем по центру рабочей области
                  window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
       
                  // подписываемся на уведомление о нажатии клавиш
                  window.KeyUp += new KeyEventHandler(window_KeyUp);
       
                  // отображаем окно
                  window.Show();
                  app.Run();
              }
       
              static void window_KeyUp(object sender, KeyEventArgs e)
              {
                  // выясняем текущий размер рабочей области
                  Rect workArea = SystemParameters.WorkArea;
       
                  // получаем ссылку на окно
                  Window window = sender as Window;
       
                  // позиционируем окно взависимости от пользовательского ввода
                  switch (e.Key)
                  {
                      case Key.T:
                          {
                              window.Left = 0;                        
                              window.Top = 0;
                              window.Width = workArea.Width;
                              window.Height = workArea.Height / 2;
                              break;
                          }
                      case Key.B:
                          {                        
                              window.Width = workArea.Width;
                              window.Height = workArea.Height / 2;
                              window.Left = 0;
                              window.Top = workArea.Height - window.Height;
       
                              break;
                          }
                      case Key.L:
                          {
                              window.Left = 0;
                              window.Top = 0;
                              window.Width = workArea.Width / 2;
                              window.Height = workArea.Height;
                              break;
                          }
                      case Key.R:
                          {
                              window.Width = workArea.Width / 2;
                              window.Height = workArea.Height;
                              window.Left = workArea.Width - window.Width;
                              window.Top = 0;
                              break;
                          }
                  }
              }
          }
      }


    В следующий раз, попробуем разобраться с тем, как WPF «красит» окна. А может окна сами красят себя? ;)
    Сообщение отредактировано: juice -
      Цитата juice @
      А так как разрешающая способность для большинства современных мониторов это 96 DPI, то в подавляющем большинстве случаев 1 DIP = 1 физическому пикселу.

      На самом деле равенство это практически никогда не выполняется (ну разве что на каких то дорогих спец. мониторах). Но, как правило, оно выполняется с некоторым допуском.
      Так что если надо точно показать 5 см на экране - необходимы какие то механизмы калибровки.

      А вообще, в статье для меня в ней был один интересный момент - механизмы поддержания актуальности коллекции окон приложения.

      А про размеры (Width/Height, ActualSize, DesiredSize и ещё куча других Size) - это всё к немного другой теме - механизмаму Layoyt в Wpf.
      Тема интересная, но объёмная.
        Цитата Alexus @
        А про размеры (Width/Height, ActualSize, DesiredSize и ещё куча других Size) - это всё к немного другой теме - механизмаму Layoyt в Wpf.
        Тема интересная, но объёмная.

        С Божьей и Вашей помощью доберемся :)
          Читаю вот Петцольда - посмотрим, что у него об этом написано, а там уж и своё чтото ваять можно будет.

          Добавлено
          Кстати, его первые главы по содержанию аналогичны твоим статьям. Если подумать, это вполне логично. С чего ж ещё начинать?
          :)
          Сообщение отредактировано: Alexus -
            Цитата Alexus @
            Кстати, его первые главы по содержанию аналогичны твоим статьям.

            Я читал его Code + Murkup. Еще я когда то читал его программирование для Windows на C#. Подкупает то, что он пишет весь код руками, это именно то, что нужно при освоении новой технологии. Но честно говоря я не уверен, что стоит не писать о XAML так долго как это делает он.
              без Xaml wpf ничем принципиально не отличается от windows forms
              0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
              0 пользователей:


              Рейтинг@Mail.ru
              [ Script execution time: 0,0345 ]   [ 15 queries used ]   [ Generated: 16.04.24, 10:20 GMT ]