Archive for the ‘WPF’ Category

UIAutomation to open ComboBox from Code

Sunday, May 18th, 2008

In WPF there’s an Automation Framework called UIAutomation. This Framework can be used to control UIElements from code. This can be useful for different scenarios:

  • Provide the user additional help
  • Control a programm by another programm
  • Test applications
  • Execute a user-action from code

The Automation Frameowork isn’t limited to WPF. You can also control Win32-Applications.

In WPF for every FrameworkElement you find a class named like [TheElementsName]AutomationPeer. E.g. for the Button-class there’s a ButtonAutomationPeer-class, for ComboBox there’s a ComboBoxAutomationPeer-class…

Such AutomationPeer-Classes support different Patterns. E.g. the ComboBoxAutomationPeer-class supports the ExpandCollapse-Pattern to expand and collapse the ComboBox. You do this with the following snippet:

ComboBoxAutomationPeer peer =
  new ComboBoxAutomationPeer(yourComboBox);
IExpandCollapseProvider provider =
  (IExpandCollapseProvider)
  peer.GetPattern(PatternInterface.ExpandCollapse);
provider.Expand();

There’s much more you can do with UIAutomation, which is part of my German WPF-book (Chapter 19).

WPF Multi-Layer Business Application for Download

Friday, May 16th, 2008

Tomorrow Karl Shifflett is giving a Code Camp session in Charlotte. Unfortunately it’s too far away for me to participate. :-)

Today Karl has posted a really great WPF Multi-Layer Business Application that can be downloaded from his blog. Check it out here and learn from it. Thx to Karl for posting and sharing that great sample app.

LostFocus (TextBox) vs. Buttons IsDefault-Property

Friday, May 2nd, 2008

If you bind the Text-Property of a TextBox to something, the "something" is updated when the TextBox loses focus. This is the Default-UpdateSourceTrigger defined in the Metadata for the TextBox.TextProperty. In a Data Binding you can specify another UpdateSourceTrigger, like e.g. PropertyChanged.

If a TextBox has LostFocus as UpdateSourceTrigger, which is the default, you can get problems if the TextBox is inside of a Dialog that contains a OK-Button with the IsDefault-Property set to true. When the TextBox has the Focus, the user can press Enter and the Button is clicked, but the TextBox still keeps the Focus. The LostFocus-Event doesn’t occur, so the Source of a Data Binding isn’t updated with the value of the TextBoxs Text-Property. You need to update the source explicit. Let’s take an example and use the Person-class of my previous post:

public class Person : INotifyPropertyChanged
{
  private string _name;
  public string Name
  {
    get { return _name; }
    set
    {
      _name = value;
      if (PropertyChanged != null)
        PropertyChanged(this,
          new PropertyChangedEventArgs("Name"));
    }
  }
  public event PropertyChangedEventHandler PropertyChanged;
}

The Window below just contains a TextBox and a Button. The Text-Property of the TextBox is bound to the Name of the data in the DataContext. This would be a Person-instance, as you’ll see below in the codebehind-file. The Button has it’s IsDefault-Property set to true and defines an eventhandler for the Click-Event.

<Window x:Class="LostFocusTest.Window1" ...
  xmlns:local="clr-namespace:LostFocusTest"
  Title="Focus/IsDefault" Width="200" SizeToContent="Height">
  <StackPanel>
    <TextBox Margin="5" Text="{Binding Name}"/>
    <Button Content="OK" IsDefault="True"
       Click="Button_Click"/>
  </StackPanel>
</Window>

In the Constructor in the Codebehind-file a Person-instance is created. It’s assigned to the Windows DataContext-Property, so the TextBox above will display the Persons name, which is set to "Thomas". The Click-Eventhandler for the Button simply displays the name of the Person in a MessageBox.

public partial class Window1 : Window
{
  private Person _pers;
  public Window1()
  {
    InitializeComponent();
    _pers = new Person();
    _pers.Name = "Thomas";
    this.DataContext = _pers;
  }

  private void Button_Click(object sender, RoutedEventArgs e)
  {
    MessageBox.Show(_pers.Name);
  }
}

If I start the application and type "Urs" into the TextBox and press Enter, the Button is clicked but the TextBox keeps the focus. So the Source, which is the Person-Instance, isn’t updated and the MessageBox still displays the old value (“Thomas”), as you can see in the Image below:

