Pull to refresh

WPF4 и Taskbar в Windows 7: Кнопки предпросмотра(Thumbnail buttons)

Reading time15 min
Views2.4K
Original author: Pete Brown
У панели задач Windows 7 есть много способов для приложений предоставлять уникальную информацию чтобы сделать UX ещё круче. Одна из них рассматривается в этой статье — кнопки панели предсмотра на таскбаре.

Существует вероятность что вы уже используете несколько приложений использующих эту функциональность. Вот скриншот приложения Zune с 4мя кнопками предпросмотра.



А вот как приложение выглядит с одной из кнопок при наведении мышки:



Вот ещё один пример. На этот раз это Fishbowl(клиент для Facebook)



Давайте посмотрим как реализовать кнопки предпросмотра в нашем собственном WPF4 приложении.

Project Setup

Создайте стандартное клиентскоп WPF-приложение. В моём примере я назвал его WpfTaskbarThumbnailButtons. Как только вы это сделали — откройте XAML для главного окна(это то, где мы проведем большую часть времени). Добавьте секцию ресурсов и обычную TaskbarItemInfo, как мы сделали в предыдущих постах.

<Window x:Class="WpfTaskbarThumbnailButtons.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Thumbnail Button Application" Height="350" Width="525">
  <Window.Resources>
  </Window.Resources>
  
  <Window.TaskbarItemInfo>
  </Window.TaskbarItemInfo>

  <Grid>   
  </Grid>
</Window>

* This source code was highlighted with Source Code Highlighter.


Следующим шагом будет создание ресурсов для изображений наших кнопок

Button Images
Как только вы решили какие кнопки вы хотите — настает время создать графику для них. Стандарт для таскбара Windows 7 это 16х16 пикселей(24х24 для высоких DPI), обычного в чернобелой схеме. Если вы создадите изображения большего размера — они будут уменьшены до подходящего размера, так что если вы ленивы(особенно если у вас векторная графика) — можно не уменьшать вручную.

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

<Window.Resources>
  <DrawingImage x:Key="Button1Image">
    <DrawingImage.Drawing>
      <DrawingGroup>
        <DrawingGroup.Children>
          <GeometryDrawing Brush="Red">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0 0 24 24"
                        RadiusX="4"
                        RadiusY="4" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
        </DrawingGroup.Children>
      </DrawingGroup>
    </DrawingImage.Drawing>
  </DrawingImage>
  <DrawingImage x:Key="Button2Image">
    <DrawingImage.Drawing>
      <DrawingGroup>
        <DrawingGroup.Children>
          <GeometryDrawing Brush="Green">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0 0 24 24"
                        RadiusX="4"
                        RadiusY="4" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
        </DrawingGroup.Children>
      </DrawingGroup>
    </DrawingImage.Drawing>
  </DrawingImage>
  <DrawingImage x:Key="Button3Image">
    <DrawingImage.Drawing>
      <DrawingGroup>
        <DrawingGroup.Children>
          <GeometryDrawing Brush="Blue">
            <GeometryDrawing.Geometry>
              <RectangleGeometry Rect="0 0 24 24"
                        RadiusX="4"
                        RadiusY="4" />
            </GeometryDrawing.Geometry>
          </GeometryDrawing>
        </DrawingGroup.Children>
      </DrawingGroup>
    </DrawingImage.Drawing>
  </DrawingImage>
</Window.Resources>

* This source code was highlighted with Source Code Highlighter.


Я использовал здесь векторную графика, но, как я упоминал в своей статье о перекрывающих иконках на таскбаре(overlay icon), вы можете так же использовать растровую графику.

Следующий шаг — собственно добавление трех кнопок на таскбар. Это делается через коллекцию ThumButtonInfos классов TaskbarItemInfo.

