【WPF学习】第十九章 控件类

https://www.cnblogs.com/Peter-Luo/archive/2020/01/30/12243949.htmlhtml


  WPF窗口充满了各类元素,但这些元素中只有一部分是控件。在WPF领域,控件一般被描述为与用户交互的元素——能接收焦点并接受键盘或鼠标输入的元素。明显的例子包括文本框和按钮。然而,这个区别有时有些模糊。将工具提示视为控件,由于它根据用户鼠标的移动显示或消失。将标签视为控件,由于它支持记忆码(mnemonics,将焦点转移到相关控件快捷键)。浏览器

  全部控件都继承自System.Windows.Control类,该类添加了一小部分基本的基础结构:app

  •   设置控件内容对齐方式的能力
  •   设置Tab键顺序的能力
  •   支持绘制背景、前景和边框
  •   支持格式化文本内容的尺寸和字体

1、背景画刷和前景画刷ide

  全部控件都包含背景和前景概念。一般,背景是控件的表面(考虑一下按钮边框内部的白色或灰色区域),而前景是文本。在WPF中,分别使用Background和Foreground属性设置这两个区域(但非内容)的颜色。函数

  天然会认为Background和Foreground属性使用颜色对象。然而,这些属性实际上使用的是更强大的对象:Brush对象。该对象为填充背景和前景内容提供了灵活性,可以使用单一颜色(使用SolidColorBrush画刷)或更特殊的颜色(如使用LinearGradientBrush或TileBrush画刷)填充背景和前景。工具

  一、用代码设置颜色性能

  假设但愿在名为cmd的按钮内部设置蓝色表面区域。下面是执行这一操做的代码:字体

cmd.Background=new SolidColorBrush(Colors.AliceBlue);

 这行代码使用由简便类Colors的静态属性预约义的颜色,建立了一个新的SolidColorBrush画刷(属性的名称源自大多数Web浏览器支持的颜色名称)。然而将该画刷设置为按钮的背景画刷,从而使按钮的背景被绘制成带有轻微阴影的蓝色。优化

  也能够根据用户的喜爱从System.Windows.SystemColors枚举中获取系统颜色。下面是一个示例:动画

cmd.Background=new SolidColorBrush(SystemColors.ControlColor);

  由于常用系统画刷,因此SystemControls类还提供了预约义的返回SolidColorBrush对象的属性。下面显示了如何使用这些属性:

cmd.Background=SystemColors.ControlBrush;

  正如文档所记录的,这两个示例都存在一个小问题。若是系统颜色在运行这段代码后发生了变化,不会使用新的颜色更新按钮。本质上,代码获取的是当前颜色或画刷的快照。为确保程序可以根据配置的变化进行更新,须要使用动态资源。后面章节会进行详细介绍。

  Colors和SystemColors类提供了便捷方法,但这并不是设置颜色的惟一方法。也可经过提供R、G、B值(红、绿和蓝)建立Color对象。这三个值中的每个都是0到255之间的数字:

int red=0; int green=255; int blue=0; cmd.Foreground=new SolidColorBrush(Color.FromRgb(red,green,blue));

  也可经过提供Alpha值,并调用Color.FromArgb()方法来建立部分透明的颜色。Alpha值表示彻底不透明,而0表示彻底透明。

  二、在XAML中设置颜色

  在XAML中设置背景色和前景色时,可以使用一种很是有用的快捷方式。不是定义Brush对象,而是提供颜色名或颜色值。WPF解析器将使用指定的颜色自动建立SolidColorBrush对象,并为前景或背景使用该画刷对象。下面是一个使用颜色名得示例:

<Button Background="Red">A Button</Button>

  上面的标记和下面更繁琐的语法使等同的:

<Button>A Button <Button.Background>
        <SolidColorBrush Color="Red"/>
    </Button.Background>
