【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;
相關文章
相關標籤/搜索