Introduction
In this tutorial, I will explain how to create a Windows taskbar in C# with the Merula Shell Library.
You can download the Merula Shell Library here.
First, create a new project in Visual Studio. In the new project window, choose a WPF application. Add the three DLLs from the Merula shell library to the reference of the project.
Creating a Usercontrol
For every window, I want to create a fancy button with an image and the tile, in my taskbar. So let’s create a usercontrol, I called it TaskbarButton
.
<UserControl x:Class="DemoProject.TaskbarButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="32" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Name="imgIcon"/>
<TextBlock Name="lblTitle" Grid.Column="1" Margin="4" />
</Grid>
</UserControl>
In the usercontrol, add an image control and a textblock control.
Add the following code in the codebehind from the usercontrol:
using System;
using System.Windows.Controls;
using Window = MerulaShell.windows.Window;
namespace DemoProject
{
public partial class TaskbarButton : UserControl
{
private readonly Window window;
public TaskbarButton(Window window)
{
InitializeComponent();
this.window = window;
window.TitleChanged += WindowTitleChanged;
SetProperties();
}
private delegate void DelegateVoid();
void WindowTitleChanged(object sender, EventArgs e)
{
Dispatcher.Invoke(new DelegateVoid(SetTitle));
}
private void SetTitle()
{
lblTitle.Text = window.Title;
}
private void SetProperties()
{
imgIcon.Source = window.ProgramIcon;
lblTitle.Text = window.Title;
}
}
}
Your usercontrol will now look something like this:
Loading Windows
The next step is loading the windows in our taskbar. Go to the XAML of the main window and replace the grid with the stackpanel.
My main window XAML is as follows:
<Window x:Class="DemoProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<StackPanel Name="pnlTasks">
</StackPanel>
</Window>
Add the following code to the codebehind of the mainwindow:
using System;
using System.Windows;
using MerulaShellController.ManageWindows;
namespace DemoProject
{
public partial class MainWindow : Window
{
private ManageWindows windowManager;
public MainWindow()
{
InitializeComponent();
windowManager = new ManageWindows();
Closed += MainWindow_Closed;
windowManager.WindowListChanged += WindowManagerWindowListChanged;
LoadWindows();
}
private delegate void DelegateVoid();
void WindowManagerWindowListChanged(object sender, EventArgs e)
{
Dispatcher.Invoke(new DelegateVoid(LoadWindows));
}
void MainWindow_Closed(object sender, EventArgs e)
{
Environment.Exit(0);
}
private void LoadWindows()
{
ClearTasks();
var windows = windowManager.GetWindows();
foreach (var window in windows)
{
pnlTasks.Children.Add(new TaskbarButton(window));
}
}
private void ClearTasks()
{
pnlTasks.Children.Clear();
}
}
}
As a result, we now have a window with the current active windows. The list of windows will be updated when the number of windows change and if a tile of a window changes.
Making It Interactive
You still can’t interact with the windows, like minimize or maximize them. Open up the TaskButton
usercontrol. Add a MouseUp
handler to the usercontrol tag.
MouseUp="UserControlMouseUp"
Add the following code to the codebehind of the usercontrol:
private bool active;
private void UserControlMouseUp
(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
Background = Brushes.LightBlue;
if(active)
window.MaximizeMinimize();
else
{
active = true;
window.SetToForeground();
}
InvokeActivated(new EventArgs());
}
public void SetNonActive()
{
active = false;
Background = Brushes.White;
}
public event EventHandler Activated;
public void InvokeActivated(EventArgs e)
{
EventHandler handler = Activated;
if (handler != null) handler(this, e);
}
You’ll also have to edit the code behind of the mainwindow. Change the method LoadWindows()
:
private void LoadWindows()
{
ClearTasks();
var windows = windowManager.GetWindows();
foreach (var window in windows)
{
var button = new TaskbarButton(window);
button.Activated += ButtonActivated;
pnlTasks.Children.Add(button);
}
}
Last but not least, you’ll have to create an event handler. Add it to the codebehind of the mainwindow:
void ButtonActivated(object sender, EventArgs e)
{
var senderButton = (TaskbarButton) sender;
var otherButtons = pnlTasks.Children.OfType<TaskbarButton>().Where
(b => b != senderButton);
foreach (var otherButton in otherButtons)
{
otherButton.SetNonActive();
}
}
As a result, you have a working taskbar.
Merula Shell
More information about merula shell can be found at the following links:
History
- 3rd June, 2011: Initial post