高仿QQ即时聊天软件开发系列之三登录窗口用户选择下拉框

上一篇高仿QQ即时聊天软件开发系列之二登录窗口界面写了一个大概的布局和原理

这一篇详细说下拉框的实现原理

先上最终效果图

一开始其实只是想给下拉框加一个placeholder效果,让下拉框在未选择未输入时显示一个提示字符串。由于Background对ComboBox无效,所以直接通过Background来实现是不行了。需要重新写ComboBox的模板,也就是Template,自定义一个模板来实现这个结果。又看了一下QQ的下拉框,这玩意不自定义也难以实现,所以就干脆自定义了。

先上代码,先是ComboBox,再是ComboBoxToggleButton,最后是ComboBoxItem

 1  <Style TargetType="{x:Type ComboBox}">
 2             <Setter Property="Template">
 3                 <Setter.Value>
 4                     <ControlTemplate TargetType="ComboBox">
 5                         <Grid Margin="0">
 6                             <Border 
 7                                     BorderThickness="1"
 8                                 BorderBrush="{TemplateBinding BorderBrush}"
 9                                     CornerRadius="4,4,0,0" >
10                                 <Grid>
11                                     <Grid.ColumnDefinitions>
12                                         <ColumnDefinition></ColumnDefinition>
13                                         <ColumnDefinition Width="20" x:Name="colArrow"></ColumnDefinition>
14                                     </Grid.ColumnDefinitions>
15                                     <ToggleButton 
16                                 Name="ToggleButton" 
17                                 Grid.Column="1" 
18                                 Focusable="false"
19                                     Style="{StaticResource ComboBoxToggleButton}" 
20                                 IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
21                                 ClickMode="Press">
22                                     </ToggleButton>
23                                     <TextBox x:Name="PART_EditableTextBox"
24                                          BorderThickness="0"
25                                 VerticalAlignment="Center">
26                                         <TextBox.Resources>
27                                             <VisualBrush x:Key="tbPlaceHolder" Stretch="None" AlignmentX="Left">
28                                                 <VisualBrush.Visual>
29                                                     <Label Content="CC号码/用户名/邮箱" Foreground="Gray" Padding="5,0,0,0"></Label>
30                                                 </VisualBrush.Visual>
31                                             </VisualBrush>
32                                         </TextBox.Resources>
33                                         <TextBox.Style>
34                                             <Style TargetType="TextBox">
35                                                 <Style.Triggers>
36                                                     <Trigger Property="Text" Value="{x:Null}">
37                                                         <Setter Property="Background" Value="{DynamicResource tbPlaceHolder}">
38                                                         </Setter>
39                                                     </Trigger>
40                                                     <Trigger Property="Text" Value="">
41                                                         <Setter Property="Background" Value="{DynamicResource tbPlaceHolder}">
42                                                         </Setter>
43                                                     </Trigger>
44                                                 </Style.Triggers>
45                                             </Style>
46                                         </TextBox.Style>
47                                     </TextBox>
48                                 </Grid>
49                             </Border>
50                             <Popup 
51                                 Placement="Bottom"
52                                 IsOpen="{TemplateBinding IsDropDownOpen}"
53                                 AllowsTransparency="True" 
54                                 Focusable="False"
55                                 PopupAnimation="Slide">
56                                 <Grid
57                                   Name="DropDown"
58                                   Width="{TemplateBinding ActualWidth}"
59                                   MaxHeight="{TemplateBinding MaxDropDownHeight}">
60                                     <Border 
61                                         x:Name="DropDownBorder"
62                                         BorderThickness="1"
63                                         BorderBrush="{TemplateBinding BorderBrush}">
64                                         <ScrollViewer>
65                                             <StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
66                                         </ScrollViewer>
67                                     </Border>
68                                 </Grid>
69                             </Popup>
70                         </Grid>
83                     </ControlTemplate>
84                 </Setter.Value>
85             </Setter>
86         </Style>

有没有觉得头晕?反正我是感觉有点晕吧。我也不是凭空重写出来的,是找的别人写好的示例代码改的,别人的示例代码那可叫真看着晕。现在改成这样已经简单很多了

从上到下,一点点来

第4行,给ComboBox重新定义控件模板,只在当前页面生效,然后下面是模板的内容

第6行,Border用于实现圆角

第10行,好戏开始。这个Grid定义了两列,第一列用于存放下拉框选择的文本,第二列用于存放下拉的箭头

