• 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.zip

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

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

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

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

    http://www.cnblogs.com/tsliwei/p/5625398.html

  • 相关阅读:
    GitHub 上的优质开源游戏项目,每个都很厉害
    使用entities html 转义
    TDesign 正式开源发布,腾讯设计云布局重要能力拼图!
    copytoclipboard
    劲爆!Java 18 正式发布,默认 UTF8,finalize 被弃用。。别再乱用了!
    请求合并的 3 种方式,大大提高接口性能。。。
    面试官:说下你公司系统怎么设计防重复数据的?架构师必问!
    别再写垃圾代码了:试试阿里巴巴 Java 开发插件,打造你的团队专属风格。。。
    给你 2 万条数据,怎么快速导入到 MySQL?写得太好了...
    qt6的安装
  • 原文地址:https://www.cnblogs.com/sjqq/p/8391881.html
Copyright © 2020-2023  润新知