简介:
这是利用WPF作为前端技术,实现桌面版微信多客服系统。项目采用Prism作为前端框架,采用MVVM模式极好的对UI和逻辑代码分离,使用MefBootstrapper集成的MEF IOC容器,解耦各模块对象。合理利用 IEventAggregator 实现事件和交互。文章在介绍对应功能时候会给出相关实现的参考,读者可以参考改进,引入到自己的项目中。
程序运行界面及功能预览:

一、登陆:
功能:支持记住用户和用户设置,可选择记住用户密码。

实现相关:
自定义登陆窗口,引入Microsoft.Windows.Shell。可参考 WPF Custom Chrome Library 和 MSDN WindowChrome Class 有相关自定义窗口实现。
最小化、最大化、关闭按钮功能实现可参考上面的例子。
登陆按钮,自定义Style,重写Button的Template,参考代码如下:


<Style x:Key="LogginButton" TargetType="{x:Type Button}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid >
<Border x:Name="Bd" Background="{TemplateBinding Background }" BorderBrush="#d3d3d3" BorderThickness="1">
</Border>
<ContentPresenter x:Name="contentPresenter" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" RecognizesAccessKey="True"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Bd" Property="BorderBrush" Value="#08bd14"/>
<Setter TargetName="Bd" Property="Opacity" Value="0.8"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="Bd" Property="Background" Value="#f3f3f3"/>
<Setter TargetName="contentPresenter" Property="Margin" Value="2,2,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>View Code
记住密码,采用 XmlSerializer 把用户信息序列化到本地xml配置文件中,程序启动时加载该xml配置文件。用法 MSDN XmlSerializer
二、聊天窗口,信息发送
功能:文字发送,表情发送,图片发送,屏幕截图,快捷回复

RichTextBox 相关实现:文字,表情,图片所有输入都是在富文本框 里实现,因此针对 TextChanged 事件对输入进行一系列处理。
文字:不用做任何处理。
表情:文本框里输入的是表情的转义符号,然后根据转义符号找到对应表情图片进行替换。InlineUIContainer
Gif 动态图:WPF中不支持Gif,所以要编写自定义用户控件作为用来显示gif表情。参考 周银辉 [WPF疑难]在WPF中显示动态GIF

截图功能:源码在网上找到的,是Winform的一个截图。做了小许修改引进到项目。
参考:C# 实现完整功能的截图控件(4)-完整版 http:///
三、客户列表
控件为 TabControl,重写了TabControl 的Style 和 TabItem的Style


<Style x:Key="CustomerTabStyle" TargetType="{x:Type TabControl}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Padding" Value="4,4,4,4"/>
<Setter Property="Background" Value="#F9F9F9"/>
<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 x:Name="HeaderPanel" Grid.Column="0" Background="#f6f6f6" IsItemsHost="true" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<Border x:Name="ContentPanel" 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" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>