第15行,开始定义下拉的箭头。ToggleButton是用来作为点击后弹出下拉框的按钮,但具体是什么东东?其实自己建一个wpf项目拉一个ToggleButton出来看看就明白了。它跟复选框类似,一般情况有两个值,一个是Checked,一个是UnChecked,但跟复选框不同的是,它只是一个按钮,没有对勾,并且你点击它之后,如果它的状态是Checked,那么它就不会弹起来了,再点一下才能弹起来,想想这个是不是跟下拉框的功能有点相似?下面的Style暂时不说,因为那个是属于ComboBoxToggleButton那块的

第20行,IsChecked,关键的地方。这个值绑定到了一个叫IsDropDownOpen的属性,是双向绑定,绑定的对象是使用这个控件的控件。这什么意思呢?谁会使用这个控件呢?那其实就是ComboBox(TemplatedParent这个属性其实我没太理解透,可能一时间也难以理解透),而如果下拉框是打开的,那么也就意味着isChecked会为True,那么ToggleButton就会是选中的状态。反过来,如果下拉框未打开,那么IsChecked就是未选中状态,这个时候点击ToggleButton,那么IsChecked会为True,由于是双向绑定,所以IsDropDownOpen也会为True,下拉框就自然打开了。不得不说WPF真心强大。

第23行,这个TextBox是用于存放选择后的结果的,也是用于实现可编辑下拉框的。然后嘛,placeholder效果就在这儿实现了。

第50行,Popup,用于弹出一个控件,这里的{TemplateBinding IsDropDownOpen}其实跟上面说的TemplatedParent是一个意思,把IsOpen绑定到了应用了该控件的控件的IsDropDownOpen属性

第65行,StackPanel用于存放下拉框中的每一项,IsItemsHost表示这个控件是否用于Item的容器(好吧其实这个地方我短时间理解不了,只能这么去理解)

OK,这个完毕,下一个,ComboBoxToggleButton

 1 <Style x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
 2             <Setter Property="Template">
 3                 <Setter.Value>
 4                     <ControlTemplate TargetType="ToggleButton">
 5                         <Grid>
 6                             <Grid.ColumnDefinitions>
 7                                 <ColumnDefinition />
 8                             </Grid.ColumnDefinitions>
 9                             <Path 
10                                 Panel.ZIndex="1"
11                               x:Name="Arrow"
12                               Grid.Column="1"     
13                               Fill="#B1B1B1"
14                               Stroke="#B1B1B1"
15                               HorizontalAlignment="Center"
16                               VerticalAlignment="Center"
17                               Data="M0,0L3,3 6,0z">
18                                 <Path.RenderTransform>
19                                     <ScaleTransform x:Name="stfArrow" CenterY="2"></ScaleTransform>
20                                 </Path.RenderTransform>
21                             </Path>
22                             <TextBlock Panel.ZIndex="0"></TextBlock>
23                         </Grid>
37                         <!--</Grid>-->
38                         <ControlTemplate.Triggers>
45                             <Trigger Property="IsMouseOver" Value="True">
46                                 <Setter TargetName="Arrow" Property="Fill" Value="Black"></Setter>
47                                 <Setter TargetName="Arrow" Property="Stroke" Value="Black"></Setter>
48                             </Trigger>
49                             <EventTrigger RoutedEvent="Checked">
50                                 <EventTrigger.Actions>
51                                     <BeginStoryboard>
52                                         <Storyboard>
53                                             <DoubleAnimation  
54                                          Duration="0:0:0.2"  
55                                                         Storyboard.TargetName="stfArrow"
56                                          Storyboard.TargetProperty="ScaleY"  From="1" 
57                                          To="-1"  />
58                                         </Storyboard>
59                                     </BeginStoryboard>
60                                 </EventTrigger.Actions>
61                             </EventTrigger>
62                             <EventTrigger RoutedEvent="Unchecked">
63                                 <EventTrigger.Actions>
64                                     <BeginStoryboard>
65                                         <Storyboard>
66                                             <DoubleAnimation  
67                                          Duration="0:0:0.2"  
68                                                         Storyboard.TargetName="stfArrow"
69                                          Storyboard.TargetProperty="ScaleY"  From="-1" 
70                                          To="1"  />
71                                             <DoubleAnimation  
72                                          Duration="0:0:0.2"  
73                                                         Storyboard.TargetName="stfArrow"
74                                          Storyboard.TargetProperty="ScaleY"  From="-1" 
75                                          To="1"  />
76                                         </Storyboard>
77                                     </BeginStoryboard>
78                                 </EventTrigger.Actions>
79                             </EventTrigger>
80                         </ControlTemplate.Triggers>
81                     </ControlTemplate>
82                 </Setter.Value>
83             </Setter>
84         </Style>

很多重复的技术点就跳过

第9行,Path控件用于画出点击下拉框时的那个向下的箭头,其中的Data可能比较难以理解,推荐一篇文章:http://blog.csdn.net/johnsuna/article/details/1885597,我也是在这儿看懂的。

第18行,RenderTransform中的ScaleTransform用于旋转这个Path控件也就是箭头,ScaleTransform有一个属性ScaleY,改为-1时就会180度翻转,可以实现当下拉框被打开时箭头朝上的效果

第22行,呃··怎么不记得有这一行,可能没什么用吧,忽略掉

第45行,注册鼠标经过触发器,经过时把箭头变成黑色

第49行,注册Checked事件触发器,BeginStoryboard开始一段动画,Storyboard创建一个动画,DoubleAnimation创建两个值之间的过渡,TargetName指定给哪个控件应用这个过渡,TargetProperty指定给哪个属性应用,From和To就不用说了。下面的UnChecked跟上面类似。这个主要用于实现点击箭头时的翻转动画。

OK,下一部分

 1 <Style TargetType="{x:Type ComboBoxItem}">
 2             <Setter Property="RenderTransform">
 3                 <Setter.Value>
 4                     <ScaleTransform x:Name="stItem"></ScaleTransform>
 5                 </Setter.Value>
 6             </Setter>
 7             <Setter Property="Template">
 8                 <Setter.Value>
 9                     <ControlTemplate TargetType="ComboBoxItem">
10                         <Grid Background="White" x:Name="spItem" Height="23">
11                             <Grid.ColumnDefinitions>
12                                 <ColumnDefinition x:Name="colImage" Width="20"></ColumnDefinition>
13                                 <ColumnDefinition></ColumnDefinition>
14                                 <ColumnDefinition Width="30"></ColumnDefinition>
15                             </Grid.ColumnDefinitions>
16                             <Image Grid.Column="0" Margin="0,1" Source="{Binding Image}"></Image>
17                             <Label Grid.Column="1" HorizontalAlignment="Stretch" Content="{Binding CC}" Name="lblItem" VerticalContentAlignment="Center" FontSize="11" HorizontalContentAlignment="Left" Margin="0,1">
18                             </Label>
19                             <Image Cursor="Hand" ToolTip="删除该账号" x:Name="delImage" Visibility="Collapsed" Margin="10,0" Grid.Column="2" Width="9" HorizontalAlignment="Right" Source="Resources/images/deleteAccountNormal.png"></Image>
20                         </Grid>
21                         <ControlTemplate.Triggers>
22                             <EventTrigger RoutedEvent="ComboBoxItem.MouseEnter" SourceName="spItem">
23                                 <EventTrigger.Actions>
24                                     <BeginStoryboard>
25                                         <Storyboard>
26                                             <DoubleAnimation Storyboard.TargetName="spItem" Storyboard.TargetProperty="(Height)" From="23" To="40" Duration="0:0:0.20"></DoubleAnimation>
27                                             <DoubleAnimation Storyboard.TargetName="lblItem" Storyboard.TargetProperty="FontSize" From="11" To="14" Duration="0:0:0.20"></DoubleAnimation>
28                                         </Storyboard>
29                                     </BeginStoryboard>
30                                 </EventTrigger.Actions>
31                             </EventTrigger>
32                             <EventTrigger RoutedEvent="ComboBoxItem.MouseLeave" SourceName="spItem">
33                                 <EventTrigger.Actions>
34                                     <BeginStoryboard>
35                                         <Storyboard>
36                                             <DoubleAnimation Storyboard.TargetName="spItem" Storyboard.TargetProperty="(Height)" From="40" To="23" Duration="0:0:0.20"></DoubleAnimation>
37                                             <DoubleAnimation Storyboard.TargetName="lblItem" Storyboard.TargetProperty="FontSize" From="14" To="11" Duration="0:0:0.20"></DoubleAnimation>
38                                         </Storyboard>
39                                     </BeginStoryboard>
40                                 </EventTrigger.Actions>
41                             </EventTrigger>
42                             <Trigger Property="IsMouseOver" Value="true">
44                                 <Setter TargetName="spItem" Property="Background" Value="#378FCF"></Setter>
45                                 <Setter TargetName="lblItem" Property="Foreground" Value="White"></Setter>
46                                 <Setter TargetName="colImage" Property="Width" Value="40"></Setter>
47                                 <Setter TargetName="delImage" Property="Visibility" Value="Visible"></Setter>
48                             </Trigger>
49                         </ControlTemplate.Triggers>
50                     </ControlTemplate>
51                 </Setter.Value>
52             </Setter>
53         </Style>

终于到最后一个地方了,上面的代码定义了下拉框中的每一项的模板

第10行,定义了一个Grid,三列,第一列是图片,也就是用户头像,第二列是用户名,第三列是删除用户的图标

然后其实下面的就是一堆动画,这个跟上一部分的动画原理类似的。

 

这些模板定义好之后,直接拖个ComboBox出来就行了,不需要任何设置

这篇文章肯定会有技术错误,毕竟我对WPF并不是太熟,如果有的话请指正

转载于:https://www.cnblogs.com/wzxinchen/p/4266152.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/263823.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RoRoWoBlog 开源博客系统介绍

萝萝窝个人博客开源项目 以Asp.net MVC 2.0 ADO.Net Entity Framework 4.0 Unity 2.0 MvcPager JQuery 等技术框架&#xff0c;开发的个人博客系统。 支持MetaWeblog接口 通过MetaWeblog接口&#xff0c;可以将您个人博客系统中的博文&#xff0c;直接同步到您其它网站的博…

JAVA 面试知识点

主要包括以下几个部分&#xff1a; Java 基础知识点Java 常见集合高并发编程&#xff08;JUC 包&#xff09;JVM 内存管理Java 8 知识点网络协议相关数据库相关MVC 框架相关大数据相关Linux 命令相关面试&#xff0c;是大家从学校走向社会的第一步。 互联网公司的校园招聘&…

sqlserver 导出mysql,sqlserver数据(表)导出到mysql

这里说明我的工具&#xff1a; Navicat Premium1 首先 navicat 连接到 sqlserver 数据库&#xff0c;也就是我要从这里导出那个 170 万条数据的表&#xff0c;然后选中表右键单击&#xff0c;选择导出向导2 然后选择文本文件&#xff0c;下一步3 核对下我们要导出的表&#xff…

MediatR 知多少 - 简书

MediatR 知多少 - 简书 原文:MediatR 知多少 - 简书引言 首先不用查字典了&#xff0c;词典查无此词。猜测是作者笔误将Mediator写成MediatR了。废话少说&#xff0c;转入正题。 先来简单了解下这个开源项目MediatR&#xff08;作者Jimmy Bogard&#xff0c;也是开源项目AutoMa…

oracle数据库扩展目录,Oracle 扩充磁盘空间

Oracle 扩充磁盘空间环境&#xff1a;OS:Oracle Linux Server release 6.3DB:Oracle 11.2.0.4.0问题&#xff1a;根目录磁盘空间不足&#xff0c;还剩6.5G解决办法&#xff1a;扩容磁盘空间&#xff1b;由于安装操作系统时没有使用LVM&#xff0c;不能直接扩容根目录&#xff0…

使用ANT打包Android应用

大家好&#xff0c;今天来分享一下如何使用ANT打包Android应用。 通常我们习惯用eclipse来开发Android程序&#xff0c;它会自动帮我们打包当前的应用程序。如果在Navigator视图下&#xff0c;我们可以看到以下几个文件&#xff1a; 在上图中&#xff0c;com包放置的是我们的cl…

迷你飞信一出,LibFetion该挂了把

飞信确实是个好东西&#xff01; 发短信不要钱 支持群发&#xff0c;这样发个通知什么的&#xff0c;可以轻松搞定 但是以前的飞信客户端太庞大了 好几十M呢 而且光大还多了很多没有用的功能 比如&#xff1a;什么飞信空间啊&#xff0c;网上营业厅&#xff0c;彩信&#xff0c…

Java设计模式(1)工厂模式(Factory模式)

工厂模式定义&#xff1a;提供创建对象的接口。 为何使用工厂模式 工厂模式是我们最常用的模式了&#xff0c;著名的Jive论坛&#xff0c;就大量使用了工厂模式&#xff0c;工厂模式在Java程序系统可以说是随处可见。为什么工厂模式是如此常用&#xff1f;因为工厂模式就相当于…

cmd使用另一个Oracle的sid,(转发备用)Oracle SID在本机上已经存在,请指定一个不同的SID”的解决办法...

(转发备用)Oracle SID在本机上已经存在,请指定一个不同的SID”的解决办法(2014-04-30 10:57:17)1、 开始&#xff0d;&#xff1e;设置&#xff0d;&#xff1e;控制面板&#xff0d;&#xff1e;管理工具&#xff0d;&#xff1e;服务 停止所有Oracle服务。2、 开始&#xff0…

$Poj1952\ $洛谷$1687\ Buy\ Low,Buy\ Lower$ 线性$DP+$方案计数

Luogu Description 求一个长度为n的序列a的最长下降子序列的长度,以及这个长度的子序列种数,注意相同的几个子序列只能算作一个子序列. n<5000,a[i]不超过long范围 Sol 求最长下降子序列的长度: 1.f[i]表示以a[i]结尾的最长下降子序列长度 2.f[i]表示以i结尾的最长下降子序列…

JavaScript中的各种宽高以及位置总结

在javascript中操作dom节点让其运动的时候&#xff0c;常常会涉及到各种宽高以及位置坐标等概念&#xff0c;如果不能很好地理解这些属性所代表的意义&#xff0c;就不能理解js的运动原理&#xff0c;同时&#xff0c;由于这些属性概念较多&#xff0c;加上浏览器之间 实现方式…

MySQL 8.0索引合并

简介参考https://dev.mysql.com/doc/refman/8.0/en/index-merge-optimization.html#index-merge-intersection。索引合并是通过多个range类型的扫描并且合并它们的结果集来检索行的。仅合并来自单个表的索引扫描&#xff0c;而不是跨多个表的索引扫描。合并会产生底层扫描的三种…

linux开通80端口命令,Linux iptables开启80端口

Linux下安装好apache的时候访问IP 发现无法访问!以为安装失败了&#xff0c;于是测试apache 监听的端口80#netstat -lnt |grep 80tcp 0 0 :::80 :::* LISTEN安装成功了&#xff01;想到用本机telnet IP 80不通- - 但…

服务端配置实现AJAX跨域请求

2019独角兽企业重金招聘Python工程师标准>>> 一直以为AJAX跨域是无法逾越的鸿沟&#xff0c;最近发现原来在服务端可以通过发送header信息来允许AJAX跨域请求。 PHP代码示例&#xff1a; header(Access-Control-Allow-Origin:*); header(Access-Control-Allow-Hea…

【翻译】怎样使用css制作迷人的button

英文原文&#xff1a;How to make sexy buttons with css 作者&#xff1a;Alex 这是一个教程&#xff0c;作者Alex一步步地叫我们怎样使用css来制作一个迷人的按钮&#xff0c;看后觉得挺好&#xff0c;很想大家都看看&#xff0c;翻译的可能稍有不妥&#xff0c;望谅解…… 这…

Linux内核分析(三)----初识linux内存管理子系统

原文:Linux内核分析&#xff08;三&#xff09;----初识linux内存管理子系统Linux内核分析&#xff08;三&#xff09; 昨天我们对内核模块进行了简单的分析&#xff0c;今天为了让我们今后的分析没有太多障碍&#xff0c;我们今天先简单的分析一下linux的内存管理子系统&#…

linux常用高级命令,Linux常用高级文件操作命令

Linux常用高级文件操作命令 cat 查看文本#cat 文件名 打印文件内容到当前屏幕上#cat -n 文件名 显示行号#cat gt;Linux常用高级文件操作命令cat 查看文本#cat 文件名 打印文件内容到当前屏幕上#cat -n 文件名 显示行号#cat > a.txt 可以用这种方法修改或…

java高并发实战Netty+协程(Fiber)|系列1|事件驱动模式和零拷贝

今天开始写一些高并发实战系列。 本系列主要讲两大主流框架&#xff1a; Netty和Quasar(java纤程库) 先介绍netty吧&#xff0c;netty是业界比较成熟的高性能异步NIO框架。 简单来说&#xff0c;它就是对NIO2的封装&#xff0c;但提供了更好用&#xff0c;bug更少的API。 为什么…

桌面级linux推荐,七大顶级桌面比较!Linux平台自由选择

七大顶级Linux桌面&#xff1a;Unity对于开源Linux平台来说&#xff0c;如何选择就是首要解决的问题。通常Linux发行版都有默认的桌面成为你的首选&#xff0c;但目前可供选择的桌面环境种类繁多。特别是Ubuntu系统一个平台就提供9种正式备选版本&#xff0c;且各自拥有不同的桌…

最大子列和问题

问题陈述&#xff1a; 给定N个整数的序列{A1, A2, ... , AN}&#xff0c;求函数ƒ(i, j) max{0, Ai Ai1 ... Aj}(1<i<j<N)的最大值。 问题分析&#xff1a; 求给定数列的最大子列和。 算法设计&#xff1a; 算法1&#xff1a;计算每个子列的和 时间复杂度: T(N) …