</Button>

  若是想建立不一样类型的画刷(如LinearGradientBrush画刷),并使用该画刷绘制背景,那么须要使用较长的格式。

  若是但愿使用颜色代码,须要使用稍难一点的语法,以十六进制形式设置R、G和B的值。可以使用两种格式的任意一种——#rrggbb或#aarrggbb(它们之间的区别是后一种格式包含了alpha值)。由于使用的是十六进制方式,因此只需使用两位数字提供A、R、G和B值。下面的示例使用#aarrggbb方式建立与上面代码片断相同的颜色:

<Button Background="#FFFF0000">A Button</Button>

  这里,alpha值是FF(255),红色值时FF(255),而绿色值和蓝色值是0;

  使用画刷不只可设置Background和Foreground属性,还可以使用BorderBrush和BorderThickness属性在控件(以及其余元素,如Border元素)周围绘制一条边框。BorderBrush属性使用画刷,而BorderThickness属性使用设备无关单位的边框宽度值。在现实边框前须要设置这两个属性。

2、字体

  Control类定义了一小部分与字体相关的属性,这些属性肯定文本咋控件中的显示方式。下表列出了这些属性。

表 Control类中与字体有关的属性

 

   一、字体家族

  字体家族(font family)是相关字体的集合——例如,Arial Regular、Arial Bold、Arial Italic以及Arial Bold Italic字体都是Arial字体的家族的一部分。尽管每种字体分别定义排版规则和字符,但操做系统仍能识别出它们的相关的。所以,可以使用Arial Regular字体配置元素,将FontWeight属性设置为Bold,但必定要使WPF将其转换为Arial Bold字体。

  当选择字体时,必须提供完整的字体家族名称,以下所示:

<Button name="cmd" FontFamily="Times New Roman" FontSize="18">A Button</Button>

  也可使用代码:

cmd.FontFamily="Times New Roman"; cmd.FontSize="18";

  当肯定FontFamily时,不能使用缩写的字符串。这意味着不能使用Times或Times New代替全名Times New Roman。

  还能够用字体的全名获得斜体或粗体,以下所示:

<Button name="cmd" FontFamily="Times New Ronman Bold">A Button</Button>

  然而,仅使用字体家族名并设置其余属性(如FontStyle和FontWeight属性)获得所需的变体更清晰,也更灵活。例如,下面的标记将FontFamily属性设置为Times New Roman,并将FontWeight属性设置为FontWeights.Bold;

<Button name="cmd" FontFamily="Times New Roman" FontWeight="Bold">A Button</Button>

  二、文本装饰和排版

  有些元素还能够经过TextDecorations和Typography属性,支持更高级的文本控制。这些属性能够修饰文本。例如,可以使用TextDecorations类中的静态属性设置TextDecorations属性。该类仅提供4中修饰,每种修饰均可觉得文本添加几类线,包括BaseLine、OverLine、Strikethrough和Underline。Typography属性更高级,经过该属性能够访问只有某些字体才会提供的特殊字体变种。这方面的例子包括不一样的数字对齐方式、连字(在相邻字母之间的链接)和小音标(caps)。

  对于大多数状况,TextDecorations和Typography特征指用于流文档内容——用于建立丰富的可读文档。然而,这些属性能够用于TextBox类。此外,TextBlock元素也支持他们,TextBlock元素是Label控件的轻量级版本,对于现实少许可换行的文本内容,TextBlock元素是很是完美的。尽管你可能不喜欢对TextBox控件使用文本修饰或改变它的排版,但可能但愿在TextBlock元素中使用下划线。以下所示:

