一、需要的前提文件
从网上下载Emoji的表情包,当然是png的图片,因为WPF不支持彩色的Emoji,所以,做列表的时候,需要用图片。
随着压缩包一起的还有一个Emoji.xml文件,文件的层级结构如下
其实我们需要的知识
xml version="1.0" encoding="utf-8" ?> <array> <dict> <key>naturekey> <array> <e>2600e> <e>2614e> <e>2601e> <e>26c4e> <e>1f319e> <e>26a1e> <e>1f300e> <e>1f30ae> <e>1f431e> <e>1f436e> <e>1f42de> <e>1f439e> <e>1f430e> <e>1f43ae> <e>1f438e> <e>1f42fe> <e>1f428e> <e>1f43be> <e>1f437e> <e>1f42ee> <e>1f417e> <e>1f435e> <e>1f412e> <e>1f434e> <e>1f40ee> <e>1f42be> <e>1f411e> <e>1f418e> <e>1f40de> <e>1f426e> <e>1f424e> <e>1f414e> <e>1f427e> <e>1f41be> <e>1f419e> <e>1f420e> <e>1f41fe> <e>1f433e> <e>1f42ce> <e>1f490e> <e>1f338e> <e>1f337e> <e>1f340e> <e>1f339e> <e>1f33be> <e>1f33ae> <e>1f341e> <e>1f343e> <e>1f342e> <e>1f334e> <e>1f335e> <e>1f33ee> <e>1f41ae> array> dict> <dict> <key>objectskey> <array> <e>1f38de> <e>1f49de> <e>1f38ee> <e>1f392e> <e>1f393e> <e>1f38fe> <e>1f386e> <e>1f387e> <e>1f390e> <e>1f391e> <e>1f383e> <e>1f47be> <e>1f385e> <e>1f384e> <e>1f381e> <e>1f514e> <e>1f389e> <e>1f388e> <e>1f4bfe> <e>1f4c0e> <e>1f4f7e> <e>1f3a5e> <e>1f4bbe> <e>1f4fae> <e>1f4f1e> <e>1f4e0e> <e>260ee> <e>1f4bde> <e>1f4fce> <e>1f50ae> <e>1f4e2e> <e>1f4e3e> <e>1f4fbe> <e>1f4e1e> <e>27bfe> <e>1f50de> <e>1f513e> <e>1f512e> <e>1f511e> <e>2702e> <e>1f528e> <e>1f4a1e> <e>1f4f2e> <e>1f4e9e> <e>1f4ebe> <e>1f4eee> <e>1f6c0e> <e>1f6bde> <e>1f4bae> <e>1f4b0e> <e>1f531e> <e>1f6ace> <e>1f4a3e> <e>1f52be> <e>1f48ae> <e>1f489e> <e>1f3c8e> <e>1f3c0e> <e>26bde> <e>26bee> <e>1f3bee> <e>26f3e> <e>1f3b1e> <e>1f3cae> <e>1f3c4e> <e>1f3bfe> <e>2660e> <e>2665e> <e>2663e> <e>2666e> <e>1f3c6e> <e>1f47ee> <e>1f3afe> <e>1f004e> <e>1f3ace> <e>1f4dde> <e>1f4d6e> <e>1f3a8e> <e>1f3a4e> <e>1f3a7e> <e>1f3bae> <e>1f3b7e> <e>1f3b8e> <e>303de> <e>1f45fe> <e>1f461e> <e>1f460e> <e>1f462e> <e>1f455e> <e>1f454e> <e>1f457e> <e>1f458e> <e>1f459e> <e>1f380e> <e>1f3a9e> <e>1f451e> <e>1f452e> <e>1f302e> <e>1f4bce> <e>1f45ce> <e>1f484e> <e>1f48de> <e>1f48ee> <e>2615e> <e>1f375e> <e>1f37ae> <e>1f37be> <e>1f378e> <e>1f376e> <e>1f374e> <e>1f354e> <e>1f35fe> <e>1f35de> <e>1f35be> <e>1f371e> <e>1f363e> <e>1f359e> <e>1f358e> <e>1f35ae> <e>1f35ce> <e>1f372e> <e>1f35ee> <e>1f373e> <e>1f362e> <e>1f361e> <e>1f366e> <e>1f367e> <e>1f382e> <e>1f370e> <e>1f34ee> <e>1f34ae> <e>1f349e> <e>1f353e> <e>1f346e> <e>1f345e> array> dict> <dict> <key>peoplekey> <array> <e>1f604e> <e>1f60ae> <e>1f603e> <e>263ae> <e>1f609e> <e>1f60de> <e>1f618e> <e>1f61ae> <e>1f633e> <e>1f60ce> <e>1f601e> <e>1f61ce> <e>1f61de> <e>1f612e> <e>1f60fe> <e>1f613e> <e>1f614e> <e>1f61ee> <e>1f616e> <e>1f625e> <e>1f630e> <e>1f628e> <e>1f623e> <e>1f622e> <e>1f62de> <e>1f602e> <e>1f632e> <e>1f631e> <e>1f620e> <e>1f621e> <e>1f62ae> <e>1f637e> <e>1f47fe> <e>1f47de> <e>1f49be> <e>1f499e> <e>1f49ce> <e>1f497e> <e>1f49ae> <e>2764e> <e>1f494e> <e>1f493e> <e>1f498e> <e>2728e> <e>1f31fe> <e>1f4a2e> <e>2755e> <e>2754e> <e>1f4a4e> <e>1f4a8e> <e>1f4a6e> <e>1f3b6e> <e>1f3b5e> <e>1f525e> <e>1f4a9e> <e>1f44de> <e>1f44ee> <e>1f44ce> <e>1f44ae> <e>270ae> <e>270ce> <e>1f44be> <e>270be> <e>1f450e> <e>1f446e> <e>1f447e> <e>1f449e> <e>1f448e> <e>1f64ce> <e>1f64fe> <e>261de> <e>1f44fe> <e>1f4aae> <e>1f6b6e> <e>1f3c3e> <e>1f46be> <e>1f483e> <e>1f46fe> <e>1f646e> <e>1f645e> <e>1f481e> <e>1f647e> <e>1f48fe> <e>1f491e> <e>1f486e> <e>1f487e> <e>1f485e> <e>1f466e> <e>1f467e> <e>1f469e> <e>1f468e> <e>1f476e> <e>1f475e> <e>1f474e> <e>1f471e> <e>1f472e> <e>1f473e> <e>1f477e> <e>1f46ee> <e>1f47ce> <e>1f478e> <e>1f482e> <e>1f480e> <e>1f463e> <e>1f48be> <e>1f444e> <e>1f442e> <e>1f440e> <e>1f443e> array> dict> <dict> <key>placeskey> <array> <e>1f3e0e> <e>1f3ebe> <e>1f3e2e> <e>1f3e3e> <e>1f3e5e> <e>1f3e6e> <e>1f3eae> <e>1f3e9e> <e>1f3e8e> <e>1f492e> <e>26eae> <e>1f3ece> <e>1f307e> <e>1f306e> <e>1f3e7e> <e>1f3efe> <e>1f3f0e> <e>26fae> <e>1f3ede> <e>1f5fce> <e>1f5fbe> <e>1f304e> <e>1f305e> <e>1f303e> <e>1f5fde> <e>1f308e> <e>1f3a1e> <e>26f2e> <e>1f3a2e> <e>1f6a2e> <e>1f6a4e> <e>26f5e> <e>2708e> <e>1f680e> <e>1f6b2e> <e>1f699e> <e>1f697e> <e>1f695e> <e>1f68ce> <e>1f693e> <e>1f692e> <e>1f691e> <e>1f69ae> <e>1f683e> <e>1f689e> <e>1f684e> <e>1f685e> <e>1f3abe> <e>26fde> <e>1f6a5e> <e>26a0e> <e>1f6a7e> <e>1f530e> <e>1f3b0e> <e>1f68fe> <e>1f488e> <e>2668e> <e>1f3c1e> <e>1f38ce> <e>1f1ef_1f1f5e> <e>1f1f0_1f1f7e> <e>1f1e8_1f1f3e> <e>1f1fa_1f1f8e> <e>1f1eb_1f1f7e> <e>1f1ea_1f1f8e> <e>1f1ee_1f1f9e> <e>1f1f7_1f1fae> <e>1f1ec_1f1e7e> <e>1f1e9_1f1eae> array> dict> <dict> <key>symbolskey> <array> <e>0031_20e3e> <e>0032_20e3e> <e>0033_20e3e> <e>0034_20e3e> <e>0035_20e3e> <e>0036_20e3e> <e>0037_20e3e> <e>0038_20e3e> <e>0039_20e3e> <e>0030_20e3e> <e>0023_20e3e> <e>2b06e> <e>2b07e> <e>2b05e> <e>27a1e> <e>2197e> <e>2196e> <e>2198e> <e>2199e> <e>25c0e> <e>25b6e> <e>23eae> <e>23e9e> <e>1f197e> <e>1f195e> <e>1f51de> <e>1f199e> <e>1f192e> <e>1f3a6e> <e>1f201e> <e>1f4f6e> <e>1f235e> <e>1f233e> <e>1f250e> <e>1f239e> <e>1f22fe> <e>1f23ae> <e>1f236e> <e>1f21ae> <e>1f237e> <e>1f238e> <e>1f202e> <e>1f6bbe> <e>1f6b9e> <e>1f6bae> <e>1f6bce> <e>1f6ade> <e>1f17fe> <e>267fe> <e>1f687e> <e>1f6bee> <e>3299e> <e>3297e> <e>1f51ee> <e>1f194e> <e>2733e> <e>2734e> <e>1f49fe> <e>1f19ae> <e>1f4f3e> <e>1f4f4e> <e>1f4b9e> <e>1f4b1e> <e>2648e> <e>2649e> <e>264ae> <e>264be> <e>264ce> <e>264de> <e>264ee> <e>264fe> <e>2650e> <e>2651e> <e>2652e> <e>2653e> <e>26cee> <e>1f52fe> <e>1f170e> <e>1f171e> <e>1f18ee> <e>1f17ee> <e>1f532e> <e>1f534e> <e>1f533e> <e>1f55be> <e>1f550e> <e>1f551e> <e>1f552e> <e>1f553e> <e>1f554e> <e>1f555e> <e>1f556e> <e>1f557e> <e>1f558e> <e>1f559e> <e>1f55ae> <e>2b55e> <e>274ce> <e>00a9e> <e>00aee> <e>2122e> array> dict> array>
二、解析文件
xml文件其实就是对压缩包里的png图片的一个分组,既然知道是做这个用的,则可以进行读取xml,并获取列表内容。
获取内容之前,要先根据建立一个实体,实体的内容写了三个字段key,keyimg(内容的第一个Emoji),EmojiCode
public class emojiEntity { private string _key;//分组 private string _keyImg;//分组图像 private Dictionary<string, string> _emojiCode = new Dictionary<string, string>();//emoji编码 ////// 分组 /// public string Key { get { return _key; } set { _key = value; } } /// /// emoji编码 /// public Dictionary<string, string> EmojiCode { get { return _emojiCode; } set { _emojiCode = value; } } /// /// 分组图像 /// public string KeyImg { get { return _keyImg = EmojiCode.Values.First(); } } }
读取xml文件,并写入到List集合中
private ListemojiList = new List (); /// /// emoji集合 /// public List EmojiList { get { return emojiList; } set { emojiList = value; } } /// /// 解析xml /// public void AnayXML() { XmlDocument xmlDoc = new XmlDocument(); xmlDoc.Load(Path.Combine(Environment.CurrentDirectory,@"Emoji.xml")); XmlNode root = xmlDoc.SelectSingleNode("array"); XmlNodeList nodeList = root.ChildNodes; foreach (XmlNode xn in nodeList) { XmlElement xe = (XmlElement)xn; XmlNodeList subList = xe.ChildNodes; emojiEntity entity = new emojiEntity(); foreach (XmlNode xmlNode in subList) { if (xmlNode.Name== "key") { entity.Key = xmlNode.InnerText; } if (xmlNode.Name== "array") { XmlElement lastXe = (XmlElement)xmlNode; foreach (XmlNode lastNode in lastXe) { if (lastNode.Name=="e") { entity.EmojiCode.Add(lastNode.InnerText,GetEmojiPath(lastNode.InnerText)); } } } } EmojiList.Add(entity); } } /// /// 返回Emoji路径 /// /// /// private string GetEmojiPath(string name) { return "../image/"+"emoji_" + name + ".png"; }
三、写ListBox和TabControl样式
<SolidColorBrush x:Key="TabControlNormalBorderBrush" Color="#8C8E94"/> <SolidColorBrush x:Key="TabItemHotBorderBrush" Color="#3C7FB1"/> <SolidColorBrush x:Key="TabItemSelectedBackground" Color="#F9F9F9"/> <SolidColorBrush x:Key="TabItemDisabledBackground" Color="#F4F4F4"/> <SolidColorBrush x:Key="TabItemDisabledBorderBrush" Color="#FFC9C7BA"/> <Style x:Key="TabItemFocusVisual"> <Setter Property="Control.Template"> <Setter.Value> <ControlTemplate> <Rectangle Margin="3,3,3,1" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/> ControlTemplate> Setter.Value> Setter> Style> <Style x:Key="TabItemStyle1" TargetType="{x:Type TabItem}"> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Disabled"/> <Setter Property="Background" Value="White"/> <Setter Property="FocusVisualStyle" Value="{StaticResource TabItemFocusVisual}"/> <Setter Property="Foreground" Value="Black"/> <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Stretch"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabItem}"> <Grid SnapsToDevicePixels="true"> <Grid.ColumnDefinitions> <ColumnDefinition Width="42*"/> <ColumnDefinition Width="55*"/> Grid.ColumnDefinitions> <Border Background="WhiteSmoke" x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" Padding="{TemplateBinding Padding}" Grid.ColumnSpan="2"> <Grid> <ContentPresenter x:Name="Content" ContentSource="Header" HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/> Grid> Border> Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="true"> <Setter Property="Panel.ZIndex" Value="1"/> <Setter Property="Background" TargetName="Bd" Value="White"/> Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="false"/> <Condition Property="IsMouseOver" Value="true"/> MultiTrigger.Conditions> <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource TabItemHotBorderBrush}"/> MultiTrigger> <Trigger Property="TabStripPlacement" Value="Bottom"> <Setter Property="BorderThickness" TargetName="Bd" Value="0"/> Trigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="true"/> <Condition Property="TabStripPlacement" Value="Top"/> MultiTrigger.Conditions> <Setter Property="Margin" Value="-2,-2,-2,-1"/> <Setter Property="Margin" TargetName="Content" Value="0,0,0,1"/> MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="true"/> <Condition Property="TabStripPlacement" Value="Bottom"/> MultiTrigger.Conditions> <Setter Property="Margin" Value="-2,-1,-2,-2"/> <Setter Property="Margin" TargetName="Content" Value="0,1,0,0"/> MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="true"/> <Condition Property="TabStripPlacement" Value="Left"/> MultiTrigger.Conditions> <Setter Property="Margin" Value="-2,-2,-1,-2"/> <Setter Property="Margin" TargetName="Content" Value="0,0,1,0"/> MultiTrigger> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="IsSelected" Value="true"/> <Condition Property="TabStripPlacement" Value="Right"/> MultiTrigger.Conditions> <Setter Property="Margin" Value="-1,-2,-2,-2"/> <Setter Property="Margin" TargetName="Content" Value="1,0,0,0"/> MultiTrigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Background" TargetName="Bd" Value="{StaticResource TabItemDisabledBackground}"/> <Setter Property="BorderBrush" TargetName="Bd" Value="{StaticResource TabItemDisabledBorderBrush}"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> Trigger> ControlTemplate.Triggers> ControlTemplate> Setter.Value> Setter> Style> <Style x:Key="TabControlStyle1" TargetType="{x:Type TabControl}"> <Setter Property="TabStripPlacement" Value="Bottom"/> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="BorderBrush" Value="{StaticResource TabControlNormalBorderBrush}"/> <Setter Property="Background" Value="White"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TabControl}"> <Grid ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local"> <Grid.ColumnDefinitions> <ColumnDefinition x:Name="ColumnDefinition0"/> <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/> Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition x:Name="RowDefinition0" Height="Auto"/> <RowDefinition x:Name="RowDefinition1" Height="*"/> Grid.RowDefinitions> <TabPanel Background="WhiteSmoke" x:Name="HeaderPanel" Grid.Column="0" IsItemsHost="true" Margin="2,2,2,0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/> <Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local"> <ContentPresenter x:Name="PART_SelectedContentHost" ContentSource="SelectedContent" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> Border> Grid> <ControlTemplate.Triggers> <Trigger Property="TabStripPlacement" Value="Bottom"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="2,0,2,2"/> Trigger> <Trigger Property="TabStripPlacement" Value="Left"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/> <Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/> <Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="0"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="2,2,0,2"/> Trigger> <Trigger Property="TabStripPlacement" Value="Right"> <Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/> <Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/> <Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/> <Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/> <Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/> <Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/> <Setter Property="Height" TargetName="RowDefinition0" Value="*"/> <Setter Property="Height" TargetName="RowDefinition1" Value="0"/> <Setter Property="Margin" TargetName="HeaderPanel" Value="0,2,2,2"/> Trigger> <Trigger Property="IsEnabled" Value="false"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> Trigger> ControlTemplate.Triggers> ControlTemplate> Setter.Value> Setter> Style> <Style x:Key="WrapListBox" TargetType="ListBox"> <Setter Property="Background" Value="Transparent"/> <Setter Property="BorderThickness" Value="0"/> <Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/> <Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Hidden"/> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <WrapPanel/> ItemsPanelTemplate> Setter.Value> Setter> <Setter Property="ItemTemplate"> <Setter.Value> <DataTemplate> <Grid> <Image Source="{Binding Path=Value}" Width="24" Height="24" Stretch="Uniform"/> Grid> DataTemplate> Setter.Value> Setter> Style>
四、绑定数据
<TabControl SelectedIndex="0" ItemsSource="{Binding EmojiList,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}" Style="{StaticResource TabControlStyle1}" ItemContainerStyle="{StaticResource TabItemStyle1}"> <TabControl.ItemTemplate> <DataTemplate> <Image Source="{Binding KeyImg}" Width="30" Height="30"/> DataTemplate> TabControl.ItemTemplate> <TabControl.ContentTemplate> <DataTemplate DataType="TabItem"> <ListBox ItemsSource="{Binding EmojiCode}" Style="{StaticResource WrapListBox}"/> DataTemplate> TabControl.ContentTemplate> TabControl>
五、效果图