Rudi Grobler

“simple problem or target: a target that is easy to achieve, or a problem that is easy to solve”

Here is a breakdown of the 3 most used browser to access my blog. IE7/8 has soooo many features that makes the browsing experience better (And thy are extremely easy to implement)

Introducing Instant Search

“Starting with Internet Explorer 7, the Instant Search box provides an AutoComplete feature so users can search for similar search terms used in previous searches. Internet Explorer 7 also enables users to add multiple search providers. Search improvements in Internet Explorer 8 focus on helping users search by significantly improving the Instant Search box drop-down menu and supporting search suggestions.”

Here is the provider.xml

<?xml version="1.0" encoding="UTF-8"?>
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/" xmlns:ie="http://schemas.microsoft.com/Search/2008/">
    <ShortName>Rudi Grobler</ShortName>
    <Url type="text/html" template="http://blogs.windowsclient.net/rudigrobler/search.aspx?q={searchTerms}"/>   
</OpenSearchDescription>

After uploading the provider.xml file to my webserver, the next step is to make the search provider discoverable! By adding the following to my header, the instant search box will turn orange to indicate that a search provider can be installed!

<link title="Rudi Grobler" rel="search"
   type="application/opensearchdescription+xml"
   href="http://dotnet.org.za/blogs/rudi/provider.xml">

When you click the orange drop-down arrow, a list of the search providers that are installed and other available options is displayed. When you click the Add Search Providers option, a list of the available providers is displayed.

Last step is to confirm the installation of the provider

Now we can start using the search provider…

Easy, isn’t it?

| More

The last couple of days I’ve been searching and evaluating some point of sale systems for a friend… I found a excellent solution from openbravo! It has just one problem (that could easily be fixed using WPF). The software is designed to run on 1024 x 768! Their are some tweaks you can do to force it to run on 800 x 600 but some panels still do not render properly! I want to run this solution on a panel pc that can only do 800 x 600!

Introducing the ViewBox

“Defines a content decorator that can stretch and scale a single child to fill the available space.”

Now I can place my content inside the ViewBox and always assume I will be displayed at x resolution, if not… it will auto-magically resize it for me!!!


<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <Viewbox>            
        <Canvas Width="1024" Height="768">
            <Rectangle Fill="Gray" Width="100" Height="100" Canvas.Left="120" Canvas.Top="75" />
            <Rectangle Fill="Orange" Width="100" Height="100" Canvas.Left="900" Canvas.Top="600" />
            <Rectangle Fill="Red" Width="100" Height="100" Canvas.Left="600" Canvas.Top="400" />
            <Rectangle Fill="LightBlue" Width="100" Height="100" Canvas.Left="450" Canvas.Top="90" />
        </Canvas>
    </Viewbox>
</Window>

Easy? isn’t it!!!

DISCLAIMER: DO NOT USE THIS EVERYWHERE! The ViewBox is not for every single application! It works great in KIOSK type applications where the application will almost always run at a known resolution!

| More

Reporting is one of those things that we hate but can’t live without!

WPF is a awesome platform with so many powerful controls available! I have seen so many people use FlowDocuments to create reports! This is really cool but what if you need a more complex reporting engine! Can it handle it? Can it be abstracted and reused! Do you have to start from scatch each time?

Introducing Open-Source .NET WPF Reporting Engine

“This project allows you to create reports using WPF (Windows Presentation Foundation). Its supports headers and footers, DataTable binding, barcode generation, XPS creation and more.”

First things, first… Create a ReportDocument. This is the “container" for our report

ReportDocument reportDocument = new ReportDocument();

Next, we need to supply a template for our report. 