<Button TextDecorations="Underline">Underlined Text</Button>

  三、字体继承

  当设置任何字体属性时,属性值都会流经嵌套的对象。例如,若是为顶级窗口设置FontFamily属性,窗口中的全部控件都会获得相同的FontFamily属性值(除非为控件明确设置了不一样的字体)。这种作法之因此可行,是由于字体属性是依赖项属性,而且依赖项属性可以提供的特性之一就是属性值继承——这是在嵌套的控件中传递字体设置的魔力所在。

  有必要指出,属性值继承可以流经那些根本就不支持相应属性的元素。例如,设想建立包含StackPanel面板的窗口,在StackPanel面板中有三个Label控件。可为窗口设置FontSize属性,由于Windows类继承自Control类。但不能为StackPanel面板设置FontSize属性,由于它不是控件。但若是设置了窗口的FontSize属性,属性值仍然会“通过”StackPanel面板,到达其内部的标签,并改变标签的字体尺寸。

  与字体设置同样,其余几个基本属性也是用属性值继承。在Control类中,Foreground属性使用继承。Background属性不使用(然而,默认背景是空引用,大多数控件将其呈现为透明背景。这意味着仍会显示父元素的背景)。在UIElement类中,AllowDrop、IsEnabled以及IsVisible属性都使用属性继承。在FrameworkElement中,CultureInfo和FlowDirection属性也使用属性值继承。

  四、字体替换

  设置字体时务必谨慎,确保选择的字体在用户计算机上已经存在。然而,WPF没有经过字体回调系统提供一点灵活性。可将FontFamily属性设置为由逗号分隔的字体选项列表。WPF将按顺序遍历该列表,尝试查找在列表中指定的一种字体。

  下面列举一个示例,该例试图使用Technical Italic字体,但若是该字体不存在,就使用ComicSans MS或Arial字体:

<Button FontFamily="Technical Italic,ComicSan MS,Arial">A Button</Button>

  若是某个字体家族的名称中确实包含一个逗号,那么须要经过在一行中将其包含两次来转义该逗号。

  顺便提一下,使用System.Windows.Media.Fonts类的静态SystemFontFamilies集合,可得到在当前计算机上已安装的全部字体的列表。

foreach(FontFamily fontFamily in Fonts.SystemFontamilies) { lstFonts.Items.Add(fontFamily.Source); }

  FontFamily对象还容许检查其余细节,如行间距和关联的字体。

  五、字体嵌入

  处理不常见字体的另外一种选择是在应用成功需中嵌入字体。经过嵌入字体,应用程序就永远不会出现找不到所需字体这一问题。

  嵌入过程很是简单。首先向应用程序添加字体文件(一般是具备.ttf扩展名得文件),并将Build Action选项设置为Resource(为设置该属性,可在Visual Studio的Solution Explorer中选择字体文件,并在Properties窗口中改变它的Build Action属性)。

  接下来,当使用字体时,须要在字体家族名称以前添加字符序列"./#",以下所示:

