Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Tagged as

Implementing a Windows Phone 7 Conversation View

, 19 Jul 2011 CPOL
Rate this:
Please Sign up or sign in to vote.
This blog post looks at how to to create a conversation view, mimicking the SMS messaging interface within Windows Phone 7. This post shows how we can select different DataTemplate for each item in an ItemsControl to achieve this effect.

This blog post looks at how to create a conversation view, mimicking the SMS messaging interface within Windows Phone 7. This post shows how we can select different DataTemplate for each item in an ItemsControl to achieve this effect.

The Windows Phone 7 SMS messaging interface graphically illustrates between yourself and the other party by showing your messages as speech bubbles. Creating this view in your own application is not a straightforward process, with the template for each message being dependant on which side of the conversation it belongs to. In this blog post, I will show how to create a simple template selector to achieve the view shown below:

Firstly, we’ll start with the model that represents our conversation:

public enum MessageSide
{
  Me,
  You
}
 
/// <span class="code-SummaryComment"><summary>
</span>/// An SMS message
/// <span class="code-SummaryComment"></summary>
</span>public class Message
{ 
  public string Text { get; set; }
 
  public DateTime Timestamp { get; set; }
 
  public MessageSide Side { get; set; }
}
 
/// <span class="code-SummaryComment"><summary>
</span>/// A collection of messages
/// <span class="code-SummaryComment"></summary>
</span>public class MessageCollection : ObservableCollection<Message>
{
}

It’s pretty simple, a collection of Message objects, each one with a Text and Timestamp property and a Side which indicates which side of the conversation it is on.

To aid in the design of this view, I created some design-time data:

<MessageCollection xmlns="clr-namespace:WP7ConversationView">
  <Message Text="Hi, How are you?" Side="You"/>
  <Message Text="Pretty good thanks. How are things at your end?" Side="Me"/>
  <Message Text="The weather here is a bit grim" Side="Me"/>
  <Message Text="Aye, not bad here, a bit of sun" Side="You"/>
  <Message Text="Do you want to hear a joke?" Side="You"/>
  <Message Text="Go on then" Side="Me"/>
  <Message Text="Knock knock" Side="You"/>
  <Message Text="Who's there?" Side="Me"/>
  <Message Text="Doctor!" Side="You"/>
  <Message Text="Doctor who?" Side="Me"/>
  <Message Text="Doctor Who ... ha ha ROFLMAO" Side="You"/>
  <Message Text="genius. Pure genius" Side="Me"/>
</MessageCollection>

Formatting a Message instance so that it looks like a speech bubble is pretty straightforward. We create a grid with three rows, the first has the message text, the next has the date and the final one contains a path which renders a small triangle:

<contribConverters:StringFormatConverter x:Key="StringFormatConverter"/>
 
<Grid Margin="30, 10, 5, 0"
      contribControls:GridUtils.RowDefinitions=",,"
      Width="420">
  <Rectangle Fill="{StaticResource PhoneAccentBrush}"
             Grid.RowSpan="2"/>
  <TextBlock Text="{Binding Path=Text}"
             Style="{StaticResource TextBlockStyle}"/>
  <TextBlock Text="{Binding Path=Timestamp, 
		Converter={StaticResource StringFormatConverter},
                                            ConverterParameter='ddd, HH:mm'}"
             Style="{StaticResource TimestampStyle}"
             Grid.Row="1"/>
  <Path Data="m 0,0 l 16,0 l 0,16 l -16,-16"
        Fill="{StaticResource PhoneAccentBrush}"
        Margin="0,0,5,0"
        HorizontalAlignment="Right"
        Grid.Row="2"/>
</Grid>

The above code uses a couple of useful little classes from the WP7Contrib project. The first is GridUtils, which gives a simplified grid syntax. In the above example, three rows were constructed using the simple string ",,". The second is a StringFormatConverter, which formats bound values using the supplied string.

Now, the problem is, the above markup renders a speech bubble for messages that have been sent, for received messages we want the bubble to have different margins (aligning it to the left) and have the triangle at the top. This could be achieved using a horrible mess of value converters, however, it would be better if we could just use different markup for each.

WPF and Silverlight v5 have the concept of implicit DataTemplates, where a template is selected based on the type of the item being rendered, however, this feature is not present in WP7. Also, in this case we need to select a template based on the Message.Side property.

The Silverlight ContentControl renders the object assign to its Content property using the DataTemplate specified by the ContentTemplate property. It is actually very easy to extend this control to additional DataTemplate properties which are applied based on the bound data:

public class MessageContentPresenter : ContentControl
{
  /// <span class="code-SummaryComment"><summary>
</span>  /// The DataTemplate to use when Message.Side == Side.Me
  /// <span class="code-SummaryComment"></summary>
</span>  public DataTemplate MeTemplate { get; set; }
 