StreamReader reader = new StreamReader(new FileStream(@"Templates\SimpleReport.xaml", FileMode.Open, FileAccess.Read)); 
reportDocument.XamlData = reader.ReadToEnd(); 
reportDocument.XamlImagePath = Path.Combine(Environment.CurrentDirectory, @"Templates\"); 
reader.Close();

Here is how our template looks

<FlowDocument xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:xrd="clr-namespace:CodeReason.Reports.Document;assembly=CodeReason.Reports" 
              PageHeight="29.7cm" PageWidth="21cm" ColumnWidth="21cm">
    <xrd:ReportProperties>
        <xrd:ReportProperties.ReportName>SimpleReport</xrd:ReportProperties.ReportName>
        <xrd:ReportProperties.ReportTitle>Simple Report</xrd:ReportProperties.ReportTitle>
    </xrd:ReportProperties>
    <Section Padding="80,10,40,10" FontSize="12">
        <Paragraph FontSize="24" FontWeight="Bold">
            <xrd:InlineContextValue PropertyName="ReportTitle" />
        </Paragraph>
        <Paragraph>This is a simple report example that contains a table.
            The table is filled using a DataTable object.</Paragraph>
        <xrd:SectionDataGroup DataGroupName="ItemList">
            <Paragraph FontSize="20" FontWeight="Bold">Item List</Paragraph>
            <Table CellSpacing="0" BorderBrush="Black" BorderThickness="0.02cm">
                <Table.Resources>
                    <!-- Style for header/footer rows. -->
                    <Style x:Key="headerFooterRowStyle" TargetType="{x:Type TableRowGroup}">
                        <Setter Property="FontWeight" Value="DemiBold"/>
                        <Setter Property="FontSize" Value="16"/>
                        <Setter Property="Background" Value="LightGray"/>
                    </Style>

                    <!-- Style for data rows. -->
                    <Style x:Key="dataRowStyle" TargetType="{x:Type TableRowGroup}">
                        <Setter Property="FontSize" Value="12"/>
                    </Style>

                    <!-- Style for data cells. -->
                    <Style TargetType="{x:Type TableCell}">
                        <Setter Property="Padding" Value="0.1cm"/>
                        <Setter Property="BorderBrush" Value="Black"/>
                        <Setter Property="BorderThickness" Value="0.01cm"/>
                    </Style>
                </Table.Resources>

                <Table.Columns>
                    <TableColumn Width="0.5*" />
                    <TableColumn Width="2*" />
                    <TableColumn Width="*" />
                    <TableColumn Width="0.5*" />
                </Table.Columns>
                <TableRowGroup Style='{StaticResource headerFooterRowStyle}'>
                    <TableRow>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>Pos.</Bold>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>Item Name</Bold>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>EAN</Bold>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <Bold>Count</Bold>
                            </Paragraph>
                        </TableCell>
                    </TableRow>
                </TableRowGroup>
                <TableRowGroup Style='{StaticResource dataRowStyle}'>
                    <xrd:TableRowForDataTable TableName='Ean'>
                        <TableCell>
                            <Paragraph>
                                <xrd:InlineTableCellValue PropertyName='Position' />
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph>
                                <xrd:InlineTableCellValue PropertyName='Item' />
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph>
                                <xrd:InlineTableCellValue PropertyName='EAN'/>
                            </Paragraph>
                        </TableCell>
                        <TableCell>
                            <Paragraph TextAlignment='Center'>
                                <xrd:InlineTableCellValue PropertyName='Count' AggregateGroup='ItemCount'/>
                            </Paragraph>
                        </TableCell>
                    </xrd:TableRowForDataTable>
                </TableRowGroup>
            </Table>
            <Paragraph>
                There are
                <xrd:InlineAggregateValue AggregateGroup='ItemCount' AggregateValueType='Count' EmptyValue='no' FontWeight='Bold' /> item positions with a total of
                <xrd:InlineAggregateValue AggregateGroup='ItemCount' AggregateValueType='Sum' EmptyValue='0' FontWeight='Bold' /> items listed.
            </Paragraph>
        </xrd:SectionDataGroup>
    </Section>
</FlowDocument>

I will go into more detail on how to customize this template in future posts. Now the data…

ReportData data = new ReportData();

First add some “metadata”

data.ReportDocumentValues.Add("PrintDate", DateTime.Now);

And then the DataTables

data.DataTables.Add(table);

Here, table is of type DataTable.

And that is it!

Finally export it to Xps and show

XpsDocument xps = reportDocument.CreateXpsDocument(data);

You can use the standard DocumentViewer to display the report

Read more

| More

If you ever worked on a relatively large WPF project, you probable at some point wanted to know which resources are used by a specific element? The problem is even harder if these resources are in multiple resource dictionaries? Imagine if you have a base resource dictionary with some “default” color and then a separate resource dictionary with the actually style! This can very easily get out of hand! Luckily blend makes it “super easy” to determine which resources are used by a selected control!

Select the element on the design surface, open the Resources tab and click on the “Show resources used by selected element”. This will filter all the resources to only show the resources that are used by this element!

| More

This weekend was Devs4Devs and we had a blast! Here is my slide deck

SketchFlow in 20 minutes or less

Thank you to everyone who attended my session!

Since joining BB&D, I also get a opportunity to present ASTRA or TR sessions, here is the slide decks of my recent presentations

Composite Application Library (PRISM)

SketchFlow

What’s new in Silverlight 3.0

ImagineCup 2009 - Microsoft Robotics Studio 2008

I will also start slowly uploading older presentations from Tech-ed and Developer Days!

| More

I FINALLY managed to finish the series on all the COOL stuff in the new Windows 7 taskbar!

If you want to see a “real” application using some of these features, check out Fishbowl

“Experience your Facebook content in new ways with a trial desktop client application that lets you personalize how you read your newsfeed, update status, comment, like, browse and upload photos.”

Also download the source from codeplex: http://fishbowl.codeplex.com/

Other

 

If you application is associated with a specific file extension, then you get the last part for free! The taskbar also list files opened by your application in the Recent category!

To check if your file extension is associated with your application, open your registry editor and navigate too HKEY_CLASSES_ROOT and search for your extension!

Here is a code snippet to check

RegistryKey openWithKey = Registry.ClassesRoot.OpenSubKey(Path.Combine(".wpost", "OpenWithProgIds")); 
string value = openWithKey.GetValue(progId, null) as string; 

if (value == null) 
{ 
   // No extension registered 
} 
else 
{ 
   // File extension is registered 
}

Registering a file extension is extremely easy using the RegistrationHelper

string executablePath = Assembly.GetEntryAssembly().Location; 

RegistrationHelper.RegisterFileAssociations( 
   "LiveWriter", 
   false, 
   "LiveWriter", 
   executablePath + " /doc %1", 
   ".wpost");

To manually report file usage to shell, call the AddToRecent

jumpList.AddToRecent(fileName);

Note: The dialog box automatically reports usage to shell, but it's still recommended that the user explicitly calls AddToRecent. Shell will automatically handle duplicate additions.

And that’s it…

The last topic I want to cover about the Windows 7 taskbar is the Jumplist!!!

To create a new JumpList, call CreateJumpList()

JumpList jumplist = JumpList.CreateJumpList();

We should now choose if we are only creating user tasks or custom categories? I decided to create user tasks

jumplist.AddUserTasks(new JumpListLink(Path.Combine(Environment.CurrentDirectory, "MiMail.exe"), "Mail") { Arguments = "mail" });
jumplist.AddUserTasks(new JumpListLink(Path.Combine(Environment.CurrentDirectory, "MiMail.exe"), "Contacts") { Arguments = "contacts" });
jumplist.AddUserTasks(new JumpListLink(Path.Combine(Environment.CurrentDirectory, "MiMail.exe"), "Calendar") { Arguments = "calendar" });

We could also use custom categories to group our tasks

JumpListCustomCategory category = new JumpListCustomCategory("Mail");
category.AddJumpListItems(new JumpListLink(Path.Combine(Environment.CurrentDirectory, "MiMail.exe"), "Inbox") { Arguments = "inbox" });
category.AddJumpListItems(new JumpListLink(Path.Combine(Environment.CurrentDirectory, "MiMail.exe"), "New Message") { Arguments = "newMessage" });
jumplist.AddCustomCategories(category);

Don’t forget to call Refresh()

jumplist.Refresh();

Now, if you read my previous blog post and had no clue why you would want to use it? JumpList allows you to specify a application (and its arguments) to be executed if you click on a user task!!!

Cool, isn’t it?

To remove all the user tasks

jumplist.ClearAllUserTasks();

User tasks is also available if the application is pinned to the taskbar (If not removed)!

Related Posts – Anatomy of the Windows 7 taskbar series

Imagine for a second that you are writing a application like outlook… lets call it MiMail.exe! This application is very basic and has 3 views that are relevant to me! i want to be able to see my mail, contacts and calendar! There is also 3 specific tasks that I want to be able to execute: new mail, new contact and new appointment!

At any given time, I only want one instance of this application running but I want to be able to execute these task by using the command line arguments, ie:

MiMail.exe /mail

MiMail.exe /newContact

I am going to use a variation of the mediator pattern to facilitate the inter process communication via named pipes!

Mediator Pattern

The mediator pattern, one of the 23 design patterns described in Design Patterns: Elements of Reusable Object-Oriented Software, provides a unified interface to a set of interfaces in a subsystem. This pattern is considered to be a behavioral pattern due to the way it can alter the program's running behavior.

Usually a program is made up of a (sometimes large) number of classes. So the logic and computation is distributed among these classes. However, as more classes are developed in a program, especially during maintenance and/or refactoring, the problem of communication between these classes may become more complex. This makes the program harder to read and maintain. Furthermore, it can become difficult to change the program, since any change may affect code in several other classes.

With the mediator pattern communication between objects is encapsulated with a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator. This reduces the dependencies between communicating objects, thereby lowering the coupling.

Ok, so variation is maybe a under statement… more like abuse the mediator pattern!

Named Pipes

In computing, a named pipe (also known as a FIFO for its behavior) is an extension to the traditional pipe concept on Unix and Unix-like systems, and is one of the methods of inter-process communication. MacOS calls it a socket, which should not be confused with a TCP socket. The concept is also found in Microsoft Windows, although the semantics differ substantially. A traditional pipe is "unnamed" because it exists anonymously and persists only for as long as the process is running. A named pipe is system-persistent and exists beyond the life of the process and must be deleted once it is no longer being used. Processes generally attach to the named pipe (usually appearing as a file) to perform inter-process communication (IPC).

A good friend and fellow MVP, Mario Lionello, helped me out getting the asynchronous named pipes to work! I included his MaLio.AsyncPipes library!!!

Here is my updated App.xaml.cs

public partial class App : Application
{
   const string appName = "MiMail";

   private void OnStartup(object sender, StartupEventArgs e)
   {
      if (SingleInstanceManager.IsApplicationRunning())
      {
         foreach (var arg in e.Args)
         {
            Mediator.Notify(appName, arg);
         }

         App.Current.Shutdown();
         return;
      }

      Views.MainView view = new Views.MainView();
      view.DataContext = new ViewModels.MainViewModel();
      view.Show();
   }
}

MiMail is using a very simple mutex to detect if their is a instance of this application running. If the application is already running, use the Mediator to notify the listeners that a new instance was started and pass the command line arguments as messages!

Now I can just wait for new messages!

mediator = new Mediator(appName);

mediator.Register("contacts", ShowContacts);
mediator.Register("calendar", ShowCalendar);
mediator.Register("mail", ShowMail);

Here is a example of the Action<>

void ShowContacts(object message)
{
    this.Dispatcher.Invoke(
        DispatcherPriority.Normal,
        new Action(() => 
        {
            viewHost.Children.Clear();
            viewHost.Children.Add(new ContactsView());
        }));
}

And that is it!!!

Launching “MiMail.exe contacts” will call the ShowContacts action!!!

Source

Related Posts – Anatomy of the Windows 7 taskbar series

Ever noticed the subtle progress overlay while downloading something from the internet? With Windows 7’s new taskbar, applications can visually display their progress on the taskbar!

We first need to set the mode

TaskbarManager.Instance.SetProgressState(TaskbarProgressBarState.Normal);

The Windows 7 taskbar has 5 possible states

  • NoProgress - No progress is displayed.
  • Indeterminate - The progress is indeterminate (marquee).
  • Normal - Normal progress is displayed.
  • Error - An error occurred (red).
  • Paused - The operation is paused (yellow).

If the state is changed to Normal, the you can also set the value

TaskbarManager.Instance.SetProgressValue(50, 100);

Easy? Isn’t it?

What would a post be without trying to make it just a little easier for the WPF developers? I also created a attached property that auto-magically links a WPF ProgressBar to the Windows 7 taskbar…

Here is my very simple demo

<Window x:Class="ProgressDemo.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:="clr-namespace:ProgressDemo"
    Title="ProgressDemo" Height="100" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Slider Minimum="0" Maximum="100" x:Name="source" Grid.Row="0" />
        <ProgressBar Minimum="0" Maximum="100" Grid.Row="1" Height="20"
             Value="{Binding ElementName=source, Path=Value}" 
             local:Win7.ShowProgressInTaskbar="True" />
    </Grid>
</Window>

As you can see from this XAML, I created a Slider and bound it to the ProgressBar. To make the ProgressBar auto-magically update the Windows 7 taskbar, all we need to do is set the ShowProgressInTaskbar=”True”!!!

Source

Related Posts – Anatomy of the Windows 7 taskbar series

In my “quest” to create thumbnails similar to the once used in IE8, I hit a couple of snags! In part 1 we looked at the basics of creating a TabbedThumbnail. This is still a very manual process so I decided to make it more WPF-like!

Introducing TabbedThumbnailContentControl

Maybe I should take a step back and first recap what a ContentControl is in WPF?

Represents a control with a single piece of content.

http://msdn.microsoft.com/en-us/library/system.windows.controls.contentcontrol.aspx

Ok, so that isn’t the greatest MSDN article every but the ContentControl is a fundamental building block of WPF… As you might have guest by now, the TabbedThumbnailContentControl is a UI element that can host a single piece of content! The magic thou is that it will auto-magically create the TabbedThumbnail for you and show as its preview what-ever you placed inside the content control!!!

And to make it a little more useful, its also fully MVVM-able! The TabbedThumbnailControl exposes 2 commands that can be bound too by the VM:

  • ActivateView - The event that occurs when a tab is activated (clicked) on the taskbar thumbnail preview.
  • CloseView - The event that occurs when a tab is closed on the taskbar thumbnail preview.

And to use the TabbedThumbnailContentControl? Very easy… Here is my view

<ListBox ItemsSource="{Binding}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <local:TabbedThumbnailContentControl Title="{Binding Title}" ActivateView="{Binding ActivatedCommand}" CloseView="{Binding CloseCommand}">
                <Image Source="{Binding Path}" Width="200" Height="200" />
            </local:TabbedThumbnailContentControl>
        </DataTemplate>
    </ListBox.ItemTemplate>
    <ListBox.ItemContainerStyle>
        <Style TargetType="{x:Type ListBoxItem}">
            <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
        </Style>
    </ListBox.ItemContainerStyle>
</ListBox>

My ViewModel

public class PhotoViewModel : WorkspaceViewModel
{
    public string Title { get; set; }
    public string Path { get; set; }

    private bool isSelected = false;
    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            if (isSelected != value)
            {
                isSelected = value;
                OnPropertyChanged("IsSelected");
            }
        }
    }

    ICommand activatedCommand;
    public ICommand ActivatedCommand
    {
        get
        {
            if (activatedCommand == null)
                activatedCommand = new DelegateCommand(Activated);

            return activatedCommand;
        }
    }

    private void Activated()
    {
        IsSelected = true;
    }
}