<Label Name="tst" FontSize="20" FontFamily="./#Bayern"
             >This is an embedded font</Label>

  WPF将"./"字符解释为“当前文件夹”。为理解该字符串序列的含义,须要进一步了解与XAML打包系统相关的内容。

  能够在“./”字符序列以后提供文件名称,但一般添加数字记号(#)和字体的实际家族名。在上面的示例中,嵌入的字体名为Bayern。

  六、文本格式化模式

  WPF中的文本渲染和旧式的基于GDI的应用程序的文本渲染有很大区别。很大一部分区别是因为WPF的设备无关显示系统形成的,但WPF中的文本渲染也获得了显著加强,能更清晰地显示文本,在LCD监视器上尤为如此。

  然而,WPF文本渲染具备一个众所周知的缺点。当使用较小的文本尺寸时,文本会变得模糊,并会显示一些使人讨厌的问题(例如边缘周围的颜色干扰)。使用GDI文本显示时不会发生这些问题,缘由是GDI使用不少技巧来优化小文本的清晰度。例如,GDI可以修改小字母的形状,调整他们的位置,并在像素边界对齐全部内容。浙西步骤致使字体失去了其特殊的性质,当当处理极小的文本时,可在屏幕上获得更好的阅读模式。

  那么如何修复WPF的小文本显示问题呢?最好增大文本(在96dpi的监视器上,使用大约15设备无关单位的文本尺寸,这个问题就会消失),或使用具备足够的分辨率,从而可以清晰显示任何尺寸文本的高dpi显示器。可是由于这些选择每每逃离了实际,因此WPF还具备选择使用与GDI类型的文本渲染能力。

  为了使用GDI风格的文本渲染,为显示文本的元素(例如TextBlock或Label)增长了TextOptions.TextFormattingMode附加属性,并将其设置为Display(而不是标准值Ideal)。下面是一个例子:

<Window x:Class="Controls.GdiTextRendering" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="GdiTextRendering" Height="300" Width="300">
    <StackPanel Margin="10">
        <TextBlock FontSize="12" Margin="5"> This is a Test. Ideal text is blurry at small sizes. </TextBlock>

        <TextBlock FontSize="12" Margin="5" TextOptions.TextFormattingMode="Display"> This is a Test. Display text is crisp at small sizes. </TextBlock>

    </StackPanel>
</Window>

  TextFormattingMode属性仅仅是针对小尺寸文本的解决方案,记住这一点很重要。若是为更大的文本(超过15点的文本)使用该属性,文本将不会一样清晰,间隔将不会一样均衡,而且字体将不会被一样准确呈现。并且若是结合旋转、缩放和改变外观的变换使用文本,应当老是使用WPF的标准文本显示模式。由于针对显示文本的GDI风格的优化是在全部变换以前应用的。一旦应用变换,结果将再也不对齐到像素边界,文本的显示将变得模糊不清。

3、鼠标光标

  对于任何应用程序而言,一个常见任务是调整鼠标光标以指示当应用程序正处于繁忙状态或指示不一样控件的工做方式。可为任何元素使用Cursor属性以设备鼠标指针,该属性继承自FrameworkElement类。
  能够经过System.Windwos.Input.Cursor对象来表示每一个光标。获取Cursor对象的最简易方法是使用Cursors类的静态属性,它们包含了全部标准的Windows鼠标光标,如沙漏光标、手庄光标、调整尺寸的箭头光标等。下面的示例将当前窗口的鼠标光标设置为沙漏光标:

this.Cursor=Cursors.Wait;

  如今,将鼠标移到当前窗口上时,鼠标指针会变成你们属性的沙漏图标。

  若是使用XAML设置鼠标光标,就不须要直接使用Cursors类。这是由于Cursor属性的类型转换器能识别属性名称,并从Cursors类中检索对应的鼠标光标。这意味着当鼠标位于某个按钮上时,为了显示“帮助”光标(箭头和问号的组合),可按以下方式编写标记:

<Button Cursor="Help">Help</Button>

  有时可能设置相互重叠的光标。对于这种状况,会使用最特殊的光标。例如,可为一个按钮额包含按钮的窗口设置不一样的光标。当鼠标移到按钮上时,将显示为按钮设置的光标,而对于窗口中的其余区域则显示为窗口设置的光标。

  但有一个例外,经过使用ForceCursor属性,父元素可覆盖子元素的光标设置。将该属性设置为true时,会忽略子元素的Cursor属性,父元素的光标会被应用到内部的全部内容。

  若是但愿为应用程序每一个窗口中的每一个元素应用光标设置,使用FrameworkElement.Cursor属性将不起做用。相反,须要使用静态的Mouse.OverrideCursor属性,该属性覆盖每一个元素的Cursor属性:

Mouse.OverrideCursor=Cursors.Wait;

  为了移除应用程序范围的光标覆盖设置,须要将Mouse.OverrideCursor属性设置为null。

  最后,WPF彻底支持自定义光标。可以使用广泛的.cur光标文件,也可以使用.ant动画光标文件。要使用自定义的光标,须要为Cursor对象的构造函数传递光标文件的文件名或包含光标数据的流:

Cursor customCursor=new Cursor(Path.Combine(applicationdir,"stopwatch.ani"); this.Cursor=customCursor;

  Cursor对象不直接支持URI资源语法,经过该语法,其余WPF元素(如Image对象)可以使用保存在编译过的额程序集中的文件,然而,可方便地为应用程序添加光标文件做为资源,而后做为可用于构造Cursor对象的数据流检索该资源。诀窍是使用Application.GetResourceStream()方法:

StreamResourceInfo sri=Application.GetResourceStream(new Uri("stopwatch.ani",UriKind.Relative)); Cursor customCursor=new Cursor(sri.Stream); this.Cursor-customCursor;
相关文章
相关标签/搜索