Pull to refresh

Программируем Windows 7: Taskbar. Часть 5 – CustomWindowsManager

Reading time 4 min
Views 1.2K
Мы продолжаем изучать возможности панели задач в Windows 7. Наверняка все вы обратили внимание на то, что если одно и то же приложение запустить несколько раз, Windows 7 автоматически сгруппирует их в одну кнопку на панели задач. Кроме того при наведении на значок этого приложения панель задач покажет набор preview для этих окон.

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



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

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

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

CustomWindowsManager _windowsManager;

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


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

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

_windowsManager.ThumbnailRequested += (o, e) =>
{
Bitmap bmp = new Bitmap(e.Width, e.Height);
this.DrawToBitmap(bmp, new Rectangle(0, 0, e.Width, e.Height));
e.Bitmap = bmp;
};


Понятно, что здесь мы можем манипулировать этим объектом так как нам удобно. Например, можем наложить на preview нашу картинку.

_windowsManager.ThumbnailRequested += (o, e) =>
{
Bitmap bmp = new Bitmap(e.Width, e.Height);
this.DrawToBitmap(bmp, new Rectangle(0, 0, e.Width, e.Height));
Graphics.FromImage(bmp).DrawImage(Images.coffeecup, 35, 5);
e.Bitmap = bmp;
};


Событие PeekRequested предназначено для того, чтобы выделить окно при наведении мыши на его preview в панели задач. Здесь также присутствует параметр типа BitmapRequestedEventArgs. Аналогичным образом можно использовать свойства UseWindowScreenshot и Bitmap.

_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 формы. Однако, я могу выводить previewлюбого другого элемента управления. Например, я могу отображать TextBox.

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

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

base.OnClosed(e);
}


После этого мы получили следующее приложение.



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



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

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


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



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

Демонстрационное приложение:
Taskbar-WindowsManager.zip
Tags:
Hubs:
+41
Comments 34
Comments Comments 34

Articles