My VM borrowed Josh’s WorkspaceViewModel base class (To support a VM closing itself)!

And that is it! Now I can add photos to my ListBox and it would be showed in the taskbar! Their is also FULL integration! If you close a thumbnail in the taskbar it will be removed from the ListBox

Source

Related Posts – Anatomy of the Windows 7 taskbar series

One of the “features” of the new taskbar that excites me is the TabbedThumbnail interface! This allows me to quickly see which applications are open and what their status is! From the screen capture above you can easily see that I have my favourite google group (The WPF Disciples) open and also my own website (Shameless plug). Even these buttons are customizable… and it’s VERY easy to do!!!

To create a new TabbedThumbnail

preview = new TabbedThumbnail(this, this, VisualTreeHelper.GetOffset(this));
preview.Tooltip = "This is a awesome new tooltip";
preview.Title = "Customer XYZ";
preview.DisplayFrameAroundBitmap = true;

And to use it

TaskbarManager.Instance.TabbedThumbnail.AddThumbnailPreview(preview);

Although I am using the TabbedThumbnail at its most basic form here, it’s got loads of options, here are some examples

  • TabbedThumbnailClosed - The event that occurs when a tab is closed on the taskbar thumbnail preview.
  • TabbedThumbnailMaximized - The event that occurs when a tab is maximized via the taskbar thumbnail preview (context menu).
  • TabbedThumbnailMinimized - The event that occurs when a tab is minimized via the taskbar thumbnail preview (context menu).
  • TabbedThumbnailActivated - The event that occurs when a tab is activated (clicked) on the taskbar thumbnail preview.
  • TabbedThumbnailBitmapRequested - The event that occurs when a thumbnail or peek bitmap is requested by the user.