TaskbarItemInfo.ThumbButtonInfos
Как только вы определились какие кнопки вы хотите на панеле предсмотра вашего приложения(у вас есть место для максимум 7 кнопок в Windows 7), и у вас есть изображения для них — вы можете создать их в коде или, как я люблю, в XAML-е. Кнопки являются экземплярами класса TaskbarItemInfo и добавляются в коллекцию ThumbButtonInfos.

Вот свойство окна TaskbarItemInfo с нашими тремя простыми кнопками. Заметьте что всё что я определил для них — это картинка и описание(подсказка)

<Window.TaskbarItemInfo>
  <TaskbarItemInfo>
    <TaskbarItemInfo.ThumbButtonInfos>
      <ThumbButtonInfo ImageSource="{StaticResource Button1Image}"
               Description="Button 1" />
      <ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
               Description="Button 2" />
      <ThumbButtonInfo ImageSource="{StaticResource Button3Image}"
               Description="Button 3" />
    </TaskbarItemInfo.ThumbButtonInfos>
  </TaskbarItemInfo>
</Window.TaskbarItemInfo>

* This source code was highlighted with Source Code Highlighter.


И вот скриншот результата. Заметьте что порядок кнопок такой же в каком они добавлены в коллекцию. Слева направа — от первого к последнему.



ThumbButtonInfo Class

Класс ThumbButtonInfo описывает одну кнопку в окне предпросмотра на таскбаре. Поскольку они должны соответствовать Windows 7 API — они не обычные кнопки, к которым мы привыкли в WPF. Другими словами вы не можете применять к ним шаблоны как вы могли привыкнуть. Однако им можно назначать картинку(растровую или векторную).

Command, CommandParameter, CommandTarget
Это поддержка инфраструктуры команд в WPF. Ничего необычного здесь. Если не хотите использовать команды — просто вешайте обработчик на событие Click кнопки.

Description
Это всплывающая подсказка кнопки. Желательно её указывать.

IsInteractive
Это свойство определяет является ли кнопка обычной кнопкой или просто картинкой с подсказкой. Если True — то кнопка, если False — то картинка отображается, но на неё нельзя нажать.

IsBackgroundVisible
Это определяет видимы или нет граница и фоновая подсветка вокруг кнопки. В обоих примерах ниже я снимал скриншот при наведении мышки на среднюю кнопку «Button 2».

Background Visible

<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsBackgroundVisible="True"/>


* This source code was highlighted with Source Code Highlighter.




Background Invisible
<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsBackgroundVisible="False"/>


* This source code was highlighted with Source Code Highlighter.



DismissWhenClicked
Если true — щелчок по кнопке закроет окно предпросмотра. Значение False оставит окно предпросмотра открытым так чтобы пользователь мог щелкать на другие кнопки или увидеть изменения в предпросмотре окна.

ImageSource
ImageSource это что угодно что приводится к типу System.Windows.Media.ImageSource, обычно это DrawingImage или BitmapSource. В нашем примере мы использовали DrawingImage которым содержал векторный рисунок.

Visibility
Это работает так же как и везде в WPF. Visible кнопки отображаются, Hidden занимают место но не отображаются, а Collapsed ни отображаются ни занимают место

Button 2 Visible
<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsBackgroundVisible="True"
         Visibility="Visible"/>

* This source code was highlighted with Source Code Highlighter.



Button 2 Hidden
<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsBackgroundVisible="True"
         Visibility="Hidden"/>

* This source code was highlighted with Source Code Highlighter.



Заметьте что кнопка всё ещё занимает место.

Button 2 Collapsed
<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsBackgroundVisible="True"
         Visibility="Collapsed"/>

* This source code was highlighted with Source Code Highlighter.



IsEnabled
При True — кнопка активна и рисуется в обычных цветах. При False — кнопка отключена и рисуется в чёрно-белых цветах.

Button 2 Enabled
<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsEnabled="True"
         IsBackgroundVisible="True"
         Visibility="Visible"/>


* This source code was highlighted with Source Code Highlighter.



