Работа с панелью задач Windows 7 в приложениях WPF

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

В реальности, использование этих возможностей в приложениях WPF не сильно отличается от их реализации в WinForms. Как известно, для использование возможностей панели задач Windows 7 мы пользовались статическим классом WindowsFormsExtensions, в котором содержаться методы-расширения для класса Form (представление формы в Windows Forms). К сожалению, в .NET Interop Sample Library нет подобного класса для WPF приложений. Однако совсем не сложно создать его самостоятельно.

Если взглянуть на класс WindowsFormsExtensions внимательно, то становится понятно, что все вызовы перенаправляются классу Windows7Taskbar, который для идентификации формы используется Handle окна, с которым производится работа. В случае с Windows Forms у формы есть свойство Handle, которое возвращает нужное значение. Соответственно первая задача – это получить handle окна Windows Presentation Foundation. К сожалению, у окон WPF нет свойства Handle. Однако, можно воспользоваться услугами класса WindowInteropHelper и получить эту информацию. Для этого я сделал еще один метод, который возвращает Handle WPF-окна.

private static IntPtr GetWindowHandle(Window window)
{
  return (new WindowInteropHelper(window)).Handle;
}

Далее во всех методах-расширениях необходимо изменить тип параметра (тип, к которому применяется extension method) с From на Window. После этого большинство возможностей уже доступны для WPF-приложений.

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

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

  base.WndProc(ref m);
}

К сожалению, для окон WPF такого метода нет. Однако, в WPF приложениях можно воспользоваться объектом HwndSource и добавить перехват сообщений Windows через него.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
  HwndSource.FromHwnd(new WindowInteropHelper(this).Handle).AddHook(WndProc);
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  if (msg == WM_DWMSENDICONICLIVEPREVIEWBITMAP)
  {
    // ...
  }
  return IntPtr.Zero;
}

В остальном использование возможностей панели задач Windows 7 в приложениях WPF реализуется аналогично Windows Forms.