If you have content that constantly changes (Think media player), you can also call InvalidatePreview!

And that’s it for part 1, in part 2 we will cover custom peek areas and multi-tab interface (Like IE8)

Related Posts – Anatomy of the Windows 7 taskbar series

One of the cool new features of the Windows 7 taskbar is that all running applications gives you this nice feedback that its running using the color hot-track “feature”

“Color hot-track is a small touch that typifies the new taskbar’s personality. When a person moves her mouse over a running program on the taskbar, she will be pleasantly surprised to find that a light source tracks her mouse and the color of the light is actually based on the icon itself. We calculate the most dominant RGB of the icon and dynamically paint the button with this color. Color hot-track provides a delight factor, it offers feedback that a program is running and it showcases a program’s icon. We’ve always believed that programs light up the Windows platform and now, we’re returning the favor.”

Engineering Windows 7 - The Windows 7 Taskbar

A while back I read a article from Grant Hinkson called “McGuffin”-Enabling Image Converter!

“This converter is bound to an Image’s Source property and then returns an “averaged” Color”

I “borrowed” his idea and created my own value converter that takes a icon (BitmapFrame), calculates the average color and the create a linear gradient brush using this color!

public class IconToAvgColorBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return new SolidColorBrush(Colors.Transparent);
        }

        MemoryStream stream = new MemoryStream();
        if (value is BitmapFrame)
        {
            BitmapFrame frame = (BitmapFrame)value;
            System.Windows.Media.Imaging.BmpBitmapEncoder e = new BmpBitmapEncoder();
            e.Frames.Add(frame);
            e.Save(stream);
        }

        try
        {
            Bitmap bitmap = new Bitmap(stream);

            int tr = 0;
            int tg = 0;
            int tb = 0;

            for (int x = 0; x < bitmap.Width; x++)
            {
                for (int y = 0; y < bitmap.Height; y++)
                {
                    System.Drawing.Color pixel = bitmap.GetPixel(x, y);
                    tr += pixel.R;
                    tg += pixel.G;
                    tb += pixel.B;
                }
            }

            byte r = (byte)Math.Floor((double)(tr / (bitmap.Height * bitmap.Width)));
            byte g = (byte)Math.Floor((double)(tg / (bitmap.Height * bitmap.Width)));
            byte b = (byte)Math.Floor((double)(tb / (bitmap.Height * bitmap.Width)));

            LinearGradientBrush brush = new LinearGradientBrush();
            brush.EndPoint = new System.Windows.Point(0.5, 1.0);
            brush.StartPoint = new System.Windows.Point(0.5, 0.0);
            brush.GradientStops.Add(new GradientStop(System.Windows.Media.Color.FromArgb(0xFF, r, g, b), 0.00));
            brush.GradientStops.Add(new GradientStop(System.Windows.Media.Color.FromArgb(0x00, r, g, b), 1.00));
            return brush;
        }
        catch (Exception)
        {
            return new SolidColorBrush(Colors.Transparent);
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new Exception("The method or operation is not implemented.");
    }
}