LostFocus vs. IsDefault

For such a scenario, you have to update the source explicit. You could do this in the Click-Eventhandler. To update the source, you have to get the BindingExpression for the TextProperty. You get the BindingExpression by calling the GetBindingExpression-Method on the TextBox. Pass in the Text-Property as parameter. On the BindingExpression call the UpdateSource-Method to update the Person-instance explicitly with the value defined in the Text-Property of the TextBox. With the Eventhandler below the Person-Instance would always be actualized when the Button is clicked. The MessageBox would display the right value:

private void Button_Click(object sender, RoutedEventArgs e)
{
  TextBox textBox = Keyboard.FocusedElement as TextBox;
  if (textBox != null)
  {
    BindingExpression be =
      textBox.GetBindingExpression(TextBox.TextProperty);
    if (be != null)
      be.UpdateSource();
  }
  MessageBox.Show(_pers.Name);
}

Just kick it for me:

kick it on DotNetKicks.com

Vista’s SaveFileDialog and OpenFileDialog in WPF

Saturday, April 12th, 2008

Windows Vista contains new Win32-Dialogs to save and open a file. There are also the old dialogs from XP available.

Windows Presentation Foundation has two wrapper-classes for Win32-Dialogs. The Microsoft.Win32-Namespace contains a SaveFileDialog- and an OpenFileDialog-class. The classes are located in the PresentationFramework-Assembly, one of the central assemblies of WPF.

When you use the classes from Microsoft.Win32-Namespace, you get the old dialogs from XP. In the snippet below the OpenFileDialog is opened.

Microsoft.Win32.OpenFileDialog dlg =
  new Microsoft.Win32.OpenFileDialog();
dlg.ShowDialog()

With the two lines above the dialog below is shown, and that’s the old-style Windows XP OpenFileDialog:

image

Windows Forms also wraps the two Dialogs SaveFileDialog and OpenFileDialog with classes in the namespace System.Windows.Forms. Add a reference to the assembly System.Windows.Forms.dll to your WPF-Project, and you can use these wrapper-classes. The interesting part is that they show per default the new Vista Dialog.

System.Windows.Forms.OpenFileDialog dlg =
  new System.Windows.Forms.OpenFileDialog();
dlg.ShowDialog();

With the lines above the new Vista Dialog is displayed:

image

Both WinForms-Dialog-Classes contain a property called AutoUpgradeEnabled (inherited from FileDialog, property is supported in .NET Versions 3.5, 3.0 SP1 and 2.0 SP1). This property is per default true, so the FileDialog-Instance will automatically upgrade appearance and behavior when running on Windows Vista. Set it to false, to get the old dialog-style:

System.Windows.Forms.OpenFileDialog dlg =
  new System.Windows.Forms.OpenFileDialog();
dlg.AutoUpgradeEnabled = false;
dlg.ShowDialog();

On XP, the AutoUpgradeEnabled-property doesn’t have any effect, of course, there’s only the old dialog available.

Fazit: The cool thing about Microsoft.Win32 is that you can add a using-directive to your WPF-Project and use the classes inside that namespace without a full qualified name. Adding a using-directive for System.Windows.Forms isn’t a good thing in a WPF-Project. There are many double-matches in System.Windows.Forms and e.g. WPF’s System.Windows.Controls-Namespace, like e.g. the Button-class. So the compiler needs full qualified names. But if you wan’t to use the new Dialogs, you have to use the Wrappers from Windows Forms, but don’t add a using-directive for System.Windows.Forms, use full qualified names instead.

There are also other possibilities to get the new vista dialogs. E.g. you could make a Win32-call into comdlg32.dll, but the already available wrappers from Windows Forms are the easiest and fastest way to do it. And you won’t program something, if it’s already there, right? But you have to know that it is there. 8-)

I think Microsoft will update the classes in Microsoft.Win32 in the near future, maybe in the upcoming servicing release for .NET 3.5 planned for Summer 2008? It’s really a little bit strange, WPF is the technology to create first class Vista apps, and its wrappers show still old dialogs, while Windows Forms wrappers don’t…

Take Snapshots PART II – Save as animated GIF

Wednesday, April 9th, 2008

I was asked, if it would be possible to save the snapshots created in my last post as an animated gif. With a DispatcherTimer and the GifBitmapEncoder-class you’re not far away from it. Just create a MediaElement in your Window:

