Сообщений 9    Оценка 1375        Оценить  
Система Orphus

Программируем панель задач Windows 7

Возможности панели задач Windows 7 для .NET разработчика

Автор: Сергей Звездин
Источник: RSDN Magazine #2-2009
Опубликовано: 13.10.2009
Исправлено: 10.12.2016
Версия текста: 1.0
.NET Sample Interop Library
Progress Bar
ThumbButtons
OverlayIcons
Windows manager
ThumbnailPreview
JumpLists
Заключение
Ссылки

Исходные коды к статье

Операционная система Windows 7 содержит большое количество нововведений и улучшений. Эти улучшения касаются безопасности, производительности, надежности и т.д. Серьезное внимание также уделено и пользовательскому интерфейсу. Для разработчиков Windows-приложений эта операционная система также представляет интерес, т.к. в ней содержатся элементы, на которые можно воздействовать программно.

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

.NET Sample Interop Library

С точки зрения разработчика клиентских Windows-приложений, процесс использования данной функциональности в собственных приложениях выглядит достаточно просто. Взаимодействие с ОС происходит на неуправляемом уровне через COM-объекты. Именно поэтому для .NET-приложений необходима реализация управляемых оберток. Всю эту работу уже проделали разработчики из Microsoft и поместили ее результат в библиотеку .NET Interop Sample Library. Мы будем использовать эту библиотеку для построения всех демонстрационных приложений в этой статье.

Библиотека .NET Interop Sample Library состоит из множества компонентов и демонстрационных приложений. Мы не будем подробно останавливаться на каждом из них. В данном случае нам важно, что в ее состав входят проекты «Vista Bridge Sample Library» и «Windows7.DesktopIntegration».

В составе проекта «Windows7.DesktopIntegration» есть класс WindowsFormsExtensions. Этот класс реализует набор методов-расширений для формы Windows Forms. К сожалению, на момент написания статьи в этом классе не было реализована поддержка WPF-приложений. Однако этот недочет очень просто исправить самостоятельно. Все, что потребуется сделать в этом случае – это изменить способ получения описателя (handle) окна.

Progress Bar

Одно из наиболее заметных изменений в панели задач Windows 7 – это возможность отображения прогресса выполнения задачи (progress bar) прямо в панели задач.


Рисунок 1.

На этом рисунке хорошо видно, что на панели задач отображается информация о процессе копирования. Такая функциональность реализована в Windows 7 для копирования файлов, загрузки данных из сети (Internet Explorer) и т. д. Эту функциональность мы можем использовать и для своих приложений. Сценариев может быть огромное количество – отображение процесса преобразования данных, копирования, формирования данных, построение отчетов, генерация изображений и т.д.

Класс WindowsFormsExtensions содержит два метода – SetTaskbarProgress и SetTaskbarProgressState. Вызов первого метода позволяет указать процент выполнения текущей задачи.

      // процесс выполнения = 35% 
      // вызов метода расширения простого статического метода
WindowsFormsExtensions.SetTaskbarProgress(this, 35); 

// или так (this = Form)this.SetTaskbarProgress(35);

Метод SetTaskbarProgressState позволяет задать текущее состояние прогресс-бара.

      this.SetTaskbarProgressState(Windows7Taskbar.ThumbnailProgressState.Normal);

Всего доступно четыре режима: Normal, Indeterminate (мерцание), Error (отображается красным цветом) и Paused (отображается желтым цветом).


Рисунок 2.

ThumbButtons

Другой интересной возможностью новой панели задач Windows 7 является возможность добавлять собственные кнопки управления приложением в окно предварительного просмотра. Подобную функциональность вы уже могли заметить при использовании Windows 7. Например, подобные кнопки существуют для Windows Media Player. Они позволяют переключать треки, а также останавливать воспроизведение. Всего таких кнопок можно создать не более семи.


Рисунок 3.