[DISCLAIMER] This code still needs some error checking…

The next part could be re-factored into a control but I just wanted to show the basics! I create a style that changes the background color from transparent to the average color using triggers!

<local:IconToAvgColorBrushConverter x:Key="iconToAvgColorBrushConverter"/>

<Style x:Key="ColorHotTrackButton" TargetType="{x:Type Button}" BasedOn="{x:Null}">
    <!-- Removed for brevity -->
</Style>

And to use it is very simple!

<Button Margin="2.5,0,2.5,0" Style="{DynamicResource ColorHotTrackButton}" Background={Binding Path=Source, Converter={StaticResource iconToAvgColorBrushConverter}, ElementName=explorerIcon, Mode=Default}">
    <Image Source="Assets/IE.ico" Width="32" Height="32" Margin="12.5,0,12.5,0" x:Name="ieIcon" />        
</Button>

Here is the end result…

Source

Related Posts – Anatomy of the Windows 7 taskbar series

As you would expect from Microsoft, Office integrates very nicely with Windows 7 taskbar! Have a look at the following 2 taskbar icons:

And if I have unread mail

These “visual clues” makes status changes look natural! And the best of all? It’s sooooo easy to do!

TaskbarManager.Instance.SetOverlayIcon(this.Handle, TaskbarDemo.Properties.Resources.IveGotMail, "IveGotMail");