<MediaElement Source="thomasOnBoard.wmv"
  x:Name="media" MediaOpened="media_MediaOpened"
  MediaEnded="media_MediaEnded" Width="300"
  Height="200" Stretch="Fill"/>

In the Codebehind-File, implement Eventhandlers for MediaOpened and MediaEnded-Events. In MediaOpened you start the DispatcherTimer. I’ve just used an interval of 100 milliseconds. In the Tick-Eventhandler, which is called each 100 milliseconds, a BitmapFrame is added to the GifBitmapEncoders Frames-Property. When the video ends, the MediaEnded-Eventhandler writes the GIF to your disk and opens the file. That’s it. :-)

public partial class Window1 : Window
{  ...
  GifBitmapEncoder _encoder;
  DispatcherTimer _timer;
  private void media_MediaOpened(object sender, ...)
  {
    _timer = new DispatcherTimer();
    _timer.Interval = TimeSpan.FromMilliseconds(100);
    _timer.Tick += OnTick;
    _timer.Start();
  }
  void OnTick(object sender, EventArgs e)
  {
    Size dpi = new Size(96, 96);
    RenderTargetBitmap bmp =
      new RenderTargetBitmap(300, 200,
        dpi.Width, dpi.Height, PixelFormats.Pbgra32);
    bmp.Render(media);

    if (_encoder == null)
      _encoder = new GifBitmapEncoder();

    _encoder.Frames.Add(BitmapFrame.Create(bmp));
  }

  private void media_MediaEnded(object sender, ...)
  {
    _timer.Tick -= OnTick;
    _timer = null;

    string filename = Guid.NewGuid().ToString() + ".gif";
  FileStream fs = new FileStream(filename, FileMode.Create);
    _encoder.Save(fs);
    fs.Close();
    _encoder = null;

    Process.Start(filename);
  }
}

Here’s the gif saved from my video. Just click on it to see it animated:

withWPFCreated

Take Snapshots of Videos with WPF

Sunday, April 6th, 2008

With WPF’s Imaging-Classes you can take snapshots of any Visual. The snapshot can be saved in any common Image-Format, like e.g. JPG. Let’s take a look at a pretty short example, that shows how easy this can be done. The example takes snapshots of a Video.

The following Window contains a MediaElement and a Button. The MediaElement plays the Video thomasOnBoard.wmv. The Button defines an Eventhandler for the Click-Event. It takes a snapshot of the video, when you click it.

<Window x:Class="SnapShots.Window1"
    xmlns=http://schemas.microsoft.com/winfx/2006/xaml/...
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
 ResizeMode="NoResize">
  <StackPanel>
   <MediaElement x:Name="media" Height="200" Stretch="Fill">
      <MediaElement.Triggers>
       <EventTrigger RoutedEvent="MediaElement.Loaded">
        <BeginStoryboard>
         <Storyboard>
          <MediaTimelineSource="thomasOnBoard.wmv"
           RepeatBehavior="Forever"/>
         </Storyboard>
        </BeginStoryboard>
       </EventTrigger>
      </MediaElement.Triggers>
     </MediaElement>
     <Button Click="Button_Click" Content="Snapshot"/>
  </StackPanel>
</Window>

Let’s look at the Eventhandler of the Button. An instance of the RenderTargetBitmap-class is created with some parameters about image-size, dots per inch (dpi) and Pixelformat. The Render-Method gets the MediaElement as a parameter, so MediaElements visual appearance is stored in the RenderTargetBitmap in memory. With a JpegBitmapEncoder and a FileStream the Image is written as a JPG to disk. That’s it.

void Button_Click(object sender, RoutedEventArgs e)
{
  Size dpi = new Size(96,96);
  RenderTargetBitmap bmp =
    new RenderTargetBitmap(300, 200,
      dpi.Width, dpi.Height, PixelFormats.Pbgra32);
  bmp.Render(media);

  JpegBitmapEncoder encoder = new JpegBitmapEncoder();
  encoder.Frames.Add(BitmapFrame.Create(bmp));

  string filename = Guid.NewGuid().ToString()+".jpg";
  FileStream fs = new FileStream(filename,FileMode.Create);
  encoder.Save(fs);
  fs.Close();

  Process.Start(filename);
}

