我们平常用的最多的APP可能就是企鹅和微信了。有没有想过聊天窗口如何实现的?本篇我们将简单模拟一个聊天窗口。
聊天窗口大致上就是消息的一个集合列表。集合列表最常见的展现形式无非就是ListView。可能有些童鞋会觉得ListView的样式和聊天窗口相去甚远,虽然我们可以通过自定义ItemTemplate来修改元素的显示效果,但如何将ListView的元素以不同样式展现呢?这就要通过ListView的ItemTempateSelector属性来实现了。基本原理是通过条件判断,返回不同的DataTemplate给ListViewItem使用。
首先我们来定义ViewModel层的消息集合,集合共有两种不同类型的消息,分别是普通文本信息和红包消息。这两种又需要区别是接受的消息(来自对方)和发送消息(自己发出)。
public abstract class MessageBase { public string Name { get; set; } public DateTime Published { get; set; } } public class Message : MessageBase { public string Comment { get; set; } public bool IsSelf { get; set; } } public class Gift : Message { public int Amount { get; set; } }
其次我们要定义展现消息的DataTemplate,同样分为普通文字消息和红包消息。MessageDataTemplate和SelfMessageDataTemplate就是左右对称的对话框气泡,GiftDataTemplate就是红包的样式啦。
<DataTemplate x:Key="MessageDataTemplate"> <Grid HorizontalAlignment="Left" > <Grid.RowDefinitions> <RowDefinition Height="Auto">RowDefinition> <RowDefinition Height="Auto">RowDefinition> Grid.RowDefinitions> <Grid Grid.Row="0" CornerRadius="4" Background="LightGray" Padding="15"> <TextBlock Text="{Binding Comment}">TextBlock> Grid> <StackPanel Grid.Row="1" Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Foreground="LightGray">TextBlock> <TextBlock Text="{Binding Published}" Foreground="LightGray" Margin="10,0,0,0">TextBlock> StackPanel> Grid> DataTemplate> <DataTemplate x:Key="SelfMessageDataTemplate"> <Grid HorizontalAlignment="Right" > <Grid.RowDefinitions> <RowDefinition Height="Auto">RowDefinition> <RowDefinition Height="Auto">RowDefinition> Grid.RowDefinitions> <Grid Grid.Row="0" CornerRadius="4" Background="Green" Padding="15"> <TextBlock Text="{Binding Comment}" Foreground="White">TextBlock> Grid> <StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right"> <TextBlock Text="{Binding Published}" Foreground="LightGray" Margin="0,0,10,0">TextBlock> <TextBlock Text="{Binding Name}" Foreground="LightGray">TextBlock> StackPanel> Grid> DataTemplate> <DataTemplate x:Key="GiftDataTemplate"> <Grid HorizontalAlignment="Left" > <Grid.RowDefinitions> <RowDefinition Height="Auto">RowDefinition> <RowDefinition Height="Auto">RowDefinition> Grid.RowDefinitions> <Grid Grid.Row="0" CornerRadius="4" Background="Orange" Padding="10"> <Grid.RowDefinitions> <RowDefinition Height="Auto">RowDefinition> <RowDefinition Height="Auto">RowDefinition> <RowDefinition Height="Auto">RowDefinition> Grid.RowDefinitions> <Ellipse Grid.Row="0" Width="50" Height="50" Fill="Red" Stroke="Gold" StrokeThickness="4">Ellipse> <TextBlock Grid.Row="0" Text="红包" TextAlignment="Center" VerticalAlignment="Center">TextBlock> <TextBlock Grid.Row="1" Text="{Binding Amount}" TextAlignment="Center">TextBlock> <TextBlock Grid.Row="2" Text="{Binding Comment}" TextAlignment="Center" >TextBlock> Grid> <StackPanel Grid.Row="1" Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Foreground="LightGray">TextBlock> <TextBlock Text="{Binding Published}" Foreground="LightGray" Margin="10,0,0,0">TextBlock> StackPanel> Grid> DataTemplate>
接下来就是如何应用ItemTemplateSelector了,我们需要创建继承自DataTemplateSelector的子类,并且override SelectTemplateCore方法。该方法将我们在App.xaml中定义的DataTemplate资源文件根据集合众不同的元素返回对应的模板。
public class MessageItemDataTemplateSelector : DataTemplateSelector { protected override DataTemplate SelectTemplateCore(object item, DependencyObject container) { if (item is Gift) { return App.Current.Resources["GiftDataTemplate"] as DataTemplate; } else if (item is Message) { if ((item as Message).IsSelf) { return App.Current.Resources["SelfMessageDataTemplate"] as DataTemplate; } else { return App.Current.Resources["MessageDataTemplate"] as DataTemplate; } } return base.SelectTemplateCore(item); } }
使用之前,我们需要在XAML中声明一个MessageItemDataTemplateSelector类型的实例。
<local:MessageItemDataTemplateSelector x:Key="MessageItemDataTemplateSelector">local:MessageItemDataTemplateSelector>
然后Binding到ListView的ItemTemplateSelector属性。
<ListView Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" ItemTemplateSelector="{StaticResource MessageItemDataTemplateSelector}" ItemsSource="{Binding MessageList}"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch">Setter> <Setter Property="Margin" Value="10">Setter> Style> ListView.ItemContainerStyle> ListView>
运行看一下效果,是不是蛮简单的?
Sample的代码放在全球最大同性交友网站上,地址如下:
https://github.com/manupstairs/UWPSamples