  /// <span class="code-SummaryComment"><summary>
</span>  /// The DataTemplate to use when Message.Side == Side.You
  /// <span class="code-SummaryComment"></summary>
</span>  public DataTemplate YouTemplate { get; set; }
 
  protected override void OnContentChanged(object oldContent, object newContent)
  {
    base.OnContentChanged(oldContent, newContent);
 
    // apply the required template
    Message message = newContent as Message;
    if (message.Side == MessageSide.Me)
    {
      ContentTemplate = MeTemplate;
    }
    else
    {
      ContentTemplate = YouTemplate;
    }
  }
}

Using the above template-selector, we can supply different templates for the messages from either side of the conversation as follows:

<ItemsControl ItemsSource="{Binding}">
  <ItemsControl.ItemTemplate>
    <DataTemplate>
      <local:MessageContentPresenter Content="{Binding}">
        <local:MessageContentPresenter.MeTemplate>
          <!--<span class="code-comment"> template for sent messages --></span>
          <DataTemplate>
            <Grid Margin="30, 10, 5, 0"
                  contribControls:GridUtils.RowDefinitions=",,"
                  Width="420">
              <Rectangle Fill="{StaticResource PhoneAccentBrush}"
                          Grid.RowSpan="2"/>
              <TextBlock Text="{Binding Path=Text}"
                          Style="{StaticResource TextBlockStyle}"/>
              <TextBlock Text="{Binding Path=Timestamp, 
			Converter={StaticResource StringFormatConverter},
                           ConverterParameter='ddd, HH:mm'}"
                          Style="{StaticResource TimestampStyle}"
                          Grid.Row="1"/>
              <Path Data="m 0,0 l 16,0 l 0,16 l -16,-16"
                    Fill="{StaticResource PhoneAccentBrush}"
                    Margin="0,0,5,0"
                    HorizontalAlignment="Right"
                    Grid.Row="2"/>
            </Grid>                
          </DataTemplate>
        </local:MessageContentPresenter.MeTemplate>
        <local:MessageContentPresenter.YouTemplate>
          <!--<span class="code-comment"> template for received messages --></span>
          <DataTemplate>
            <Grid Margin="5, 10, 30, 0"
                  contribControls:GridUtils.RowDefinitions=",,"
                  Width="420">
              <Path Data="m 0,0 l 0,16 l 16,0 l -16,-16"
                    Fill="{StaticResource PhoneAccentBrush}"
                    Margin="5,0,0,0"
                    HorizontalAlignment="Left"/>
              <Rectangle Fill="{StaticResource PhoneAccentBrush}"
                          Grid.Row="1" Grid.RowSpan="2"/>
              <TextBlock Text="{Binding Path=Text}"
                          Style="{StaticResource TextBlockStyle}"
                          Grid.Row="1"/>
              <TextBlock Text="{Binding Path=Timestamp, 
			Converter={StaticResource StringFormatConverter},
                                                        ConverterParameter='ddd, HH:mm'}"
                          Style="{StaticResource TimestampStyle}"
                          Grid.Row="2"/>
            </Grid>
          </DataTemplate>
        </local:MessageContentPresenter.YouTemplate>
      </local:MessageContentPresenter>
    </DataTemplate>
  </ItemsControl.ItemTemplate>
</ItemsControl>

In the above XAML, the two templates are subtly different, rendering a triangle at a different grid location with a different orientation. The type of differences that would be hard to achieve via value converters.

I was able to test all of the above using design time data in Visual Studio, not having to execute the code once within the emulator!

You can download the full source code for the project from here.

Regards, Colin E.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Colin Eberhardt
Architect Scott Logic
United Kingdom United Kingdom
I am CTO at ShinobiControls, a team of iOS developers who are carefully crafting iOS charts, grids and controls for making your applications awesome.
 
I am a Technical Architect for Visiblox which have developed the world's fastest WPF / Silverlight and WP7 charts.
 
I am also a Technical Evangelist at Scott Logic, a provider of bespoke financial software and consultancy for the retail and investment banking, stockbroking, asset management and hedge fund communities.
 
Visit my blog - Colin Eberhardt's Adventures in .NET.
 
Follow me on Twitter - @ColinEberhardt
 
-
Follow on   Twitter   Google+

Comments and Discussions

 
QuestionSupport for Orientation Pinmembersusmithamaddula20-Feb-13 3:18 
QuestionMissing file: GridUtils.cs PinmemberMr.Jinky11-Aug-11 4:17 
AnswerRe: Missing file: GridUtils.cs PinmvpColin Eberhardt1-Nov-12 0:10 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.1411023.1 | Last Updated 19 Jul 2011
Article Copyright 2011 by Colin Eberhardt
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid