效果如图:

虽然说是自适应可关闭的TabControl,但TabControl并不需要改动,不如叫自适应可关闭的TabItem.

大体思路:建一个用户控件,继承自TabItem,里面放个按钮,点击的时候在TabControl中移除自身.在添加,移除TabItem和TabControl尺寸变化时,通过Items的个数计算合适的Width.

新建用户控件

新建用户控件,并继承自TabItem,这样它就拥有TabItem所有的属性和事件.而这个功能不需要自定义依赖属性和事件.它的用法就和TabItem完全一样.

建完后把UserControl换成TabItem,去掉多余部分

后台继承自UserControl改成继承自TabItem

更改样式添加关闭按钮

在Xmal里添加一个自己喜欢的样式,最主要的是在Template里添加一个按钮,注册一个Click事件,用于关闭.

 <Style TargetType="{x:Type TabItem}">
<Setter Property="BorderBrush" Value="Black"></Setter>
<Setter Property="Background" Value="White"></Setter>
<Setter Property="Foreground" Value="Black"></Setter>
<Setter Property="Padding" Value="5,0,0,0"></Setter>
<Setter Property="HorizontalAlignment" Value="Left"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Left"></Setter>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Border CornerRadius="5,0,0,0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<ContentPresenter Grid.Column="0" ContentSource="Header" Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"></ContentPresenter>
<Button Grid.Column="1" Name="btn_Close" Click="btn_Close_Click"></Button>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" Value="#FFFF923E"></Setter>
<Setter Property="Foreground" Value="White"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

后台的逻辑

查找父级TabControl

注意TabItem并不能关闭自身,这里所说的关闭其实是在他父级TabControl的Items集合里移除.而且父级TabControl的尺寸改变时还要注册事件去改变每个Item的Width.所以我决定找到它的父级TabControl,声明一个私有变量添加对父级的引用.

可以通过可视化树的帮助类VisualTreeHelper来找到它的父级TabControl.当然并不是它的父级直接就是TabControl了,需要递归去查找

 /// <summary>
/// 递归找父级TabControl
/// </summary>
/// <param name="reference">依赖对象</param>
/// <returns>TabControl</returns>
private TabControl FindParentTabControl(DependencyObject reference)
{
DependencyObject dObj = VisualTreeHelper.GetParent(reference);
if (dObj == null)
return null;
if (dObj.GetType() == typeof(TabControl))
return dObj as TabControl;
else
return FindParentTabControl(dObj);
}
计算尺寸

既然是自适应,总得有一个正常的尺寸,只有空间不足的时候才去缩小每个Item.我想到的最简单的办法就是做个约定,把这个尺寸放到父级TabControl的Tag里,这样可以通过对父级TabControl的引用,轻松拿到这个尺寸.

计算方法就是取父级TabControl运行时的宽度ActualWidth除以约定的尺寸,取整形int,这个就是保持约定宽度item个数的临界值了.

小于等于这个值就用约定宽度,大于这个值就用父级运行宽度除以Items的个数求出平均宽度,然后遍历父级TabControl的Items,都赋上这个平均值.

需要注意的是,如果所有Items的尺寸加起来大于等于父级的尺寸,Items会换行,感觉有点丑啊.所以我取的是父级运行宽度-5做的运算,这样就永远也抵达不到边界,不会换行.

不过也可以改写TabControl的控件模版,把放Hrader的容器换成Stackpanel就不会换行了,我只是觉得上面的方法比较简单.

父级尺寸改变

可以通过TabControl的SizeChanged事件监测到.需要干的事就是重新计算尺寸.

关闭按钮

在父级TabControl的Items集合里移除自身后,注意重新计算下尺寸和移除注册SizeChanged事件的方法.

最后附上代码 自适应可关闭的Tab.zip

这个效果比较常见,可能您已经做过了,有更好的想法希望您能分享出来,大家共同进步.

2016-08-16更新:感谢园友 日日夜夜 的反馈,源码已改正

1.TabItem.Resources的关闭按钮样式添加了Key,模版里的关闭按钮添加了对资源的引用.

2.去掉了TabItem样式的HorizontalContentAlignment="Left",VerticalContentAlignment="Center".头部内容的布局方式改为HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}".

WPF自适应可关闭的TabControl 类似浏览器的标签页的更多相关文章

  1. WPF自适应可关闭的TabControl 类似浏览器的标签页(转)

    效果如图: 虽然说是自适应可关闭的TabControl,但TabControl并不需要改动,不如叫自适应可关闭的TabItem. 大体思路:建一个用户控件,继承自TabItem,里面放个按钮,点击的时 ...

  2. vue单页面条件下添加类似浏览器的标签页切换功能

    在用vue开发的时候,单页面应用程序,而又有标签页这种需求,各种方式实现不了, 从这个 到这个,然后再返回上面那个 因为每个标签页的route不一样,导致组件重新渲染的问题,怎么都不知道如何实现... ...

  3. 阻止iOS Web APP中点击链接跳转到Safari 浏览器新标签页

    问题:ios封装完之后,点击里边的按钮会跳转到网页上 ——小卡遇到这个问题就是这样解决的↓↓↓ 解决方法:建议将代码放到</head>标签前,当然,另外存为一个js 文件引用也是可以的呦~ ...

  4. 监听浏览器tab选项卡选中事件,点击浏览器tab标签页回调事件,浏览器tab切换监听事件

    js事件注册代码: <script> document.addEventListener('visibilitychange',function(){ //浏览器tab切换监听事件 if( ...

  5. 类似Jquery ui 标签页(Tabs)

    <div class="indexnew_tit"> <a href="javascript:;" class="on"& ...

  6. selenium 对浏览器标签页进行关闭和切换

    关闭标签页 # 1.关闭浏览器全部标签页 driver.quit() # 2.关闭当前标签页(从标签页A打开新的标签页B,关闭标签页A) driver.close() 切换标签页 from selen ...

  7. python selenium 对浏览器标签页进行关闭和切换

    1.关闭浏览器全部标签页 driver.quit() 2.关闭当前标签页(从标签页A打开新的标签页B,关闭标签页A) driver.close() 3.关闭当前标签页(从标签页A打开新的标签页B,关闭 ...

  8. selenium WebDriver 对浏览器标签页的切换

    关于selenium WebDriver 对浏览器标签页的切换,现在的市面上最新的浏览器,当点击一个链接打开一个新的页面都是在浏览器中打开一个标签页,而selenium只能对窗口进行切换的方法,只能操 ...

  9. Winform 自定义TabControl实现浏览器标签

    作者:Gavin(daisong.michelangelo@gmail.com) 时间: Nov, 2015 封面图片为Gavin原创,请勿未经允许私自引 最近因为工作需要,要做一个桌面浏览器,和大多 ...

随机推荐

  1. [deviceone开发]-一个简单的表单示例

    一.简介 这个例子我们用do_ScrollView+do_LinearLayout来实现,当没有输入相关的值而去保存的时候,则把隐藏的几个提示Label显示出来,然后调用do_LinearLayout ...

  2. ThingkPHP对数据库进行改操作

    public function test_check(){ $Experiment = M("Experiment");//实例化Experiment对象.这个对象是跟数据库的表对 ...

  3. Java 内部类的阐述

    创建一个Computer抽象类:用来在Test类中创建匿名抽象类 package com.zhiyou; public abstract class Computer { int a = 1; /** ...

  4. Github+hexo绑定域名

    Github绑定域名 近期在新网购买了一个属于自己的域名,因此想着把自己用hexo+github搭建的博客通过域名访问,但是找了n长时间来搞,都没有成功.心灰意冷之中再次通过google来搜索,终于有 ...

  5. HTML5-01 简介

    标记语言 概述 标记语言(也称置标语言),是一种将文本及文本相关的其他信息结合起来,展现出关于文档结构和数据处理细节的计算机编码.与文本相关的其他信息(包括例如文本的结构和表示信息等)与原来的文本结合 ...

  6. 干货发布:VSS文件清理工具

    一.功能:1.删除VSS文件(以.vssscc,.scc,.vspscc为后缀的文件)2.去除文件解决方案文件和C#项目文件中的VSS标签3.删除Bin和Obj目录 二.开发工具:vs 2010 三. ...

  7. SQLServer中的页如何影响数据库性能 (转)

    无论是哪一个数据库,如果要对数据库的性能进行优化,那么必须要了解数据库内部的存储结构.否则的话,很多数据库的优化工作无法展开.对于对于数据库管理员来说,虽然学习数据库的内存存储结构比较单调,但是却是我 ...

  8. 深度解析mysql登录原理

    使用mysql数据库的第一步必然是建立连接登录,然后在上面执行SQL命令.无论是通过mysql的客户端,还是通过C-API,JDBC标准接口连接数据库,这个过程一定少不了.今天我们聊一聊mysql登陆 ...

  9. SQL Like模糊查询一些小知识

    模糊查询: where mc like '值':返回值等同于where mc ='值' where mc like '%值':匹配 名称是 '*值'(以“值”作为结尾)的所有数据,*表示任何值任何长度 ...

  10. Memcached学习笔记

    [TOC] 前言 此为学习笔记汇总,如有纰漏之处,还望不吝指出,谢谢. 启动流程 调用settings_init()设定初始化参数 从启动命令中读取参数来设置setting值 设定LIMIT参数 开始 ...