Programming Windows 7: Taskbar. Part 5 - CustomWindowsManager
We continue to explore the possibilities of the taskbar in Windows 7. Surely you all noticed that if you run the same application several times, Windows 7 will automatically group them into one button on the taskbar. In addition, when you hover over the icon of this application, the taskbar will show a preview set for these windows.
However, we see that the same behavior is implemented for open tabs in Internet Explorer 8. In this case, one instance of IE8 is actually launched (we will omit the technical details) and many tabs. In this case, Internet Explorer displays them as multiple previews. In this case, it is very useful, because right from the taskbar, you can immediately switch to the desired tab.
As you might guess, such functionality is easy to implement for your application. This is true if your window contains a set of other windows (as is the case with IE8). For these purposes, the .NET Interop Sample Library contains the CustomWindowsManager class. Let's take a closer look at creating such an application.
So, for starters, we need to create an application. Let this application work in MDI mode. Our goal is to ensure that all child windows of this application also appear in the taskbar. After creating the main and child windows, let's do the last one.
We need a moment to display a window when this window is already created and ready to go. OnShown event is very suitable for these purposes. In the handler, we must create an instance of the CustomWindowsManager object and pass it the Handle of the child window, as well as the parent window, from the point of view of the MDI model. We will save the link to the CustomWindowsManager object, we will need it later. However, these actions are not enough for correct operation. First, we must subscribe to the ThumbnailRequested event, in which to generate a Bitmap containing the display of our window for pop-ups in the taskbar. Secondly, we must subscribe to the PeekRequested event, in which to generate a Bitmap containing the display of our window to select it at the moment of mouse cursor over the preview of the window in the taskbar.
The ThumbnailRequested event contains a parameter of type BitmapRequestedEventArgs. This object will control what will be displayed on the taskbar. The simplest thing we can do is set the UseWindowScreenshot parameter to true. In this case, a screenshot of the window will be taken without your participation. If you want to display some kind of your own picture in the preview window, you can use the Bitmap parameter, where to put your Bitmap object, which should be displayed. However, you need to understand that this object must have strictly specified dimensions. We can also get these sizes from BitmapRequestedEventArgs. It is clear that here we can manipulate this object as it is convenient for us. For example, we can overlay our image on preview.
The PeekRequested event is intended to highlight a window when you hover over its preview in the taskbar. There is also a parameter of type BitmapRequestedEventArgs. Similarly, you can use the UseWindowScreenshot and Bitmap properties. Note that in these examples I use the DrawToBitmap method of the form. However, I can display the preview of any other control. For example, I can display a TextBox. And finally, you need to call the WindowClosed method when the window closes. The OnClosed event is well suited for this. After that, we got the following application.
If we look at the taskbar, we will see the following.
However, if we begin to change the appearance of the form, we will see that the preview has not changed. This is because Windows 7 did not request a preview receive event. This is especially critical if the form contains content that is constantly changing, such as video. In this case, there is a way to force the preview update. To do this, call the InvalidatePreviews method. This method in each case must be called at the right time. For example, when updating text in a TextBox. For a video, a good option is to call it by timer.
This is how you can easily and simply display the number of child windows of your application. Sample
Application:
Taskbar-WindowsManager.zip
However, we see that the same behavior is implemented for open tabs in Internet Explorer 8. In this case, one instance of IE8 is actually launched (we will omit the technical details) and many tabs. In this case, Internet Explorer displays them as multiple previews. In this case, it is very useful, because right from the taskbar, you can immediately switch to the desired tab.
As you might guess, such functionality is easy to implement for your application. This is true if your window contains a set of other windows (as is the case with IE8). For these purposes, the .NET Interop Sample Library contains the CustomWindowsManager class. Let's take a closer look at creating such an application.
So, for starters, we need to create an application. Let this application work in MDI mode. Our goal is to ensure that all child windows of this application also appear in the taskbar. After creating the main and child windows, let's do the last one.
We need a moment to display a window when this window is already created and ready to go. OnShown event is very suitable for these purposes. In the handler, we must create an instance of the CustomWindowsManager object and pass it the Handle of the child window, as well as the parent window, from the point of view of the MDI model. We will save the link to the CustomWindowsManager object, we will need it later. However, these actions are not enough for correct operation. First, we must subscribe to the ThumbnailRequested event, in which to generate a Bitmap containing the display of our window for pop-ups in the taskbar. Secondly, we must subscribe to the PeekRequested event, in which to generate a Bitmap containing the display of our window to select it at the moment of mouse cursor over the preview of the window in the taskbar.
CustomWindowsManager _windowsManager;
protected override void OnShown(EventArgs args)
{
_windowsManager =
CustomWindowsManager.CreateWindowsManager(Handle, MdiParent.Handle);
base.OnShown(args);
}
The ThumbnailRequested event contains a parameter of type BitmapRequestedEventArgs. This object will control what will be displayed on the taskbar. The simplest thing we can do is set the UseWindowScreenshot parameter to true. In this case, a screenshot of the window will be taken without your participation. If you want to display some kind of your own picture in the preview window, you can use the Bitmap parameter, where to put your Bitmap object, which should be displayed. However, you need to understand that this object must have strictly specified dimensions. We can also get these sizes from BitmapRequestedEventArgs. It is clear that here we can manipulate this object as it is convenient for us. For example, we can overlay our image on preview.
_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;
};
_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;
};
The PeekRequested event is intended to highlight a window when you hover over its preview in the taskbar. There is also a parameter of type BitmapRequestedEventArgs. Similarly, you can use the UseWindowScreenshot and Bitmap properties. Note that in these examples I use the DrawToBitmap method of the form. However, I can display the preview of any other control. For example, I can display a TextBox. And finally, you need to call the WindowClosed method when the window closes. The OnClosed event is well suited for this. After that, we got the following application.
_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;
};
protected override void OnClosed(EventArgs e)
{
if (_windowsManager != null)
{
_windowsManager.WindowClosed();
}
base.OnClosed(e);
}
If we look at the taskbar, we will see the following.
However, if we begin to change the appearance of the form, we will see that the preview has not changed. This is because Windows 7 did not request a preview receive event. This is especially critical if the form contains content that is constantly changing, such as video. In this case, there is a way to force the preview update. To do this, call the InvalidatePreviews method. This method in each case must be called at the right time. For example, when updating text in a TextBox. For a video, a good option is to call it by timer.
private void InvalidateButton_Click(object sender, EventArgs e)
{
_windowsManager.InvalidatePreviews();
}
This is how you can easily and simply display the number of child windows of your application. Sample
Application:
Taskbar-WindowsManager.zip