Несомненно, такая функциональность может быть полезна не только для Media Player, но и для других приложений. Давайте посмотрим, как можно реализовать это в нашем приложении. Создание кнопок должно происходить в момент обработки события WM_TaskbarButtonCreated. Поэтому в форме необходимо переопределить метод WndProc и обрабатывать моменты появления этого события.

      protected
      override
      void WndProc(ref Message m)
{
  if (m.Msg == Windows7Taskbar.TaskbarButtonCreatedMessage)
  {
    // initialize buttons
  }

  base.WndProc(ref m);
}

Для инициализации кнопок необходим объект ThumbButtonManager. Этот объект управляет поведением и отображением кнопок. Его можно создать, используя метод расширения CreateThumbButtonManager. После этого необходимо воспользоваться методом CreateThumbButton и создать объект кнопки. После того, как все кнопки будут созданы, необходимо добавить их на панель задач при помощи метода AddThumbButtons.

      protected
      override
      void WndProc(ref Message m)
{
  if (m.Msg == Windows7Taskbar.TaskbarButtonCreatedMessage)
  {
    InitializeThumbButtons();
  }
 
  base.WndProc(ref m);
}
 
 
protectedvoid InitializeThumbButtons()
{
  var thumbButtonManager = this.CreateThumbButtonManager();
 
  var decreaseThumbButton = thumbButtonManager.CreateThumbButton(1, 
    Icons.Navigation_First_2, "To reduce the progress");

  decreaseThumbButton.Clicked += delegate
               {
              // ..
               };
 
  thumbButtonManager.AddThumbButtons(decreaseThumbButton);
}

Теперь при запуске приложения можно увидеть, что появилась одна кнопка управления. Однако если мы попробуем нажать на нее, то увидим, что обработчик события не срабатывает. Чтобы обработчик начал работать, необходимо в методе WndProc явно передать объекту ThumbButtonManager возможность обрабатывать события. В итоге получим следующий несложный код.

      private ThumbButtonManager _thumbButtonManager;
 
protectedoverridevoid WndProc(ref Message m)
{
  if (m.Msg == Windows7Taskbar.TaskbarButtonCreatedMessage)
  {
    InitializeThumbButtons();
  }
  
  if (_thumbButtonManager != null)
    _thumbButtonManager.DispatchMessage(ref m);
 
 
  base.WndProc(ref m);
}
 
 
protectedvoid InitializeThumbButtons()
{
  if (_thumbButtonManager == null)
  {
    _thumbButtonManager = this.CreateThumbButtonManager();
  }
  
  var decreaseThumbButton = _thumbButtonManager.CreateThumbButton(1, 
    Icons.Navigation_First_2, "To reduce the progress");

  decreaseThumbButton.Clicked += delegate
    {
      Progress.Text = (float.Parse(Progress.Text) - 10).ToString();
      this.SetTaskbarProgress(float.Parse(Progress.Text));
    };
 
  // other buttons
 
  _thumbButtonManager.AddThumbButtons(decreaseThumbButton, 
     normalStateThumbButton, indeterminateStateThumbButton, 
     pauseStateThumbButton, errorStateThumbButton, increaseThumbButton);
}

Это приложение содержит 6 кнопок.


Рисунок 4.

OverlayIcons

Эта возможность исключительно полезна для приложений, которые обладают каким-то состоянием с точки зрения пользователя. К таким приложениям можно отнести программы для обмена мгновенными сообщениями (IM). Например, Windows Live Messanger активно использует эту возможность. Если мы откроем Windows Live Messanger и будем изменять состояние, то можно увидеть, как это отображается на панели задач.

Чтобы добавить значок состояния к основному значку приложения, необходимо добавить файл ресурсов в проект и разместить там нужные значки. Также мы можем получить объекты Icon из другого места, если это необходимо.


Рисунок 6.

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

      this.SetTaskbarOverlayIcon(Icons.Error, "Error");

Мы можем удалить этот значок. Для этого необходимо передать значение null вместо самого значка.

      this.SetTaskbarOverlayIcon(null, String.Empty);

Можно также представить себе другой сценарий, в котором на месте дополнительного значка отображается какая-то информация. К примеру, это может быть текущая скорость закачки, если ваше ПО что-то загружает из сети, или количество новых писем в почтовом ящике, если это почтовый клиент.