Instead of taking the picture in the Button_Click eventhandler, you could create a Timer and take an Image every 0.1s. That allows you to extract an image-sequence of your videos. As it works for any Visual, and everything that’s on the screen in a WPF-Application is a visual, there are many things you can do with it. You could create a snapshot of an Image drawn to an inkCanvas, upload it to a webserver to display it on a webpage etc.

Dependency Properties – Value Precendence

Thursday, March 13th, 2008

The value of a Dependency Properties in WPF can be set from many sources: Templates, Styles, Data Binding, Animation, Local, Inherited from Element Tree,… That’s the reason why they are called "Dependency" Properties. Their values depend on many sources.

To get not a total chaos, there’s a precedence list in WPF that rules which value finally will be set. Here’s the list beginning with the source with lowest precedence (1.) up to the Source with highest precedence (10.):

  1. default-value
  2. Inherited Value
  3. Theme Style Setter
  4. Theme Style Trigger
  5. Style Setter
  6. Template Trigger
  7. Style Trigger
  8. Local Value
  9. Animated Value
  10. Coerced Value

WPF or better say its Property Engine calculates the value of a Dependency Property out of these sources. Finally the ValidateValueCallback checks if the value is valid (If a ValidateValueCallback was registered with the Dependency Property). If the value is not valid, the calculated-value wouldn’t be used (of course).

You have always to be aware of this precedence list, even in simple scenarios. Let’s take a short example. The Attached Property TextElement.Foreground has the Inherits-Flag set to true, so the value of this property is inherited through the element tree and you can set it on any element by using the attached property syntax, e.g. on a StackPanel like below:

<StackPanel TextElement.Foreground="Green">
    <TextBox>Should be green</TextBox>
    <TextBlock>Should also be green</TextBlock>
</StackPanel>

What do you think is the result of the codesnippet above? Do both, TextBox and TextBlock, display green text? I wouldn’t ask if they would do so. :-)

No, not both Elements display green text. The text inside the TextBox is still in the standard black or darkGray. The TextBlock displays its text in green.

Mhm… why doesn’t the TextBox inherit the Foreground-Value from the StackPanel? If you set the TextElement.Foreground-Property locally, it works, and the text inside the TextBox gets green:

<TextBox TextElement.Foreground="Green">
  Should be green
</TextBox>

So lets find out why the TextBox doesn’t get the inherited Value and displays its text still in standard color. Let’s take a look at the TextBox’s ControlTemplate defined in the Theme-Style for Vista’s Aero-Theme (the theme my PC is running on). In the Triggers-Section of the ControlTemplate a Trigger is defined that is actived when the IsEnabled-Property of the TextBox is true. You can see the Templates Trigger-Section below. And as you can see there, the Trigger sets the TextElement.Foreground-Property to the Brush stored in the Field SystemColors.GrayTextBrush (by using the GrayTextBrushKey-ResourceKey).

<ControlTemplate.Triggers>
  <Trigger Property="UIElement.IsEnabled">
    <Setter Property="Panel.Background" TargetName="Bd">
      <Setter.Value>
        <DynamicResource
     ResourceKey="{x:Static SystemColors.ControlBrushKey}"/>
      </Setter.Value>
    </Setter>
    <Setter Property="TextElement.Foreground">
      <Setter.Value>
        <DynamicResource
    ResourceKey="{x:Static SystemColors.GrayTextBrushKey}"/>
      </Setter.Value>
    </Setter>
    <Trigger.Value>
      <s:Boolean>False</s:Boolean>
    </Trigger.Value>
  </Trigger>
</ControlTemplate.Triggers>

If you look to the precedence-list at the beginning of this post, you see that the Inherited Value is on position 2., and the Template Trigger is on Position 6. So the Template Trigger has higher precedence. In the StackPanel with a TextBox and a TextBlock, the Template Trigger of the TextBox will set the foreground, and not the inherited value. When we set the local value, this local value is used, cause local value is on a higher position than the Template Trigger in the precedence list.

To go one step further, let’s override the Template of the TextBox and don’t set the TextElement.Foreground-Property in the Trigger-Section. As a result of the following code with the new TextBox-Template you’ll see that both, TextBox and TextBlock will display green text. :-)

