• WPF里最简单的控件的Style你能写对么?(默认Style是有问题的)


    第一个问题,WPF最简单的常用控件是什么?(先声明Path不算控件)

    无论从控件的功能还是从控件的外观来看,最简单都是那个在菜单和Ribbon里很常见的分隔线。没错,它已经从WinForm里的一个字符串(-)进化成一个独立控件(Separator)了。

    Separator继承于Control,而且没有添加一个属性或事件。当仁不让地成为了WPF中最简单控件的首选。

    其全部Style代码如下所示:

            <Style x:Key="DefaultSeparatorStyle" TargetType="{x:Type Separator}">

                <Setter Property="Background"

                        Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>

                <Setter Property="Margin" Value="0,2,0,2"/>

                <Setter Property="Focusable" Value="false"/>

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate TargetType="{x:Type Separator}">

                            <Border Height="1" SnapsToDevicePixels="true"

                                    Background="{TemplateBinding Background}"

                                    BorderBrush="{TemplateBinding BorderBrush}"

                                    BorderThickness="{TemplateBinding BorderThickness}"/>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>

    这么简单的Style,还拿出来说什么?似乎也没有什么好学的啊。不就个TemplateBinding和绑定到SystemColors看上去还高深一些么?

    好现在让你做个事情你就明白了。如果我们想要一个正方形的Button会怎么办?注意是Button,不是Separator

    代码如下:

    <Button Width="30" Height="30"/>

    很简单,那么如果我要一个高度为2个像素的Separator怎么办?也一样写:

    <Separator Height="2"/>

    行么?

    请再鄙视一眼那个默认Style,行么?如果可行,我就不写这篇文章了。

    看到Style里的Border了么?第一个属性就是Height=1。这个属性NB啊,无论你Separator多高,我就是1个像素了。那如果就是想画一个2个像素高的Separator要怎么办啊?

    重写Style!就是把默认Style里的Height=1去了,再用Setter加个默认高为1,再在想让Separator2个像素高的地方设置Height=2。万事大吉。要重写Style啊。

    这篇文章主要不是来介绍如果写个高度为2Separator的。而是来强调Style的灵活性的。如果Style不够灵活,这次因为改Height就要改Style,下次是不是改颜色也要Style呢?还有BorderBrushBorderThicknessForegroundOpacityMask等等,是不是改个属性,就要新建一个Style呢?

    肯定不行啊。所以在你写个Style的第一行的时候,就应该时刻惦记着,你在Style做的样子,Style的使用者是不是可以很方便改变这个Style的默认外观,做一些定制化。有时的确不能保证所有的Template内的控件都可以定制化,这时就要做权衡,让重要的控件的外观可定制化,次要的可以Hard CodeStyle内部。

    所以在WPF控件的默认Style里,你可以看到很多TemplateBinding,这些Binding的存在就是为了不在TemplateHard Code控件的属性。

    但是看到Separator的默认Style,我已经有些出离愤怒了。这可是打着Microsoft商标的微软特产啊,而且是其中技术含量最低的一个Style。结果却犯了最低级的错误,而且还不只一个。

    错误如下:

    1.       Hard Code高度为1

    2.       Hard Code SnapsToDevicePixelsTure

    3.       错误地使用了Border去绘制直线。应该使用PathLine。请不要为什么,谢谢。最基本的OOD了。即使不考虑逻辑,功能上也不正确的。

    在此更提醒为数不多的WPF初学者们,学习要专注,可以沉迷于微软的技术,但不要迷信微软的技术。我也没有非难或是指摘微软员工的意思,Bug哪都有。找到BugFix或是Workaround才是主要的。

    正确的Style有很多,下面一种供大家参考。

            <Style x:Key="CorrectSeparatorStyle" TargetType="{x:Type Separator}">

                <Setter Property="Background"

                        Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>

                <Setter Property="Margin" Value="0,2,0,2"/>

                <Setter Property="Focusable" Value="false"/>

                <Setter Property="Height" Value="1"/>

                <Setter Property="SnapsToDevicePixels" Value="True"/>

                <Setter Property="Template">

                    <Setter.Value>

                        <ControlTemplate TargetType="{x:Type Separator}">

                            <Line Stretch="Fill" X2="1"

                                  Stroke="{TemplateBinding Background}"

                                  StrokeThickness="{TemplateBinding Height}"

                                  StrokeStartLineCap="Square" StrokeEndLineCap="Square"/>

                        </ControlTemplate>

                    </Setter.Value>

                </Setter>

            </Style>

    解释一下:

    1.       首先,这里的X2=”1”并不属于Hard Code

    2.       StrokeStartLineCapStrokeEndLineCap属于Hard Code。但是不影响当然Separator的使用。Separator本身就没有这些属性让人设置的。

    3.       HeightSnapsToDevicePixelSetter中设置默认值。

    如果让我来写个Separator这个控件,我会把Line或是Path的一些有用的属性添加给Separator,就可以让Separator更加灵活。

    在实际的项目中,如果的确需要一个强大的Separator控件,外观很灵活的,又不想写个单独的AdvSeparator控件。最简单的一个办法就是不用Separator,直接用Line,然后给Line定义一个SeparatorLineStyle。参考示例如下:

            <Style x:Key="SeparatorLineStyle"

                   TargetType="{x:Type Line}">

                <Setter Property="X2" Value="1"/>

                <Setter Property="Height" Value="1"/>

                <Setter Property="Stretch" Value="Fill"/>

                <Setter Property="StrokeEndLineCap" Value="Square"/>

                <Setter Property="StrokeStartLineCap" Value="Square"/>

                <Setter Property="StrokeThickness"

                        Value="{Binding Height, RelativeSource={RelativeSource Self}}"/>

                <Setter Property="Stroke"

                        Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>

            </Style>

    这样,既可以用到Line的所有高级功能去绘制一条Separator,又不需要自定义一个控件。

    Style可以很强悍,也可以很破烂。

  • 相关阅读:
    安装 node-sass 的不成功
    input标签附带提示文字(bootstrap里面输入框的两侧同时添加额外元素)
    更改bootstrap的默认样式
    属性font-family:Font property font-family does not have generic default
    let与const命令
    vue之监听事件
    组件复用传值(待解决问题)
    vue之组件注册
    vue之组件理解(一)
    学习整理与细化(2)——HTML VS XHTML
  • 原文地址:https://www.cnblogs.com/nankezhishi/p/MostSimpleStyleAndGuide.html
Copyright © 2020-2023  润新知