Button 2 Disabled
<ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
         Description="Button 2"
         IsEnabled="False"
         IsBackgroundVisible="True"
         Visibility="Visible"/>


* This source code was highlighted with Source Code Highlighter.



Заметьте что кнопка стала чернобелой, прямо как кнопки перемотки на скриншоте Zune в начале этой статьи.

Настройка поведения кнопки
Есть несколько способов настроить поведение кнопок в окне предпросмотра. Можно использовать или команды или обработчики событий. Метод который вы выберете зависит от архитектуры вашего приложения и от ваших привычек.

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

Обработка событий
Для целей демонстрации мы начнем с обработки событий. Вы можете назначить события в коде или прямо в XAML. Я обычно делаю это в коде, но покажу другой способ, я позволю Visual Studio 2010 создать обработчики основываясь на XAML-разметке.

Вот соответствующий XAML-код:
<Window.TaskbarItemInfo>
  <TaskbarItemInfo>
    <TaskbarItemInfo.ThumbButtonInfos>
      <ThumbButtonInfo ImageSource="{StaticResource Button1Image}"
               Click="Button1_Click"
               Description="Button 1" />
      <ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
               Click="Button2_Click"
               Description="Button 2"
               IsEnabled="False"
               IsBackgroundVisible="True"
               Visibility="Visible"/>
      <ThumbButtonInfo ImageSource="{StaticResource Button3Image}"
               Click="Button3_Click"
               Description="Button 3" />
    </TaskbarItemInfo.ThumbButtonInfos>
  </TaskbarItemInfo>
</Window.TaskbarItemInfo>

* This source code was highlighted with Source Code Highlighter.


А вот исходный программный код:
public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
  }

  private void Button1_Click(object sender, EventArgs e)
  {
    MessageBox.Show("Button 1");
  }

  private void Button2_Click(object sender, EventArgs e)
  {
    MessageBox.Show("Button 2");
  }

  private void Button3_Click(object sender, EventArgs e)
  {
    MessageBox.Show("Button 3");
  }
}

* This source code was highlighted with Source Code Highlighter.


Теперь попробуем подход с использованием команд.

Команды
Это требует немного большей настройки, но более соответствует топу что реальное приложение будет делать. Часто кнопки в панели предпросмотра это просто специализированные копии кнопок с вашего тулбара. Использование команд позволяет указать этим кнопкам использовать тот же код который вы реализуете для главных кнопок с тулбара. В дополнение к лучшей структуре и вторичному использованию кода, вы также получаете дополнительные бонусы, такие как автоматическая установка свойства IsEnabled.

Создание Команд
Сначала мы создадим три класса команд в папке Commands нашего проекта. Наши классы не будут делать ничего сильно различающегося, но мы всё равно создадим три разных класса. В вашем собственном коде продумывайте когда лучше использовать общие команды с делегатами, а когда лучше использовать более устойчивые реализации команд, такие как были представлены в Prism.



class RedCommand : ICommand
{
  public bool CanExecute(object parameter)
  {
    // Тут разместите код проверки на возможность выполнения команды
    return true;
  }

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter)
  {
    // Обработка нажатия кнопки тут
    MessageBox.Show("Red Command.");
  }
}

class GreenCommand : ICommand
{
  public bool CanExecute(object parameter)
  {
    // Тут разместите код проверки на возможность выполнения команды
    return false;
  }

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter)
  {
    // Обработка нажатия кнопки тут
    MessageBox.Show("Green Command.");
  }
}

class BlueCommand : ICommand
{
  public bool CanExecute(object parameter)
  {
    // Тут разместите код проверки на возможность выполнения команды
    return true;
  }

  public event EventHandler CanExecuteChanged;

  public void Execute(object parameter)
  {
    // Обработка нажатия кнопки тут
    MessageBox.Show("Blue Command.");
  }
}

* This source code was highlighted with Source Code Highlighter.