<Window.Resources>
  <Style TargetType="TextBox">
  <Setter Property="Template">
   <Setter.Value>
    <ControlTemplate TargetType="TextBoxBase" ...>
     <ScrollViewer Name="PART_ContentHost" .../>
    <ControlTemplate.Triggers>
     <Trigger Property="UIElement.IsEnabled">
      <Setter Property="TextElement.Foreground">
       <Setter.Value>
        <DynamicResource
  ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
       </Setter.Value>
      </Setter>
      <Trigger.Value>
       <s:Boolean>False</s:Boolean>
      </Trigger.Value>
     </Trigger>
    </ControlTemplate.Triggers>
   </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>
</Window.Resources>
<StackPanel TextElement.Foreground="Green">
 <TextBox>Should be green</TextBox>
 <TextBlock>Should also be green</TextBlock>
</StackPanel>

Built-in DataGrid for WPF is planned

Saturday, February 23rd, 2008

Yes, they are planning to release it. Really great news. Today there’s no DataGrid for WPF-applications as part of .NET Framework 3.5. There are only third-party controls like the Grid from Xceed or Infragistics.

Have you ever built a business application without a DataGrid? I haven’t. I’m really happy to hear that microsoft will release a DataGrid for WPF as part of .NET. That wouldn’t make thirdparty-components necessary (If you don’t need all functionality e.g. Infragistics provides). I hope the DataGrid for WPF will be more like the DataGridView of WinForms in NET 2.0, and not like DataGrid in .NET < 2.0. :-)

Take a look at the .NET 3.5 roadmap on Scott Guthries blogpost. There’s a little line containing this information about a planned built-in DataGrid by end 2008. Also some other missing controls are planned, like Calendar/DatePicker.

Kick it like Beckham with WPF Animations

Thursday, February 21st, 2008

I’m just finishing the Animation-Chapter of my German-speaking WPF book (WPF-Buch erscheint im Juni 2008). I had a hard time to find a good idea how to show the reader animations in a really "non-boring", but easy way. And I think I’ve found one.

Animations in WPF are really powerful. You can create them completely in XAML. Even if the example of this post doesn’t make sense for a business application, think of the things you can do with animations:

  • Create buttons with professional hover-effekts
  • Improve the user-interface with some nice effects
  • Ease navigation for the user by animating something he should do now

Of course, Animations in business applications must be placed in the right way. It’s not recommended to animate everything you can. If you do so, your application won’t be serious anymore.

The application we are looking at here isn’t a business application. It’s just a small Loose XAML-File that allows you to become a soccer profi. :-) It show’s how animations are completely created in XAML and how they can be controlled.

Animations in XAML are placed inside Triggers. Either in an EventTriggers Action-Property or in another Triggers EnterAction or ExitAction-Property. These Properties are all of type TriggerAction. The BeginStoryboard-class and some other classes derive from TriggerAction. BeginStoryboard contains a Storyboard. The Storyboard itself contains the Animations.

Below a loose XAML. The Animation (bold) changes the Canvas.Top-Property of an image that contains a ball (the teamgeist-ball of worldcup 2006 Germany). The Animation starts, when a button with the Name btnStart is clicked. Between the ball-image the Canvas contains an image of me. And the clou is, it looks like I kick the ball for thousand times like a real profi.