and to remove the visual clues

TaskbarManager.Instance.SetOverlayIcon(this.Handle, null, null);

Easy? Isn’t it… To make your application play nice with Windows 7 isn’t very difficult!!!

Related Posts – Anatomy of the Windows 7 taskbar series

With Windows 7’s public release less than 2 weeks away (22 October 2009) I decided to dig into how the taskbar works! I will specifically be looking at it from a developers point of view! Before we start, download the Windows® API Code Pack for Microsoft® .NET Framework

The Windows® API Code Pack for Microsoft® .NET Framework provides a source code library that can be used to access some new Windows 7 features (and some existing features of older versions of Windows operating system) from managed code. These Windows features are not available to developers today in the .NET Framework.

The first part we will be dissecting is the ThumbnailToolbarButton

buttonPrevious = new ThumbnailToolbarButton(Properties.Resources.prevArrow, "Previous");
buttonPrevious.Enabled = false;
buttonPrevious.Click += new EventHandler(buttonPrevious_Click);

buttonNext = new ThumbnailToolbarButton(Properties.Resources.nextArrow, "Next");
buttonNext.Enabled = false;
buttonNext.Click += new EventHandler(buttonNext_Click);

buttonPlay = new ThumbnailToolbarButton(Properties.Resources.play, "Play");
buttonPlay.Click += new EventHandler(buttonPlay_Click);

And to actually add it to the TabbedThumbnail?

TaskbarManager.Instance.ThumbnailToolbars.AddButtons(new WindowInteropHelper(this).Handle, buttonPrevious, buttonPlay, buttonNext);

Other properties of note:

  • IsInteractive - Non-interactive buttons don't display any hover behavior nor do they raise click events. They are intended to be used as status icons. This is mostly similar to being not Enabled, but the image is not desaturated.
  • DismissOnClick - If set to true, the taskbar button's flyout will close immediately. Default is true.
  • Enabled - If the button is disabled, it is present, but has a visual state that indicates that it will not respond to user action. Default is true.

We will be seeing more and more of this kind of integration in the future! Web browsers forward/back navigation integration, Media player play/next/previous, etc!

PS. Don’t forget to check if your OS supports this before just using it!!!

if (TaskbarManager.IsPlatformSupported)
{
    // ...
}

Related Posts – Anatomy of the Windows 7 taskbar series

More Posts Next page »