WPF自适应可关闭的TabControl 类似浏览器的标签页(转)
效果如图:
虽然说是自适应可关闭的TabControl,但TabControl并不需要改动,不如叫自适应可关闭的TabItem.
大体思路:建一个用户控件,继承自TabItem,里面放个按钮,点击的时候在TabControl中移除自身.在添加,移除TabItem和TabControl尺寸变化时,通过Items的个数计算合适的Width.
新建用户控件
新建用户控件,并继承自TabItem,这样它就拥有TabItem所有的属性和事件.而这个功能不需要自定义依赖属性和事件.它的用法就和TabItem完全一样.
建完后把UserControl换成TabItem,去掉多余部分
后台继承自UserControl改成继承自TabItem
更改样式添加关闭按钮
在Xmal里添加一个自己喜欢的样式,最主要的是在Template里添加一个按钮,注册一个Click事件,用于关闭.

1 <Style TargetType="{x:Type TabItem}">
2 <Setter Property="BorderBrush" Value="Black"></Setter>
3 <Setter Property="Background" Value="White"></Setter>
4 <Setter Property="Foreground" Value="Black"></Setter>
5 <Setter Property="Padding" Value="5,0,0,0"></Setter>
6 <Setter Property="HorizontalAlignment" Value="Left"></Setter>
7 <Setter Property="VerticalAlignment" Value="Center"></Setter>
8 <Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
9 <Setter Property="VerticalContentAlignment" Value="Center"></Setter>
10 <Setter Property="Template">
11 <Setter.Value>
12 <ControlTemplate TargetType="{x:Type TabItem}">
13 <Border CornerRadius="5,0,0,0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
14 <Grid>
15 <Grid.ColumnDefinitions>
16 <ColumnDefinition Width="*"></ColumnDefinition>
17 <ColumnDefinition Width="20"></ColumnDefinition>
18 </Grid.ColumnDefinitions>
19 <ContentPresenter Grid.Column="0" ContentSource="Header" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"></ContentPresenter>
20 <Button Grid.Column="1" Name="btn_Close" Click="btn_Close_Click"></Button>
21 </Grid>
22 </Border>
23 <ControlTemplate.Triggers>
24 <Trigger Property="IsSelected" Value="true">
25 <Setter Property="Background" Value="#FFFF923E"></Setter>
26 <Setter Property="Foreground" Value="White"></Setter>
27 </Trigger>
28 </ControlTemplate.Triggers>
29 </ControlTemplate>
30 </Setter.Value>
31 </Setter>
32 </Style>

后台的逻辑
查找父级TabControl
注意TabItem并不能关闭自身,这里所说的关闭其实是在他父级TabControl的Items集合里移除.而且父级TabControl的尺寸改变时还要注册事件去改变每个Item的Width.所以我决定找到它的父级TabControl,声明一个私有变量添加对父级的引用.
可以通过可视化树的帮助类VisualTreeHelper来找到它的父级TabControl.当然并不是它的父级直接就是TabControl了,需要递归去查找

1 /// <summary>
2 /// 递归找父级TabControl
3 /// </summary>
4 /// <param name="reference">依赖对象</param>
5 /// <returns>TabControl</returns>
6 private TabControl FindParentTabControl(DependencyObject reference)
7 {
8 DependencyObject dObj = VisualTreeHelper.GetParent(reference);
9 if (dObj == null)
10 return null;
11 if (dObj.GetType() == typeof(TabControl))
12 return dObj as TabControl;
13 else
14 return FindParentTabControl(dObj);
15 }