<Grid Height="260" Width="300">
 <Grid.RowDefinitions>
  <RowDefinition/>
  <RowDefinition Height="Auto"/>
 </Grid.RowDefinitions>
 <Grid.Triggers>
  <EventTrigger RoutedEvent="Button.Click"
    SourceName="btnStart">
   <BeginStoryboard Name="beginStoryboard">
    <Storyboard TargetProperty="(Canvas.Top)"
      TargetName="imgBall">
     <DoubleAnimation AutoReverse="True" To="110"
     RepeatBehavior="Forever" Duration="0:0:0.25"
     AccelerationRatio="1"/>
    </Storyboard>
   </BeginStoryboard>
  </EventTrigger>
  <EventTrigger RoutedEvent="Button.Click"
    SourceName="btnStop">
   <StopStoryboard BeginStoryboardName="beginStoryboard"/>
  </EventTrigger>
  <EventTrigger RoutedEvent="Button.Click"
    SourceName="btnPause">
   <PauseStoryboard BeginStoryboardName="beginStoryboard"/>
  </EventTrigger>
  <EventTrigger RoutedEvent="Button.Click"
    SourceName="btnResume">
   <ResumeStoryboard BeginStoryboardName="beginStoryboard"/>
  </EventTrigger>
  <EventTrigger RoutedEvent="Button.Click"
    SourceName="btnSpeed2x">
   <SetStoryboardSpeedRatio SpeedRatio="2"
     BeginStoryboardName="beginStoryboard"/>
  </EventTrigger>
  <EventTrigger RoutedEvent="Button.Click"
    SourceName="btnSpeed1x">
   <SetStoryboardSpeedRatio SpeedRatio="1"
     BeginStoryboardName="beginStoryboard"/>
  </EventTrigger>
 </Grid.Triggers>
 <Canvas Width="250" Height="185">
  <Image Height="185" Source="fussballthomi.png"
    Canvas.Left="40"/>
  <Image x:Name="imgBall" Width="25" Canvas.Top="10"
    Canvas.Left="140" Source="teamgeist.png"/>
 </Canvas>
 <DockPanel Grid.Row="1" LastChildFill="False">
  <Button Margin="5" x:Name="btnStart" Content="Start"/>
  <Button Margin="5" x:Name="btnStop" Content="Stop"/>
  <Button Margin="5" x:Name="btnPause" Content="Pause"/>
  <Button Margin="5" x:Name="btnResume" Content="Weiter"/>
  <Button Margin="5" x:Name="btnSpeed1x" Content="1x"/>
  <Button Margin="5" x:Name="btnSpeed2x" Content="2x"/>
 </DockPanel>
</Grid>

Thomas kicks it like beckham. :-)

kickItXAML

More informations about my book, that contains the sample above and hundreds more (also more real world applications), you’ll find by march on www.thomasclaudiushuber.com

Bind to methods with ObjectDataProvider

Thursday, January 10th, 2008

Two classes inherit from DataSourceProvider. XmlDataProvider and ObjectDataProvider. ObjectDataProvider wraps an object and allows you to bind to the wrapped object in XAML. The ObjectDataProvider has a ConstructorParameters-Property for creating an object by using a constructor with parameters.

The cool thing is that a Data Binding to the wrapped object of the ObjectDataProvider is not all. With ObjectDataProvider you can even bind to a static method or to an instance method of the wrapped object. I’ll show you an example.

Just think about a really simple ComboBox that allows the user to chose some colors. Between the name of the color a rectangle filled with the color should be displayed (In WPF this is quite easy. You haven’t to create eventhandlers like you would do in Windows Forms. There you consumed the DrawItem-event of the ComboBox and used the Graphics-object to do a little bit of GDI+. In WPF GDI+ is gone). WPF’s Color class doesn’t have a name property. So just create a static class ColorHelper with one static method GetColorNames that returns an IEnumerable<string> and uses reflection to iterate over all public static properties of the Colors class that all contain Color-objects.

public static class ColorHelper
{
  public static IEnumerable<string> GetColorNames()
  {
    foreach (PropertyInfo p
      in typeof(Colors).GetProperties(
      BindingFlags.Public | BindingFlags.Static))
    {
      yield return p.Name;
    }
  }
}

The Window in the following XAML contains an ObjectDataProvider that uses the Static GetColorNames-Method of the ColorHelper class. The ItemsSource-Property (Typ: IEnumerable) of the ComboBox is bound to the ObjectDataProvider. The ItemTemplate-Property contains a DataTemplate that specifies the Visual Tree (the "look") of an item. Thanks to TypeConverters, a SolidColorBrush-Object is created for the Fill-Property of each Rectangle specified in the DataTemplate.

<Window ...
    xmlns:local="clr-namespace:SimpleObjectDataProvider">
 <Window.Resources>
  <ObjectDataProvider x:Key="colors"
   ObjectType="{x:Type local:ColorHelper}"
   MethodName="GetColorNames"/>
 </Window.Resources>
 <StackPanel>
  <ComboBox
   ItemsSource="{Binding Source={StaticResource colors}}">
   <ComboBox.ItemTemplate>
    <DataTemplate>
     <StackPanel Margin="1" Orientation="Horizontal">
      <Rectangle Fill="{Binding}" Height="10" Width="10"
        Margin="2"/>
      <TextBlock Text="{Binding}" Margin="2 0 0 0"/>
     </StackPanel>
    </DataTemplate>
   </ComboBox.ItemTemplate>
  </ComboBox>
 </StackPanel>
</Window>

The displayed, open ComboBox looks like this:

comboBoxObjectDataProvider