Telerik UI for Windows Phone by Progress

This topic demonstrates how to use RadConversationView with a custom message model. This includes defining a custom message as well as modifying RadConversationView so that it correctly visualizes the new messages.

The MessageModel class

The MessageModel class will be a little different than the standard ConversationViewMessage in that it will have one more message type, not just Incoming and Outgoing and will have one more property. The new message type will be System. For example if the user attempts to send a message but there is no network or the target user is unavailable at the moment, the app should display a notification by adding a message that says that the message was not delivered succesfully or that it will be sent later. The new property may be a url that points to a picture of the message sender. So our new message class will look like this:

CopyC#
public enum MessageType
{
    Incoming,
    Outgoing,
    System
}

public class MessageModel
{
    public string Message
    {
        get;
        set;
    }

    public DateTime Time
    {
        get;
        set;
    }

    public MessageType MessageType
    {
        get;
        set;
    }

    public string PictureUrl
    {
        get;
        set;
    }
}

Now with the message ready, we need to modify RadConversationView to use it. There are three things that need to be done. First we need to create incoming and outgoing templates that will best visualize our new message. Second we need a new message template selector that knows about our new message types so that the conversation view can choose the best template given a particular message. Finally, we need to implement the CreateMessage callback. This last step is optional because the developer may choose not use the built-in text box by setting the TextBoxVisibility to false. Here are our new incoming and outgoing message templates:

CopyXAML
<Grid.Resources>
    <local:CustomTemplateSelector x:Key="CustomTemplateSelector">
        <local:CustomTemplateSelector.IncomingTemplate>
            <DataTemplate>
                <Grid Margin="12">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="3*"/>
                    </Grid.ColumnDefinitions>
                    <primitives:RadPointerContentControl Background="{StaticResource PhoneAccentBrush}"
                                                     TargetPoint="160, 300"
                                                     Grid.Column="1">
                        <primitives:RadPointerContentControl.PointerTemplate>
                            <DataTemplate>
                                <Polygon Width="12"
                                     Height="24"
                                     Points="0,0 12,0 12,12 0,24"
                                     StrokeThickness="0"
                                     Fill="{StaticResource PhoneAccentBrush}"
                                     RenderTransformOrigin="0.5, 0.5">
                                    <Polygon.RenderTransform>
                                        <ScaleTransform ScaleX="-1"/>
                                    </Polygon.RenderTransform>
                                </Polygon>
                            </DataTemplate>
                        </primitives:RadPointerContentControl.PointerTemplate>

                        <StackPanel>
                            <TextBlock Text="{Binding Path=Message}"
                                   TextWrapping="Wrap"
                                   Margin="12"/>
                            <TextBlock Text="{Binding Path=Time}"
                                   Margin="12, 0, 12, 12"
                                   HorizontalAlignment="Right"/>
                        </StackPanel>
                    </primitives:RadPointerContentControl>
                </Grid>
            </DataTemplate>
        </local:CustomTemplateSelector.IncomingTemplate>

        <local:CustomTemplateSelector.OutgoingTemplate>
            <DataTemplate>
                <Grid Margin="12">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="3*"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>

                    <primitives:RadPointerContentControl Background="{StaticResource PhoneAccentBrush}"
                                                     TargetPoint="-150,-300">
                        <primitives:RadPointerContentControl.PointerTemplate>
                            <DataTemplate>
                                <Polygon Width="12"
                                     Height="24"
                                     Points="0,0 12,0 12,12 0,24"
                                     StrokeThickness="0"
                                     Fill="{StaticResource PhoneAccentBrush}"
                                     RenderTransformOrigin="0.5, 0.5">
                                    <Polygon.RenderTransform>
                                        <ScaleTransform ScaleX="-1"/>
                                    </Polygon.RenderTransform>
                                </Polygon>
                            </DataTemplate>
                        </primitives:RadPointerContentControl.PointerTemplate>

                        <StackPanel>
                            <TextBlock Text="{Binding Path=Message}"
                                   TextWrapping="Wrap"
                                   Margin="12"/>
                            <TextBlock Text="{Binding Path=Time}"
                                   Margin="12, 0, 12, 12"
                                   HorizontalAlignment="Right"/>
                        </StackPanel>
                    </primitives:RadPointerContentControl>
                </Grid>
            </DataTemplate>
        </local:CustomTemplateSelector.OutgoingTemplate>

        <local:CustomTemplateSelector.SystemTemplate>
            <DataTemplate>
                <Grid Margin="12"
                      Background="Orange">
                    <StackPanel>
                        <TextBlock Text="{Binding Path=Message}"
                                TextWrapping="Wrap"
                                Margin="12"/>
                        <TextBlock Text="{Binding Path=Time}"
                                Margin="12, 0, 12, 12"
                                HorizontalAlignment="Right"/>
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </local:CustomTemplateSelector.SystemTemplate>
    </local:CustomTemplateSelector>
</Grid.Resources>
Now let's implement the new template selector:
CopyC#
public class CustomTemplateSelector : DataTemplateSelector
{
    public DataTemplate IncomingTemplate
    {
        get;
        set;
    }

    public DataTemplate OutgoingTemplate
    {
        get;
        set;
    }

    public DataTemplate SystemTemplate
    {
        get;
        set;
    }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        MessageModel message = (MessageModel)item;

        switch (message.MessageType)
        {
            case MessageType.Incoming:
                return this.IncomingTemplate;
            case MessageType.Outgoing:
                return this.OutgoingTemplate;
            case MessageType.System:
                return this.SystemTemplate;
        }

        return null;
    }
}
If we decide to use the built-in text box, we implement the CreateMessage callback like this:
CopyC#
private object CreateMessage(string messageText)
{
    return new MessageModel() { Message = messageText, Time = DateTime.Now, MessageType = MessageType.Outgoing, PictureUrl = "http://www.mysite.com/mypic.png" };
}
And when we convince RadConversationView to use our modifications like this:
CopyXAML
<telerikDataControls:RadConversationView x:Name="conversationView"
                                         MessageTemplateSelector="{StaticResource CustomTemplateSelector}"/>
CopyC#
ObservableCollection<MessageModel> messages = new ObservableCollection<MessageModel>();
messages.Add(new MessageModel() { Message = "Hi, are you there.", Time = DateTime.Now, MessageType = MessageType.Outgoing });
messages.Add(new MessageModel() { Message = "Yes?", Time = DateTime.Now, MessageType = MessageType.Incoming });
messages.Add(new MessageModel() { Message = "Connection lost", Time = DateTime.Now, MessageType = MessageType.System, PictureUrl = "alert.png" });

this.conversationView.ItemsSource = messages;
this.conversationView.CreateMessage = this.CreateMessage;
we get this result:
radconversationview-custommessages