计算尺寸
既然是自适应,总得有一个正常的尺寸,只有空间不足的时候才去缩小每个Item.我想到的最简单的办法就是做个约定,把这个尺寸放到父级TabControl的Tag里,这样可以通过对父级TabControl的引用,轻松拿到这个尺寸.
计算方法就是取父级TabControl运行时的宽度ActualWidth除以约定的尺寸,取整形int,这个就是保持约定宽度item个数的临界值了.
小于等于这个值就用约定宽度,大于这个值就用父级运行宽度除以Items的个数求出平均宽度,然后遍历父级TabControl的Items,都赋上这个平均值.
需要注意的是,如果所有Items的尺寸加起来大于等于父级的尺寸,Items会换行,感觉有点丑啊.所以我取的是父级运行宽度-5做的运算,这样就永远也抵达不到边界,不会换行.
不过也可以改写TabControl的控件模版,把放Hrader的容器换成Stackpanel就不会换行了,我只是觉得上面的方法比较简单.
父级尺寸改变
可以通过TabControl的SizeChanged事件监测到.需要干的事就是重新计算尺寸.
关闭按钮
在父级TabControl的Items集合里移除自身后,注意重新计算下尺寸和移除注册SizeChanged事件的方法.
最后附上代码 自适应可关闭的Tab
这个效果比较常见,可能您已经做过了,有更好的想法希望您能分享出来,大家共同进步
WPF自适应可关闭的TabControl 类似浏览器的标签页(转)的更多相关文章
- WPF自适应可关闭的TabControl 类似浏览器的标签页
效果如图: 虽然说是自适应可关闭的TabControl,但TabControl并不需要改动,不如叫自适应可关闭的TabItem. 大体思路:建一个用户控件,继承自TabItem,里面放个按钮,点击的时 ...
- vue单页面条件下添加类似浏览器的标签页切换功能
在用vue开发的时候,单页面应用程序,而又有标签页这种需求,各种方式实现不了, 从这个 到这个,然后再返回上面那个 因为每个标签页的route不一样,导致组件重新渲染的问题,怎么都不知道如何实现... ...
- 阻止iOS Web APP中点击链接跳转到Safari 浏览器新标签页
问题:ios封装完之后,点击里边的按钮会跳转到网页上 ——小卡遇到这个问题就是这样解决的↓↓↓ 解决方法:建议将代码放到</head>标签前,当然,另外存为一个js 文件引用也是可以的呦~ ...
- 监听浏览器tab选项卡选中事件,点击浏览器tab标签页回调事件,浏览器tab切换监听事件
js事件注册代码: <script> document.addEventListener('visibilitychange',function(){ //浏览器tab切换监听事件 if( ...
- 类似Jquery ui 标签页(Tabs)
<div class="indexnew_tit"> <a href="javascript:;" class="on"& ...
- selenium 对浏览器标签页进行关闭和切换
关闭标签页 # 1.关闭浏览器全部标签页 driver.quit() # 2.关闭当前标签页(从标签页A打开新的标签页B,关闭标签页A) driver.close() 切换标签页 from selen ...
- python selenium 对浏览器标签页进行关闭和切换
1.关闭浏览器全部标签页 driver.quit() 2.关闭当前标签页(从标签页A打开新的标签页B,关闭标签页A) driver.close() 3.关闭当前标签页(从标签页A打开新的标签页B,关闭 ...
- selenium WebDriver 对浏览器标签页的切换
关于selenium WebDriver 对浏览器标签页的切换,现在的市面上最新的浏览器,当点击一个链接打开一个新的页面都是在浏览器中打开一个标签页,而selenium只能对窗口进行切换的方法,只能操 ...
- Winform 自定义TabControl实现浏览器标签
作者:Gavin(daisong.michelangelo@gmail.com) 时间: Nov, 2015 封面图片为Gavin原创,请勿未经允许私自引 最近因为工作需要,要做一个桌面浏览器,和大多 ...
随机推荐
- Dubbo通过注解实现RPC调用
启动Dubbo服务有2个方式,1是通过xml配置,2是通过注解来实现,这点和Spring相似. 采用XML配置如下: <?xml version="1.0" encodin ...
- Unity 和 3DMAx
3DMax转换成DAE模式才会有纹理信息.
- 这真是奇葩的js题目
url:http://javascript-puzzlers.herokuapp.com/ 有兴趣的可以一看,算是比较偏门自我感觉
- bzoj1001平面图最小割转对偶图最短路
https://www.lydsy.com/JudgeOnline/problem.php?id=1001 很明显的求对偶图的最短路即可(由于特判写错了一直wa = = ) //#pragma com ...
- Back Track5学习笔记
1.BT5默认用户名:root.密码:toor(公司是yeslabccies) 2.进入图形化界面命令:startx 3.更改密码:sudo passwd root 扫描工具 第一部分网络配置: 4. ...
- linux下使用FreeRDP 连接 Windows 远程桌面
linux下使用FreeRDP 连接 Windows 远程桌面 简介 FreeRDP 是一款开源的远程桌面系统,支持多种平台, 在 ubuntu 中使用 FreeRDP 可以很方便的登录到 win ...
- iptables(五)iptables匹配条件总结之二(常用扩展模块)
iprange扩展模块 之前我们已经总结过,在不使用任何扩展模块的情况下,使用-s选项或者-d选项即可匹配报文的源地址与目标地址,而且在指定IP地址时,可以同时指定多个IP地址,每个IP用" ...
- 不使用构造方法创建Java对象: objenesis的基本使用方法
转载:http://blog.csdn.net/codershamo/article/details/52015206 objenesis简介: objenesis是一个小型Java类库用来实例化一个 ...
- 将封装了envi功能的IDL类导出成java类,方便java调用
目的: 用IDL将ENVI的功能封装成为IDL的类,并使用IDL的对象导出功能把这些功能类导出为java类,方便java调用.(本来想直接通过GP工具调用的,但是没有授权文件) 操作步骤: ...
- laravel5.5中查询构造器的使用
//查询构造器新增数据: public function query1() { /* $bool=DB::table('student')->insert( ['name'=>'小李',' ...