Nieuws
Foto's
Artikelen
Componenten
Applicaties
Kleinkunst

.NET - Outlook contact foto's tonen in WPF applicatie

In this small article I will show you how to create a WPF application which displays the Outlook contact items with their picture. By using LINQ to Objects and my OutlookProvider class (see my article Querying Outlook and OneNote with LINQ) it is quite easy to display the contact properties (name, date of birth, email address, job title, ...) in a listbox.

Displaying the contact picture was a bit tricky and I had to extend my OutlookProvider class and create a custom ValueConverter class. By using styles, data templates and a value converter the final result looks like :

WPF - Office ContactItems

 

Displaying contact names

1) Create a new WPF application and open the XAML file.

2) Add a XML namespace prefix called outlook which refers to the Microsoft.Office.Interop.Outlook namespace and assembly which is stored in the GAC.

3) Add a ListBox and name it "listboxContacts".

4) Create a new style with TargetType ListBox.

5) Add some controls to the DataTemplate part. Properties of the ContactItem class can be used in the Bindings.

<Window x:Class="WpfOffice.WindowOutlookContactItems"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF - Outlook ContactItems" Height="405" Width="656"
 
    xmlns:local="clr-namespace:WpfOffice"
    xmlns:outlook="clr-namespace:Microsoft.Office.Interop.Outlook;assembly=Microsoft.Office.Interop.Outlook">
 
    <Window.Resources>
        <Style TargetType="{x:Type ListBox}">
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <TextBlock Margin="2" Text="{Binding Path=FirstName}" />
                            <TextBlock Margin="2" Text="{Binding Path=LastName}" />
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
 
    <Grid>
        <ListBox Name="listBoxContacts">
        </ListBox>
    </Grid>
</Window>

6) Create an instance of the OutlookProvider class in the partial Window class.

7) Define a LINQ to Objects query on the ContactItems collection.

8) Assign this query to the ItemsSource property of the ListBox "listBoxContacts".

public partial class WindowOutlookContactItems : Window
{
  public WindowOutlookContactItems()
  {
    InitializeComponent();
 
    OutlookProvider outlookProvider = new OutlookProvider();
 
    listBoxContacts.ItemsSource = from contact in outlookProvider.ContactItems
                                  where contact.JobTitle == "Testdata"
                                  select contact;
  }

}
The result is a listbox with the first and last name of the contact items :

WPF - Office ContactItems

 

Finding the Outlook contact picture

I thought that accessing the picture of a contact item would be very easy. So I was looking for a Picture or Photo property in the ContactItem class. It seems that such a property does not exist and I only found a HasPicture property.

If HasPicture is True, then one of the Attachments of the ContactItem is used to store the picture. The Attachment can be recognized because the DisplayName is "ContactPicture.jpg". There is no way to access the actual bitmap data in the Attachment and therefore you need to call the SaveAsFile() method to save the JPEG image to disk.

Outlook ContactItem & Attachment

That is why I started extending my OutlookProvider class and finally 2 static methods GetContactPicturePath and CleanupContactPictures have been added.

  • GetContactPicturePath will save the contact item picture as a JPEG file in the Windows temporary folder and this function will return the path to the file.
  • CleanupContactPictures can be used to clean the pictures cache when starting and/or closing your application.
public static string GetContactPicturePath(Microsoft.Office.Interop.Outlook.ContactItem contact)
{
  return GetContactPicturePath(contact, System.IO.Path.GetTempPath());
}
 
public static string GetContactPicturePath(Microsoft.Office.Interop.Outlook.ContactItem contact, string path)
{
  string picturePath = "";
 
  if (contact.HasPicture)
  {
    foreach (Microsoft.Office.Interop.Outlook.Attachment att in contact.Attachments)
    {
      if (att.DisplayName == "ContactPicture.jpg")
      {
        try
        {
          picturePath = System.IO.Path.GetDirectoryName(path) + "\\Contact_" + contact.EntryID + ".jpg";
          if (!System.IO.File.Exists(picturePath))
            att.SaveAsFile(picturePath);
        }
        catch
        {
          picturePath = "";
        }
      }
    }
  }
 
  return picturePath;
}
 
public static void CleanupContactPictures()
{
  CleanupContactPictures(System.IO.Path.GetTempPath());
}
 
public static void CleanupContactPictures(string path)
{
  foreach (string picturePath in System.IO.Directory.GetFiles(path, "Contact_*.jpg"))
  {
    try
    {
      System.IO.File.Delete(picturePath);
    }
    catch 
    {
    }
  }
}

The latest version of this OutlookProvider class, which is a part of my ScipBe.Common.Office assembly, can be downloaded from the components section of my website.

 

Displaying the contacts with their picture

1) Now you have to create a custom converter class implementing the Convert and ConvertBack methods from the IValueConverter interface. We need a one-way conversion so only implement the Convert method.

2) The value parameter contains a ContactItem object.

3) Pass this object to the static GetContactPicturePath method from the OutlookProvider class.

4) If it returns a path to the JPEG file, then you can create a BitmapImage object which loads this bitmap from file and uses it as return value. Make sure to check for design mode otherwise the WPF designer will show load failure errors.

public object Convert(object value, Type targetType, object parameter,
  System.Globalization.CultureInfo culture)
{
  // Return null in design time to avoid WPF Designer load failure
  if ((bool)(DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue)) 
  {
    return null;
  }
  else
  {
    BitmapImage bitmap = null;
 
    Microsoft.Office.Interop.Outlook.ContactItem contact = (Microsoft.Office.Interop.Outlook.ContactItem)value;
    string picturePath = OutlookProvider.GetContactPicturePath(contact);
 
    if ((picturePath != "") && (System.IO.File.Exists(picturePath)))
      bitmap = new BitmapImage(new Uri(picturePath, UriKind.Absolute));
 
    return bitmap;
  }
}

5) Create an instance of OutlookContactPictureConverter class in the Resources collection of the XAML file.

6) Add an Image to the DataTemplate and use the converter in the Binding of the Source property.

<Window x:Class="WpfOffice.WindowOutlookContactItems"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF - Outlook ContactItems with Picture" Height="405" Width="656"
 
    xmlns:local="clr-namespace:WpfOffice"
    xmlns:outlook="clr-namespace:Microsoft.Office.Interop.Outlook;assembly=Microsoft.Office.Interop.Outlook">
 
    <Window.Resources>
        <local:OutlookContactPictureConverter x:Key="OutlookContactPictureConverter"></local:OutlookContactPictureConverter>
 
        <Style TargetType="{x:Type ListBox}">
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding Converter={StaticResource OutlookContactPictureConverter}}"
                              Stretch="Fill" Width="36" Height="47" />
                            <TextBlock Margin="2" Text="{Binding Path=FirstName}" />
                            <TextBlock Margin="2" Text="{Binding Path=LastName}" />
                        </StackPanel>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Window.Resources>
 
    <Grid>
        <ListBox Name="listBoxContacts">
        </ListBox>
    </Grid>
</Window>
7) To make sure the pictures cache is cleared when closing the application, call the static CleanupContactPictures method of the OutlookProvider class in the destructor of the Window.
public partial class WindowOutlookContactItems : Window
{

  ~WindowOutlookContactItems()
  {
    OutlookProvider.CleanupContactPictures();
  }
}

When you run this application all pictures of the contact items will be shown :

WPF - Office ContactItems

 

The final layout

Let's give it a finishing touch. To improve the layout a little bit, perform the following steps :

1) Go to the XAML file and add a Border with a DropShadowBitmapEffect.

2) Use the full size of the bitmap which is 72x95 pixels.

3) Change Orientation of StackPanel to Vertical (or remove it because Vertical is the default value).

4) Add a ItemsPanel property and change the ItemsPanelTemplate so that the listbox will host its items in a WrapPanel. This will give us the benefit of having the items arranged with a different layout but be aware that it will slow down the rendering. By default, ListBoxes use a VirtualizingStackPanel. A virtualized panel does lazy-loading of UI elements. At the moment there is no VirtualizingWrapPanel available so you have to use the normal WrapPanel.

5) Set the ScrollViewer.HorizontalScrollBarVisibility property to Disabled to get the desired effect.

<Window x:Class="WpfOffice.WindowOutlookContactItems"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF - Outlook ContactItems with Picture" Height="405" Width="656"
 
    xmlns:local="clr-namespace:WpfOffice"
    xmlns:outlook="clr-namespace:Microsoft.Office.Interop.Outlook;assembly=Microsoft.Office.Interop.Outlook">
 
    <Window.Resources>
        <local:OutlookContactPictureConverter x:Key="OutlookContactPictureConverter"></local:OutlookContactPictureConverter>
 
        <Style TargetType="{x:Type ListBox}">
            <Setter Property="ItemTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <Border BorderBrush="Black" BorderThickness="1" Margin="10" Background="White">
                            <Border.BitmapEffect>
                               <DropShadowBitmapEffect Color="Black" Direction="315" ShadowDepth="5" Softness="0.25" Opacity="0.5"/>
                            </Border.BitmapEffect>
                            <StackPanel Margin="5">
                                <Image Source="{Binding Converter={StaticResource OutlookContactPictureConverter}}"
                                  Stretch="Fill" Width="72" Height="95" />
                                <TextBlock HorizontalAlignment="Center" Margin="2" Text="{Binding Path=FirstName}" />
                                <TextBlock HorizontalAlignment="Center" Margin="2" Text="{Binding Path=LastName}" />
                            </StackPanel>
                        </Border>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <WrapPanel />
                    </ItemsPanelTemplate>
                </Setter.Value>
            </Setter>
            <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
        </Style>
    </Window.Resources>
 
    <Grid>
        <ListBox Name="listBoxContacts">
        </ListBox>
    </Grid>
</Window>

Nice result, isn't it !

WPF - Office ContactItems

 

Edit the contact

The final step is implementing the double click event. The Outlook ContactItem class has a Display method which can be used to open the Outlook Contact window. So now our application has full integration with Outlook.

<ListBox Name="listBoxContacts" MouseDoubleClick="listBoxContacts_MouseDoubleClick">
</ListBox>
public void listBoxContacts_MouseDoubleClick(object Sender, MouseButtonEventArgs e)
{
  if (listBoxContacts.SelectedItem != null)
    ((Microsoft.Office.Interop.Outlook.ContactItem)listBoxContacts.SelectedItem).Display(true);
}

WPF - Office ContactItems

I hope you like this example which demonstrates the power of WPF and LINQ. If you have any remarks or suggestions, please let me know.