Это не лучший способ для использования команд. Я советую вам изучить больше о командах перед тем как изучать их в вашем собственном приложении. Вот два видео которые могут помочь(видео на английском — прим. пер.)

•How Do I: Use Command Binding in WPF
•How Do I: Create a Custom Command in WPF

Создание ViewModel
Сначала нам нужно место где их расположить. ViewModel это подходящее место для таких вещей. Создайте новый класс с названием MainViewModel (да, это ужасное имя) и заполните его соответствующими свойствами с нашими командами.

class MainViewModel
{
  private RedCommand _redCommand = new RedCommand();
  public ICommand RedCommand
  {
    get { return _redCommand; }
  }

  private GreenCommand _greenCommand = new GreenCommand();
  public ICommand GreenCommand
  {
    get { return _greenCommand; }
  }

  private BlueCommand _blueCommand = new BlueCommand();
  public ICommand BlueCommand
  {
    get { return _blueCommand; }
  }

  // остальная часть VM
}

* This source code was highlighted with Source Code Highlighter.


Связывание ViewModel и View
Дальше мы предоставим экземпляр ViewModel нашему View. Есть масса способов это сделать, включая:

•Назначение View как ресурса в окне в XAML
•Инстанциирование ViewModel как DataContext для view в XAML
•Назначение ViewModel для View в коде
•Используя dependency injection чтобы включить viewmodel в view

Мы собираемся внедрить ViewModel прямо в наш XAML-код как DataContext нашего окна. Благодаря этому у нас улучшается структура приложения, но мы теряем в тестируемости. Если вы хотите минимизровать связность, вам нужном использовать интерфейсы и подход DI.

<Window x:Class="WpfTaskbarThumbnailButtons.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:viewModels="clr-namespace:WpfTaskbarThumbnailButtons"
    Title="Thumbnail Button Application"
    Height="350"
    Width="525">
  <Window.DataContext>
    <viewModels:MainViewModel />
  </Window.DataContext>


* This source code was highlighted with Source Code Highlighter.


Заметьте что я также создал xmlns:viewModels чтобы указывать где я храню ViewModel. В большинстве приложений у вас будут отдельные папки ViewModel и View, а иногда и отдельные сборки.

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

Подключение кнопок
Это самая простая часть. Теперь, когда вся инфраструктура настроена, и у наш контекст данных(DataContext) настроен на нашу ViewModel, всё что нужно — использовать средства байндинга WPF чтобы привязать свойства ViewModel.

<TaskbarItemInfo>
  <TaskbarItemInfo.ThumbButtonInfos>
    <ThumbButtonInfo ImageSource="{StaticResource Button1Image}"
             Command="{Binding RedCommand}"
             Description="Button 1" />
    <ThumbButtonInfo ImageSource="{StaticResource Button2Image}"
             Command="{Binding GreenCommand}"
             Description="Button 2"
             Visibility="Visible" />
    <ThumbButtonInfo ImageSource="{StaticResource Button3Image}"
             Command="{Binding BlueCommand}"
             Description="Button 3" />
  </TaskbarItemInfo.ThumbButtonInfos>
</TaskbarItemInfo>

* This source code was highlighted with Source Code Highlighter.


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



Наставления для ваших собственных приложений.
Так же как иконки наложения(icon overlays) и показывание прогресса на таскбаре, вам нужно быть разумным о том как использовать эти кнопки. Они должны быть частью общего дизайна пользовательского интерфейса приложения, а не чем то что вы засунули, потому что вы можете это засунуть. Если в вашем приложении есть такая возможность, которая нужна пользователям «по первому зову», без необходимости просмотра полноразмерной версии приложения, такие кнопки вполне подходят вам.

Однако не относитесь к ним как к ещё одному тулбару. Не помещайте туда такие функции, которые более нигде не доступны. В дополнение, не помещайте туда функции которые требуют, чтобы приложение было в фокусе или хотя бы видимо на экране.
Tags:
Hubs:
+32
Comments28

Articles