В качестве второго параметра в методе SetTaskbarOverlayIcon передается объект Icon. Однако что мешает генерировать этот объект динамически? Давайте воспользуемся нехитрым кодом и сделаем это. Я создам метод, который будет генерировать такое изображение, и покажу этот значок.

      private
      static Icon BuildIcon(int param)
{
  Bitmap image = Icons.BLANK2334242;

  Graphics.FromImage(image).DrawString(param.ToString(@"D2"), 
    new Font("Arial", 54), Brushes.White, 10, 25);

  return Icon.FromHandle(image.GetHicon());
}
 
 
privatevoid ShowStatus(object sender, EventArgs e)
{
  this.SetTaskbarOverlayIcon(BuildIcon(50, "Status");
}

Таким образом, при помощи метода BuildIcon будет сгенерирован новый значок, который будет отображен на панели задач.


Рисунок 7.

В демонстрационном приложении присутствует таймер, который имитирует работу менеджера загрузки, выдавая постоянно разную “скорость” загрузки.

Windows manager

Наверняка вы обратили внимание на то, что если одно и то же приложение запустить несколько раз, Windows 7 автоматически сгруппирует их в одну кнопку на панели задач. Кроме того, при наведении курсора на значок этого приложения панель задач покажет набор уменьшенных представлений для этих окон. Однако мы видим, что такое же поведение реализовано для открытых вкладок в Internet Explorer 8. В этом случае фактически запущен один экземпляр IE8 и много вкладок в рамках основного окна. В этом случае Internet Explorer отображает их в виде нескольких областей предварительного просмотра. В данном случае это очень полезно, т.к. прямо из панели задач можно сразу переключиться на нужную вкладку.


Рисунок 8.

Как можно догадаться, такую функциональность несложно реализовать и для своего приложения. Это актуально, если в вашем окне содержится набор других окон или вкладок (как в случае с IE8). Для этих целей в .NET Interop Sample Library присутствует класс CustomWindowsManager. Давайте создадим небольшое приложение для этих целей, работающее в режиме MDI. Наша цель – добиться того, чтобы все дочерние окна этого приложения отображались в виде отдельных областях предварительного просмотра.

Нам необходим момент отображения окна, когда это окно уже создано и готово к работе. Очень хорошо для этих целей подходит событие OnShown. В обработчике этого события нужно создать экземпляр объекта CustomWindowsManager и передать ему описатель (handle) дочернего окна, и родительского MDI- окна.

CustomWindowsManager _windowsManager;
 
protectedoverridevoid OnShown(EventArgs args)
{
  _windowsManager = CustomWindowsManager.CreateWindowsManager(
                      Handle, MdiParent.Handle);
 
  base.OnShown(args);
}

Сохраним ссылку на объект CustomWindowsManager, она понадобится нам позже. Однако этих действий недостаточно для корректной работы. Во-первых, необходимо подписаться на событие ThumbnailRequested, в котором сгенерировать изображение (Bitmap) нашего окна для всплывающих окон в панели задач. Во-вторых, мы должны подписаться на событие PeekRequested, в котором сгенерировать изображение, содержащее отображение нашего окна в момент наведения курсора мыши на его уменьшенное представление в панели задач.

Событие ThumbnailRequested содержит параметр типа BitmapRequestedEventArgs. Этот объект будет управлять тем, что будет отображаться на панели задач. Самое простое, что мы можем сделать - это указать, что параметр UseWindowScreenshot равен true. В этом случае скриншот окна будет сделан без нашего участия. Если же хочется отобразить какую-то собственную картинку в области предварительного просмотра, то можно воспользоваться параметром Bitmap, куда положить свой объект Bitmap, который должен быть отображен. Однако нужно понимать, что этот объект должен иметь строго заданные размеры. Эти размеры можно получить из параметра типа BitmapRequestedEventArgs.

_windowsManager.PeekRequested += (o, e) =>
{
  var result = new Bitmap(e.Width, e.Height);

  DrawToBitmap(result, new Rectangle(0, 0, e.Width, e.Height));
  e.Bitmap = result;
};

Обратите внимание, что в этих примерах используется метод формы DrawToBitmap. Однако можно выводить уменьшенное представление любого другого элемента управления. Например, можно отображать TextBox. Ну и, наконец, необходимо вызвать метод WindowClosed, когда окно закрывается. Для этого хорошо подходит событие OnClosed.

      protected
      override
      void OnClosed(EventArgs e)
{
  if (_windowsManager != null)
  {
    _windowsManager.WindowClosed();
  }
 
  base.OnClosed(e);
}

Итак, у нас получилось следующее приложение:


Рисунок 9.

Если мы посмотрим на панель задач, то увидим следующее:


Рисунок 10.

Однако если мы начнем изменять внешний вид формы, то увидим, что область предварительного просмотра не изменилась. Это вызвано тем, что Windows 7 не генерировала заново событие получения уменьшенного изображения. Это особенно критично, если на форме находится содержание, которое постоянно изменяется, например, видео. На этот случай есть способ обновить представление принудительно. Для этого необходимо вызвать метод InvalidatePreviews.

      private
      void InvalidateButton_Click(object sender, EventArgs e)
{
  _windowsManager.InvalidatePreviews();
}

Этот метод в каждом конкретном случае необходимо вызывать в определенные моменты времени, например, при обновлении текста в TextBox. Для видео хороший вариант – вызывать этот метод по таймеру.


Рисунок 11.

Однако аналогичного эффекта можно добиться, если запустить несколько экземпляров одного и того же приложения. В этом случае Windows 7 определит, что это одно и то же приложение, и сгруппирует окна в один значок.


Рисунок 12.

В основе этого механизма лежит такое понятие, как Application ID. Для каждого окна можно задать свой ID. Эту особенность также можно использовать, если необходимо избежать такого поведения. В этом случае нужно задать различные AppId для каждого такого окна. Сделать это можно, используя .NET Interop Sample Library. Для этого необходимо вызвать метод SetAppId у класса-обертки.

      private
      void SetAppIdButton_Click(object sender, EventArgs e)
{
  this.SetAppId("SomeAppId");
}

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


Рисунок 13.

Аналогичным образом можно сгруппировать несколько окон от разных приложений. Для этого необходимо задать одинаковый AppId для каждого из окон. В этом случае панель задач Windows 7 сгруппирует эти приложения в один значок. Например, в данном случае заданы одинаковые AppId для разных окон из разных приложений, и эти окна оказались сгруппированными в панели задач Windows 7.


Рисунок 14.

ThumbnailPreview

Как мы уже могли убедиться, Windows 7 обладает удобной функциональностью по отображению окон предварительного просмотра для приложений. При наведении мыши на значок окна в панели задач можно увидеть уменьшенное представление окна. Это очень удобно, когда у пользователя открыто большое количество окон. По умолчанию в этих мини-окнах отображается все содержимое окна. Однако для некоторых приложений было бы гораздо удобнее показывать не все содержимое окна, а только его часть. Такая функциональность также предусмотрена для панели задач Windows 7, и мы можем использовать ее для своих приложений.

В рамках оберток для функций из системных библиотек Windows присутствует метод SetThumbnailClip, который поможет нам в реализации данной функциональности. При вызове данного метода в параметрах необходимо передать текущий экземпляр формы и координаты, ограничивающие область окна.

      private
      void Clip5_Click(object sender, EventArgs e)
{
  this.SetThumbnailClip(new Rectangle(10, 10, 145, 145));
}

Давайте создадим небольшое приложение, где посмотрим на возможности этой функциональности. Для этого создадим пустое приложение, в которое добавим несколько элементов управления. После запуска приложения окно предварительного просмотра будет выглядеть следующим образом.


Рисунок 15.

Видно, что изначально отображается все окно. Давайте ограничим область отображения при помощи метода SetThumbnailClip. Отобразим, например, только поля ввода, которые находятся на форме.


Рисунок 16.

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

      private
      void NoClip_Click(object sender, EventArgs e)
{
  this.SetThumbnailClip(new Rectangle(new Point(0, 0), Size));
}

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


Рисунок 17.

Для реализации подобного поведения в .NET Interop Sample Library существует метод SetIconicThumbnail. Именно с его помощью мы можем легко и просто создать собственный вид области предварительного просмотра для нашего окна. Однако, прежде чем мы начнем его использовать, мы должны разрешить это поведение с помощью метода EnableCustomWindowPreview. В противном случае при выполнении метода SetIconicThumbnail мы получим соответствующее исключение. Сделать это можно прямо в конструкторе формы.

      public Form1()
{
  InitializeComponent();
  this.EnableCustomWindowPreview();
}

Стоит сказать, что размеры изображения, которые мы хотим отобразить в области предварительного просмотра, ограничены значениями 200x120. Изображение может быть меньше этого размера. В этом случае область предварительного просмотра также будет уменьшена. Если изображение больше этих размеров, то будет сгенерировано исключение.

В параметрах метода SetIconicThumbnail передается ссылка на текущую форму и изображение (Bitmap), которое нужно отобразить. Наша задача – сгенерировать этот Bitmap. В этом случае у нас полностью развязаны руки – мы можем сгенерировать все, что нам необходимо. Это может быть снимок окна, с каким-то дополнительным текстом поверх. Это может быть какая-то собственная картинка, содержащая информацию. Это может быть текст с некоторой статистикой.

В демонстрационном приложении мы будем генерировать изображение, отображающее состояние приложения текстом и графически, а также небольшой снимок окна. Для этого создадим изображение (Bitmap) нужных размеров и зальем его фоном. После этого нарисуем там изображение состояния и снимок окна. Затем напишем на этом изображении текст состояния, и результат передадим в метод SetIconicThumbnail.

      private
      static
      void SetState(Form form, string stateText, Image stateImage)
{
  var preview = new Bitmap(200, 120);
  var g       = Graphics.FromImage(preview);
 
  // заполяем фон
  g.DrawImage(Images.background, 0, 0);
 
  // рисуем изображение отражающее состояние
if (stateImage != null)
    g.DrawImage(stateImage.GetThumbnailImage(100, 100, null, IntPtr.Zero), 100, 10);
 
  // рисуем уменшеное изображение формы
  g.DrawImage(GetFormImage(form, 50, 60), 10, 10);
 
  g.DrawString(stateText, new Font("Verdana", 18), Brushes.White, 10, 70);
 
  // устанавливаем сформированный thumbnail
  form.SetIconicThumbnail(preview);
}

Как видите, код получился достаточно лаконичный. В результате мы увидим следующее представление.


Рисунок 18.

Что интересно, наше приложение может само в фоне изменять это состояние. При этом если мышь находится на значке приложения и окно предварительного просмотра в данный момент отображается, то смена изображения во всплывающем окне происходит плавно, без каких-либо побочных эффектов. Так, например, можно создать таймер, в обработчике которого через определенные промежутки времени изменять состояние.

Стоит также отметить еще одну приятную особенность Windows 7: если навести курсор мыши на область предварительного просмотра окна, то все остальные окна скроются, а выделенное окно будет отображаться. Выглядит это следующим образом.


Рисунок 19.

Имеется возможность задать поведение панели задач Windows 7. В этом случае мы имеем возможность заменить содержимое нашей формы нашим собственным изображением. Например, написать там какой-то полезный текст. В этом случае сценарий работы может выглядеть следующим образом. У пользователя в панели задач находится приложение, которое что-то выполняет. Он может отслеживать его состояние на основе ProgressBar и OverlayIcon, которые мы обсудили ранее. Если этой информации ему недостаточно, он может навести курсор мыши на иконку приложение. В этом случае ему отобразится область предварительного просмотра, в которой содержится дополнительная информация. Пользователь может навести курсор мыши на область предварительного просмотра нужного окна и в все окна скроются, и на экране останется только выделенное окно. В этот момент можно вывести в оставшемся окне некоторую дополнительную информацию.

Вообще, по умолчанию в таком сценарии при скрытии остальных окон выведется само содержимое окна. Переопределение содержания окна в этот момент может быть полезно, если на форме информация разрознена, и сразу непонятно, что происходит в приложении.

Чтобы реализовать подобный сценарий в нашем приложении, мы воспользуемся .NET Interop Sample Library. Для этих целей предназначен метод SetPeekBitmap класса-обертки. Генерировать изображение необходимо в момент, когда пользователь наводит мышь на область предварительного просмотра окна. Для этих целей переопределим метод WndProc и отловим событие WM_DWMSENDICONICLIVEPREVIEWBITMAP. Как раз в этот момент времени необходимо генерировать изображение.

      protected
      override
      void WndProc(ref Message m)
{
  if (m.Msg == WM_DWMSENDICONICLIVEPREVIEWBITMAP)
  {
    this.SetPeekBitmap(GeneratePeekBitmap(this, Images._111), true);
  }

  base.WndProc(ref m);
}

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

      private
      static Bitmap GeneratePeekBitmap(Form form, Image stateImage)
{
  var preview = new Bitmap(form.ClientSize.Width, form.ClientSize.Height);
 
  var g = Graphics.FromImage(preview);
 
  g.DrawImage(Images.background.GetThumbnailImage(
  form.ClientSize.Width, form.ClientSize.Height, null, IntPtr.Zero), 0, 0);
  
  if (stateImage != null)
  {
  Size thumbSize = new Size(100, 100);
    g.DrawImage(stateImage.GetThumbnailImage(
    thumbSize.Width, thumbSize.Height, null, IntPtr.Zero),
  form.ClientSize.Width / 2 - thumbSize.Width / 2, 
  form.ClientSize.Height / 2 - thumbSize.Height / 2);
  }
 
  return preview;
}

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


Рисунок 20.

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

Кроме того, у метода SetPeekBitmap существует третий параметр логического типа (boolean). Изменяя этот параметр, можно указать, нужно ли убирать рамку приложения, когда осуществляется подобный просмотр.

JumpLists

Одной из важнейших функций панели задач в Windows 7 являются списки переходов (Jump Lists). Списки переходов отображаются, если нажать правую кнопку мыши на значке приложения в панели задач. Если приложение использует функциональность списков перехода, то кроме стандартных действий (pin, close) появятся еще ряд дополнительных действий, которые облегчают повседневную работу с приложением.

Эту функциональность панели задач активно используют различные приложения. Например, Windows Media Player отображает опции переключения плейлистов. Internet Explorer и Windows Explorer содержат в списках переходов историю посещений. Windows Live Messanger отображает опции переключения состояния.


Рисунок 21.

В списках переходов может присутствовать несколько различных типов элементов: задачи, ссылки на последние открытые документы и ссылки на постоянные документы. Кроме того, эти позиции могут быть закреплены. Такие элементы не исчезнут из списков переходов со временем. Это удобно, например, если мы часто работаем с одним и тем же документом. Схематично Jump List в Windows 7 можно представить следующим образом.


Рисунок 22.

По сути, каждый пункт в списках переходов представляет собой ссылку на программу или файл. Так, например, мы можем запустить калькулятор, или какой-либо документ заданного формата. К сожалению, у нас нет возможности напрямую перехватить событие нажатия на пункт в списках перехода в нашем приложении. Каждый раз, когда мы выбираем очередной пункт, будет запускаться новый экземпляр приложения. Это связано в первую очередь с тем, что со списками переходов можно работать даже тогда, когда приложение не запущено. В этом случае оно должно быть закреплено (pinned) на панели задач. Например, на следующем рисунке видно, что Internet Explorer в данный момент не запущен, но списки переходов мы использовать можем.


Рисунок 23.

Давайте посмотрим, каким образом подобная функциональность может быть реализована в наших приложениях. Для работы со списками переходов нам понадобится объект типа JumpListManager, который входит в состав .NET Interop Sample Library. Создавать его необходимо в момент создания кнопки приложения на панели задач. Для этих целей можно переопределить метод WndProc следующим образом.

      protected
      override
      void WndProc(ref Message m)
{
  if (m.Msg == Windows7Taskbar.TaskbarButtonCreatedMessage)
  {
    _jumpListManager = this.CreateJumpListManager();
    _jumpListManager.UserRemovedItems += (o, e) =>
    {
      e.CancelCurrentOperation = false;
    };
  
    // add items
  
    _jumpListManager.Refresh();
  }
  
  base.WndProc(ref m);
}

Обратите внимание на вызов метода Refresh после создания объекта JumpListManager. Вызов этого метода необходим для обновления позиций в списках переходов. Также обязательным действием является подписка на событие UserRemovedItems, соответствующее попытке удаления устаревших пунктов из списков переходов. Давайте теперь попробуем добавить новые позиции. Для этих целей существуют классы-обертки и нужные методы у объекта JumpListManager.

Самый простой тип позиций в списках переходов – задачи. Задачей может быть запуск внешнего приложения или нашего приложения с какими-то параметрами. В Windows Live Messenger в виде задач реализовано переключение состояния пользователя. Для создания задачи в списках переходов используется метод AddUserTask.

_jumpListManager.AddUserTask(new ShellLink
{
  Path = Path.Combine(
  Environment.GetFolderPath(Environment.SpecialFolder.System), "calc.exe"),
  Title = "Calculator",
  Category = "Applications",
  IconLocation = Path.Combine(Environment.GetFolderPath(
    Environment.SpecialFolder.System), "calc.exe"),
  IconIndex = 0
});

Как видим, здесь создается новый объект типа ShellLink, в который передается путь к приложению, заголовок и значок. Добавим в свое приложение две задачи и получим следующий результат.


Рисунок 24.

Другой вариант заполнения списков переходов – ссылки на ранее открывавшиеся документы. Для этих целей создадим несколько текстовых файлов с расширением “.myapp” и ассоциируем этот тип файлов со своим приложением. При запуске приложения проверим, передано ли имя файла в качестве параметра при запуске приложения. Если имя задано, то считаем этот файл и добавим его в список ранее загруженных файлов. Для этих целей существует метод AddToRecent.

      if (File.Exists(Environment.GetCommandLineArgs().Skip(1).FirstOrDefault() ?? String.Empty) == true)
{
  _jumpListManager.AddToRecent(
  Environment.GetCommandLineArgs().Skip(1).FirstOrDefault() ?? String.Empty);
}

Теперь из Windows Explorer откроем эти файлы. При этом будет запускаться демонстрационное приложение (если мы правильно ассоциировали данный тип файлов с приложением). При этом при вызове списков переходов мы увидим, что в категории “Recent” появились ссылки на ранее открытые файлы.


Рисунок 25.

Другой способ размещения позиций в списках переходов – создание ссылок на постоянные документы/программы. В этом случае можно сгруппировать эти позиции по категориям. Для этого служит метод AddCustomDestination.

_jumpListManager.AddCustomDestination(new ShellLink
{
  Path = @"about.txt",
  Title = "About",
  Category = "My application",
  IconLocation = 
  Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.System),
  "shell32.dll"),
  IconIndex = 11
});

Добавим несколько таких ссылок в списки переходов и получим следующий результат.


Рисунок 26.

На этом рисунке видно, что появились две дополнительные группы со ссылками внутри.

Замечательной особенностью списков переходов является то, что их содержимое также доступно в меню “Пуск”. Так, например, если мы активно пользуемся этой функциональностью, то этим можно использоваться и из стартового меню.


Рисунок 27.

Таким образом, мы можем использовать дополнительную функциональность, предоставляемую панелью задач Windows 7, для обеспечения максимально комфортной работы пользователя.

Заключение

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

Надеюсь, эта информация окажется полезной для вас и ваших приложений. Успехов вам в построении ваших приложений для Windows7!

Ссылки


Эта статья опубликована в журнале RSDN Magazine #2-2009. Информацию о журнале можно найти здесь
    Сообщений 9    Оценка 1375        Оценить