WPF控件


  本次將介紹控件——繼承自System.Windows.Control類的元素。首先分析Control基類,並學習該類支持畫刷和字體的原理。然后研究WPF控件的目錄,包括以下控件:

  • 內容控件——這些控件能夠包含嵌套的元素,為它們提供幾乎無限的顯示能力。內容控件包括Label、Button以及ToolTip類。
  • 帶有標題的內容控件——這些空間是允許添加一個主要內容部分以及一個單獨標題部分的內容控件。他們通常用於包裝更大的用戶界面塊。這類控件包括TabItem、GroupBox以及Expander類。
  • 文本控件——文本控件比較少,他們允許用戶輸入文本。文本控件支持普通文本、密碼以及格式化文本。
  • 列表控件——這些空間在列表中顯示項目集合。列表控件包括ListBox和ComboBox類。
  • 基於范圍的控件——這些空間通常只關心一個屬性:Value,可以使用預先規定范圍內的任何數字設置該屬性。
  • 日期控件——這類控件包含兩個允許用戶選擇日期的控件Calendar和DatePicker控件。

  6.1 控件類

  在WPF窗口充滿了各種元素,但是這些元素中只有一部分是控件。在WPF中,控件通常被描述為和用戶交互的元素——能夠接收焦點並接受鍵盤或鼠標輸入的元素。所有控件都繼承自System.Windows.Control類,該類添加了一點基本的基礎結構:

  • 設置控件內容對齊方式
  • 設置Tab鍵順序的能力
  • 支持繪制背景、前景和邊框
  • 支持格式化文本內容的尺寸和字體

  6.1.1 背景畫刷和前景畫刷

  所有的空間都包含背景和前景的概念。通常,背景是控件的表面,而前景是文本。在WPF中,分別使用Background和Foreground屬性設置這兩個區域的顏色。在WPF中Background和Foreground屬性不像在Windows窗體應用程序總所做的那樣。這些屬性可以使用更強大的對象:Brush對象。該對象為填充背景和前景內容體統了靈活性,可以使用單一顏色(SolidColorBrush)或更特殊的顏色(LinearGradientBrush或TileBrush)填充背景和前景。此次只使用簡單的SolidColorBrush畫刷,之后學習更特殊的畫刷。

  我們可以用Colors類的靜態屬性預定義的顏色,創建一個新的SolidColorBrush畫刷。然后將該畫刷設置為控件的背景顏色。如下一個示例,將一個按鈕的顏色設置為有輕微陰影的藍色

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

也可以從System.Windows.SystemColors枚舉中獲取系統顏色。

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

因為系統畫刷經常使用,所以SystemColors類還提供了預定義的返回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值255表示完全不透明,0表示不透明。

在XAML中設置背景色和前景色時,可以使用一個非常有用的快捷方式。不是定義一個Brush對象,而是提供一個顏色名或顏色值。WPF解析器會自動使用指定的顏色創建一個SolidColorBrush對象,並為前景或背景使用該畫刷對象。下面是一個使用顏色名的示例:

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

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

如果希望使用顏色代碼,就需要使用稍微有些不方便的語法,以十六進制方式設置R、G和B的值。可以使用兩種格式中的任意一種—#rrggbb或#aarrggbb(區別為后者中格式包含了alpha值)。

  使用畫刷不僅可以設置Background和Foreground屬性。還可以使用BorderBrush和BorderThickness屬性在控件(以及其他元素)周圍繪制一個邊框。BorderBrush屬性使用所選的畫刷,而BorderThickness屬性使用設備無關單位的邊框寬度值。在顯示邊框前要設置這兩個屬性。


6.1.2 字體

  Control類定義了一小部分與字體相關的屬性,這些屬性確定文本在控件中的顯示方式。

FontFamily 希望使用的字體的名稱
FontSize 字體的設備無關單位尺寸。
FontStyle 由FontStyle對象表示的文本角度。可以從FontStyles類的靜態屬性中獲取需要的預定義FontStyle對象,包括Normal、Italic或Oblique字母
FontWeight 由FontWeight對象表示的文本重量。可以從FontWeight類的靜態屬性中獲取需要的預定義FontWeight對象。
FontStretch 字體被拉伸或壓縮的程度,由FontStretch對象表示。

  FontFamily——相關字體的集合。當選擇字體時,必須提供完整的字體家族名稱,如下:

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

也可以使用代碼:cmd.FontFamily="Times New Roman";cmd.FontSize="18";

  文本裝飾和排版——有些元素還可以通過TextDecorations和Typograhpy屬性,支持更高級的文本控制。這些屬性可以修飾文本。例如:TextDecorations類的靜態屬性設置TextDecorations屬性。該類提供了4種修飾,每種都可以為文本添加幾類線(Baseline、Overline、Strikethrough、Underline)。Typography屬性更高級:通過該屬性可以訪問只有某些字體才會提供的特殊的字體變種。對於大多數情況,TextDecorations和Typograhpy特征只用於劉文檔內容——用於創建豐富的可讀的文檔。然而,這些屬性也可以用於TextBox類。此外,TextBlock元素也支持它們。

  字體繼承——當設置任何字體屬性時,屬性值都會流經嵌套的對象。例如:如果為頂級窗口設置了FontFamily屬性,窗口中的所有空間按都會得到相同的FontFamily屬性值。這一特性和Windows窗體中的環境屬性類似,但是背后的工作原理不同。之所以會這樣是因為字體屬性石依賴項屬性,並且依賴項屬性能搞提供的特性之一就是屬性值繼承。

  字體替換——當設置字體時,一定要謹慎,確保選擇的字體在用戶計算機上已經存在。然而,WPF沒有通過字體回調系統提供一點靈活性。可以將FontFamily屬性設置為一個由逗號分割的字體選擇列表。如下:

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

如果某個字體家族的名稱中確實包含一個逗號,則需要通過在一行中包含它兩次來轉義該逗號。此外使用System.Windows.Media.Fonts類的靜態的SystemFontFamilies集合,可以獲得在當前計算機上已安裝的所有自提的列表。如下,是將該集合添加到一個列表框中

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

FontFamily對象還允許其他檢查其它細節,如行間距和關聯的字體。

  文本格式化模式—— WPF中文本渲染和來的基於GDI的應用程序的文本渲染有很大的區別。有很大一部分區別是由於WPF的設備無關顯示系統造成的,但是WPF中的文本渲染也得到了顯著的增強,能更清晰得顯示文本。在WPF中顯示比較小的文本尺寸時,文本會變得模糊,並且會顯示一些令人討厭的問題。為了使用GDI風格的文本渲染,為顯示文本的元素,增加了TextOptions.TextFormattingMode附加屬性,並且將其設置為Display

        <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>

  鼠標光標——對於任何應用程序一個常見的任務是,調整鼠標光標以指

但是要記住TextFormattingMode僅是針對小尺寸文本的解決方案。示當前應用程序正處於繁忙狀態或指示不同控件的工作方式。可以為任何元素使用Cursor屬性設置鼠標指針,該屬性繼承自FrameworkElement類。每個光標通過一個System.Windows.Input.Cursor對象表示。獲取Cursor對象的最簡單方法是使用Cursors類的靜態屬性。它包含所有標准的Windows鼠標光標。如下將當前窗口的鼠標光標設置為沙漏光標:

this.Cursor=Cursors.Wait;

如果使用XAML設置鼠標光標,就不需要直接使用Cursors類。因為Cursor屬性的類型轉換器能夠識別屬性名稱,並從Cursors類中檢索對應的鼠標光標。如下是一個幫助光標按鈕

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

通過使用ForceCursor屬性,父元素可以覆蓋子元素的光標設置。當把該屬性設置為true時,會忽略子元素的Cursor屬性,並且父元素的光標會被應用到內部的所有內容。

 6.2 內容控件

  內容控件是更特殊的控件類型,他們可以包含一塊內容。從技術角度講,內容控件是可以包含單個嵌套元素的控件。所有WPF布局容器都繼承自抽象的Panel類,該類提供了對包含多個元素的支持。類似的,所有內容控件都繼承自抽象的ContentControl類。

6.2.1 Content屬性

  與Panel類提供一個Children集合來保存嵌套的元素不同,Control類添加了一個Content屬性,該屬性只接受單一對象。Content屬性支持任何類型的對象,但是可以將該屬性包含的對象分為兩大類,針對每一類進行不同的處理:

  • 未繼承自UIElement類的對象:內容控件調用這些控件的ToString()方法獲取文本,然后顯示該文本。
  • 繼承自UIElement類的對象:這些對象(包括所有的可視化元素,它們是WPF組成部分)使用UIElement.OnRender()方法在內容控件內部進行顯示

如下的示例:

    <StackPanel Margin="3">
      <Button Margin="3">Text button</Button>
      <Button Margin="3">
        <Image Source="happyface.jpg" Stretch="None" />
      </Button>
      <Button Margin="3">
        <StackPanel>
          <TextBlock Margin="3">Image and text button</TextBlock>
          <Image Source="happyface.jpg" Stretch="None" />
          <TextBlock Margin="3" >Courtesy of the StackPanel</TextBlock>
        </StackPanel>
      </Button>
      <Button Padding="3" Margin="3" HorizontalContentAlignment="Stretch">
        <StackPanel>
          <TextBlock Margin="3">Type something here:</TextBlock>
          <TextBox Margin="3" HorizontalAlignment="Stretch">Text box in a button</TextBox>          
        </StackPanel>
      </Button>
      
    </StackPanel>
View Code

6.2.2 對齊內容

  通過使用HorizontalContentAlignment和VerticalContentAlignment屬性屬性內容控件中的內容如何和其邊框對齊。我們可以通過這兩個屬性將內容對齊到控件的任意邊緣(TOP、Bottom、Left、Right),可以居中(Center),或者可以拉伸內容使其充滿可用空間(Strech)。這些設置被直接應用於嵌套的內容元素,但是可以使用多層嵌套創建復雜布局。

6.2.3 標簽

  所有內容控件中最簡單的是Label控件。其他任何內容控件類似,Label控件接受希望放入其中的單一內容。但不同的是Label控件支持記憶符——本質上,記憶符是能夠為鏈接的控件設置焦點的快捷鍵。為支持此功能,Label控件添加了一個Target屬性。為了設置Target屬性,需要使用一個指向另一個控件的綁定表達式,所有記憶符都是使用Alt鍵和已確定的快捷鍵工作。如下:

    <Label Target="{Binding ElementName=txtA}">Choose _A</Label>
    <TextBox Name="txtA"></TextBox>
    <Label Target="{Binding ElementName=txtB}">Choose _B</Label>
    <TextBox Name="txtB"></TextBox>
View Code

6.2.4 按鈕

  WPF提供了三種類型的按鈕控件:熟悉的Button控件、CheckBox控件和RadioButton控件。所有這些控件都繼承自ButtonBase類的內容控件。ButtonBase類增加了幾個成員。定義了Click事件並添加了對命令的支持,從而允許為更高層的應用程序任務觸發按鈕。ButtonBase類添加了一個ClickMode屬性,該屬性決定何時引發Click事件以引發Click事件以響應鼠標動作。默認值是ClickMode.Release(單擊鼠標並釋放時觸發Click事件),ClickMode.Press是第一次按下時引發,ClickMode.Hover是在按鈕上懸停一會兒就觸發。

  Button控件——Button類表示一直使用的Windows下壓按鈕。它添加了兩個可寫屬性:IsCancel和IsDefault。

  • 如果IsCancel屬性設置為true,按鈕就成為窗口的取消按鈕,在當前窗口的任何文職如果按下Esc鍵,就會觸發該按鈕。
  • 如果IsDefault屬性設置為true,按鈕就會成為默認按鈕。它的行為取決於焦點在窗口中的當前位置。

  ToggleButton控件和RepeatButton控件——除了Button類之外,還有三個繼承自ButtonBase類。

  • GridViewColumnHeader類,當使用一個基於網格的ListView控件時,該類表示一列可以單機的標題。
  • RepeatButton類,只要按鈕保持按下狀態,該類就不斷的觸發Click事件。
  • ToggleButton類,該類表示具有兩個狀態的按鈕,當單擊ToggleButton按鈕時,它會保持按下狀態知道再次單擊該按鈕已釋放它。有時稱為“黏貼單擊”行為。

  CheckBox控件——CheckBox控件和RadioButton控件是不同類型的按鈕。他們繼承自ToggleButton類,這意味着用戶可以切換他們的開與關狀態。對於CheckBox控件切換到控件的“開”狀態,意味着在其中放置了一個復選標記。ToggleButton類添加了IsChecked屬性。IsChecked屬性是一個可空的boolean類型,這意味着該屬性可以設置為true、false、null。ToggleButton類還添加了IsThreeState屬性,該屬性決定了用戶是否能夠將復選框設置為不確定狀態,如果IsThreeState屬性為false,只有選擇和未選擇兩種狀態,如果IsThreeState屬性為true,則會有不確定的狀態。ToggleButton還定義了Checked、UnChecked、Indeterminate三個事件。

  RadioButton控件——RadioButton控件也繼承自ToggleButton類,並且使用相同的IsChecked屬性和相同的Checked、UnChecked以及Indeterminate事件。另外,RadioButton類還增加了GroupName屬性,該屬性用於控制如何對單選按鈕進行分組。如下示例:

    <StackPanel>
      <GroupBox Margin="5">
        <StackPanel>
          <RadioButton>Group 1</RadioButton>
          <RadioButton>Group 1</RadioButton>
          <RadioButton>Group 1</RadioButton>
          <RadioButton Margin="0,10,0,0" GroupName="Group2">Group 2</RadioButton>
        </StackPanel>
      </GroupBox>
      <GroupBox Margin="5">
        <StackPanel>
          <RadioButton>Group 3</RadioButton>
          <RadioButton>Group 3</RadioButton>
          <RadioButton>Group 3</RadioButton>
          <RadioButton Margin="0,10,0,0" GroupName="Group2">Group 2</RadioButton>
        </StackPanel>
      </GroupBox>
    </StackPanel>
View Code

6.2.5 工具提示

  在WPF中為工具提示(tooltip)提供了一個靈活的模型,因為在WPF中工具提示是內容控件,所以可以在工具提示中放置任何可視化元素。還可以改變各種時間設置來控制工具提示的顯示和隱藏速度。我們可以為元素簡單的設置Tooltip屬性,ToolTip屬性是在FrameworkElement類中定義的,所以所有可以放置到窗口上的元素都可以使用ToolTip屬性。如下:

<Button ToolTip="This is my tooltip" ToolTipService.InitialShowDelay="5000">I have a tooltip</Button>

  如果我們希望提供更復雜的工具提示內容,就需要將ToolTip屬性分為單獨的元素如下:

    <Button ToolTipService.InitialShowDelay="0" ToolTipService.BetweenShowDelay="5000">
      <Button.ToolTip>
        <ToolTip Background="#60AA4030" Foreground="White"
                 HasDropShadow="False" >
        <StackPanel>
          <TextBlock Margin="3" >Image and text</TextBlock>
          <Image Source="happyface.jpg" Stretch="None" />
          <TextBlock Margin="3" >Image and text</TextBlock>          
        </StackPanel>
        </ToolTip>
        </Button.ToolTip>      
      <Button.Content>I have a fancy tooltip</Button.Content>
      
    </Button>
View Code

設置ToolTip對象的屬性——ToolTip是一個內容控件,所以可以調整它的標准屬性,如Background屬性、Padding屬性和Font屬性。還可以修改ToolTip類中定義的成員,如下:

HasDropShadow 決定工具提示是否具有擴散的黑色陰影,使其和背后的窗口區別開來。
Placement 使用一個PlacementMode枚舉值決定如何放置工具提示。Mouse:表示工具提示方框的左上角與當前鼠標的位置相關其他枚舉值使用絕對屏幕坐標來設置工具提示的位置,或相對於其他元素設置工具提示的位置。
HorizontalOffset和VerticalOffset 將工具提示為跳到所希望的位置。可以使用正值和負值。
PlacementTarget 允許相對於另一個元素定位工具提示。為了使用該屬性,Placement屬性必須設置為Left、Right、Top、Bottom或Center。
CustomPopupPlacementCallback 允許使用代碼動態地定位工具提示。如果Placement屬性被設置為Custom,此屬性確定由TooTip調用來獲取ToolTip對象放置位置的方法。回調方法接收三部分信息——popupSize(ToolTip的大小)、targetSize(PlacementTarget的大小)和offset(根據HorizontalOffset和VerticalOffset屬性創建的一個點)。該方法返回一個CustomPopupPlacement對象,該對象告訴WPF將工具提示放在什么位置。
StaysOpen 該屬性實際上不起作用。它的目的是讓你創建一個直保持打開狀態的工具提示,直到用戶在其他地方點擊鼠標位置。然而,ToolTipService.ShowDuration屬性覆蓋了StaysOpen屬性。因此,在經歷了設置的時間之后或當用戶移開鼠標時,工具提示總是會消失。如果希望創建一個始終保持打開狀態的類似工具提示的窗口,最簡單的方法是使用Popup控件
IsEnabled和IsOpen IsEnabled屬性可以暫時禁用工具提示,而通過IsOpen水洗那個可以使用代碼控制工具提示的顯示和隱藏。

ToolTipService屬性——有幾個工具提示屬性不能通過ToolTip類的屬性進行配置。對此,需要使用另一個類ToolTipService類。使用ToolTipService類可以配置顯示工具提示的相關延遲時間。ToolTipService類的所有屬性都是附加屬性,所以尅在控件標簽中直接設置他們。ToolTipService類定義了許多與ToolTip相同的屬性,從而當處理只有文本的工具提示時可以使用更簡單的語法。,不是添加一個嵌套的TooTip元素,可以使用特性設置所有內容:

<Button ToolTip="This tooltip is alined with the bottom edge" ToolTipService.Placement="Bottom">I have a tooltip</Button>
View Code

ToolTipService類還提供了兩個路由事件:ToolTipOpening和ToolTipClosing。可以響應這些事件使用即使內容填充工具提示,或重寫工具提示的工作方式。下面是ToolTipService類的屬性:

InitialShowDelay 設置當鼠標懸停在元素上時,工具提示顯示之前的延遲時間
ShowDuration 設置如果用戶不移動鼠標,在工具提示消失之前顯示的時間
BetweenShowDelay 設置一個時間間隔,在該期間用戶可以在工具提示之間移動而不用經歷InitialShowDelay屬性設置的延遲時間。
ToolTip 為工具提示設置內容。設置ToolTipService.ToolTip屬性相當於設置元素的FrameworkElement.ToolTip屬性
HasDropShadow 確定工具提示是否具有擴散的黑色陰影,從而使其與背后的窗口相互區別
ShowOnDisabled 確定當相關聯的元素被禁用后是否顯示工具提示。如果該屬性為true,將為禁用的元素顯示工具提示。默認為false。
Placement、PlacementTarget、PlacementRectangle以及VerticalOffset 這些屬性用於控制工具提示的位置,用法與ToolTip屬性一樣

Popup控件——Popup也只能包含單一內容,該單一內容可以包含任何WPF元素。另外,和ToolTip控件一樣,Popup控件也可以延伸出窗口的邊界,可以使用相同的布局屬性放置Popup控件,並且可以使用相同的IsOpen屬性顯示或隱藏Popup控件。Popup控件和ToolTop控件之間的區別更重要,下面是他們的區別:

  • Popup控件永遠不會自動顯示。為了顯示Popup控件必須設置IsOpen屬性。
  • 默認情況下,Popup.StaysOpen水洗那個被設置為true,並且Popup控件會一直顯示,直到明確的將IsOpen屬性設置為false為止。如果Popup.StaysOpen屬性設置為false,當用戶在其他地方單機鼠標時,Popup控件就會消失。
  • Popup控件提供了一個PopupAnimation屬性,當把IsOpen屬性設置為true時,通過該屬性可以控制Popup控件進入視野的方式。None是默認方式,Fade是彈出窗口的透明度逐漸增加,Scroll是在足夠的空間內,彈出窗口將從窗口的左上角滑入,Slide在足夠的空間內,彈出窗口將從上向下滑進其位置。為了使用這些動畫,還要將AllowsTransparency屬性設置為true。
  • Popup控件可以接收焦點。因此可以在其內部放置與用戶交互的控件;該功能是使用Popup控件的主要原因。
  • Popup控件在System.Windows.Controls.Primitive名稱空間中定義的,因為它的最常見用法是用作更復雜控件的構建。在外觀修飾方面可以發現Popup控件和其他控件的區別。如果希望看到內容,必須設置Background屬性,因為Popup控件不會從包含它的窗口繼承背景設置,並且需要自己添加邊框。

因為必須手動顯示Popup控件,所以您可能會完全通過代碼創建它,也可以用XAML標記定義Popup控件——但要確保包含Name屬性,從而可以使用代碼操縱該控件。如下示例:

//XAML部分
<TextBlock TextWrapping="Wrap">You can use a Popup to provide a link for
      a specific <Run TextDecorations="Underline"  
        MouseEnter="run_MouseEnter" 
                      >term</Run> of interest.</TextBlock>
      <Popup Name="popLink" StaysOpen="False" Placement="Mouse" MaxWidth="200"
             PopupAnimation="Slide" AllowsTransparency = "True">
        <Border BorderBrush="Beige" BorderThickness="2" Background="White">
          <TextBlock Margin="10"  TextWrapping="Wrap" >
            For more information, see
            <Hyperlink NavigateUri="http://en.wikipedia.org/wiki/Term" Click="lnk_Click">Wikipedia</Hyperlink>


          </TextBlock>
        </Border>
      </Popup>
//代碼部分
        private void run_MouseEnter(object sender, MouseEventArgs e)
        {
            popLink.IsOpen = true;
        }
        private void lnk_Click(object sender, RoutedEventArgs e)
        {
            Process.Start(((Hyperlink)sender).NavigateUri.ToString());
        }
View Code

6.3 特殊容器控件

  ScrollViewer控件——如果希望讓大量的內容適應有限的空間,滾動是一個重要特性。在WPF中為了獲得活動支持,需要在ScrollViewer控件中包裝希望滾動的內容。盡管ScrollViewer控件可以包含任何內容,但是通常使用它包含一個布局容器。如下示例:

  <ScrollViewer Name="scroller">

    <Grid Margin="0,10,0,0" Focusable="False">
      <Grid.RowDefinitions>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
        <RowDefinition Height="Auto"></RowDefinition>
      </Grid.RowDefinitions>
      <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
        <ColumnDefinition Width="*" MinWidth="50" MaxWidth="800"></ColumnDefinition>
        <ColumnDefinition Width="Auto"></ColumnDefinition>
      </Grid.ColumnDefinitions>

      <Label Grid.Row="0" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Home:</Label>
      <TextBox Grid.Row="0" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="0" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="1" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Network:</Label>
      <TextBox Grid.Row="1" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="1" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="2" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Web:</Label>
      <TextBox Grid.Row="2" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="2" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="3" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Secondary:</Label>
      <TextBox Grid.Row="3" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="3" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="4" Grid.Column="0" Margin="3"
       VerticalAlignment="Center">Home:</Label>
      <TextBox Grid.Row="4" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="4" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="5" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Network:</Label>
      <TextBox Grid.Row="5" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="5" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="6" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Web:</Label>
      <TextBox Grid.Row="6" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="6" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

      <Label Grid.Row="7" Grid.Column="0" Margin="3"
             VerticalAlignment="Center">Secondary:</Label>
      <TextBox Grid.Row="7" Grid.Column="1" Margin="3"
             Height="Auto"  VerticalAlignment="Center"></TextBox>
      <Button Grid.Row="7" Grid.Column="2" Margin="3" Padding="2">Browse</Button>

    </Grid>
    
  </ScrollViewer>
View Code

ScrollViewer控件的VerticalScrollBarVisbility屬性控制滾動條的顯示方式,如:當窗口不足以顯示所有內容時,顯示滾動條,當窗口足夠顯示內容時消失,就把VerticalScrollBarVisbility屬性設置為Auto;Visible是總是顯示滾動條;Disable是不顯示滾動條。ScrollViewer控件也支持水平滾動條,但默認是垂直方向,我們可以把HorizontalScrollBarVisibility屬性設置為Auto,默認是Hidden。

  代碼滾動——我們除了用鼠標滾動ScrollViewer控件外,還可以用代碼的方式進行操作,LineUp()和LineDown(),這兩個方法向上和向下移動的效果相當於單擊一次垂直滾動條兩端的箭頭按鈕。PageUp()和PageDown()方法是向上和向下滾動一屏。用於水平滾動的方法是LineLeft、LineRight、PageLeft()、PageRight()。還有ScrollToXxx()一類的方法,以滾動到特定的位置。對於垂直滾動,包括ScrollToEnd()和ScrollToHome(),這兩個方法可以滾動到內容的頂部和底部。還有ScrollToVerticalOffset,該方法可以滾動到特定的位置。對於水平滾動類似的方法有ScrollToLeftEnd()、ScrollToRightEnd()、ScrollToHorizontalOffset()。

  自定義滾動——ScrollViewer控件內置的滾動功能是很有用的。該功能允許慢慢地滾動任何內容,從復雜的矢量圖形乃至元素網格。ScrollViewer控件最奇特的特征是它允許所包含的內哦內容參與滾動過程。

  • 在ScrollViewer控件中放置一個能夠滾動的元素。可以是任何實現了IScrollInfo接口的任意元素。
  • 通過將ScrollViewer.CanContentScroll屬性設置為true,告訴ScrollViewer控件其內容知道如何進行滾動。
  • 當和ScrollViewer控件進行交互時,ScrollViewer控件通過IScrollInfo接口來調用元素的恰當方法。然后元素執行它自己的自定義滾動功能。
  <ScrollViewer CanContentScroll="True">
  <StackPanel >
    <Button Height="100">1</Button>
    <Button Height="100">2</Button>
    <Button Height="100">3</Button>
    <Button Height="100">4</Button>
  </StackPanel>
  </ScrollViewer>
View Code

6.4 帶標題的內容控件

  HeaderedContentControl類是也是一個繼承自ContentControl的類。他的角色很簡單——表示同時具有單一元素內容和單一元素標題的容器。添加的標題正是HeaderedContentControl類和到目前為止介紹的內容控件的區別。有三個類繼承自HeaderedContentControl類:GroupBox、TabItem和Expander。

6.4.1 GroupBox

  GroupBox顯示為一個具有圓角和標題的方框。如下示例:

        <GroupBox Header="A GroupBox Test" Padding="5" Margin="5" VerticalAlignment="Top">
            <StackPanel>
                <RadioButton Margin="3" Content="One" />
                <RadioButton Margin="3" Content="Two" />
                <RadioButton Margin="3" Content="Three" />
                <Button Margin="3">Save</Button>
            </StackPanel>
        </GroupBox>
View Code

GroupBox仍然需要布局容器來布置內容。GroupBox控件經常用來對數量不多的相關控件進行分組。GroupBox控件沒有提供內置功能,所以可以隨意使用它。

6.4.2 TabItem

  TabItem表示TabControl控件中的一頁。TabItem類添加的唯一一個有意義的屬性是IsSelected,該屬性指示選項卡當前是否正顯示在TabControl控件中。如下是一個簡單示例:

        <TabControl Margin="5">
            <TabItem Header="Tab One">
                <StackPanel Margin="3">
                    <CheckBox Margin="3">Setting One</CheckBox>
                    <CheckBox Margin="3">Setting Two</CheckBox>
                    <CheckBox Margin="3">Setting Three</CheckBox>
                </StackPanel>
            </TabItem>
            <TabItem Header="Tab Two">
                
            </TabItem>
        </TabControl>
View Code

與Content屬性一樣,Header屬性也可以接受任何類型的對象。繼承自UIElement的類通過渲染來顯示,對於內聯文本以及其他所有對象則使用ToString()方法。這意味着可以創建一個組合或選項卡,在它們的標題中包含圖形內容或任意元素。如下:

TabItem>
      <TabItem.Header>
        <StackPanel>
        <TextBlock Margin="3" >Image and Text Tab Title</TextBlock>
        <Image Source="happyface.jpg" Stretch="None" />        
        </StackPanel>
      </TabItem.Header>
      <StackPanel Margin="3">
        <CheckBox Margin="3">Setting One</CheckBox>
        <CheckBox Margin="3">Setting Two</CheckBox>
        <CheckBox Margin="3">Setting Three</CheckBox>
      </StackPanel>
    </TabItem>
View Code

6.4.3 Expander

  Expander控件,他包裝了一塊內容,通過單擊一個小箭頭按鈕可以顯示或隱藏所包含的內容。使用Expander控件非常簡單,只需要在該控件內部包裝希望使其能夠折疊的內容。通常每個Expander控件開始都是折疊的,但是可以在標記中通過設置IsExpanded屬性來改變這種行為。如下示例:

  <StackPanel>
 
  <Expander Margin="5" Padding="5" Header="Region One"
            BorderThickness="1" BorderBrush="Black">
    <Button Padding="3">Hidden Button One</Button>
  </Expander>
  <Expander Margin="5" Padding="5" Header="Region Two" 
            BorderThickness="1" BorderBrush="Black">
      <TextBlock TextWrapping="Wrap">
        Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Nam mi sapien, viverra et, lacinia varius, ullamcorper sed, sapien. Proin rutrum arcu vitae tellus. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Pellentesque libero dui, eleifend faucibus, auctor at, aliquet a, nulla. Nunc eros. Phasellus mauris nisi, eleifend nec, adipiscing nec, luctus nec, lacus. Aliquam justo metus, vestibulum non, accumsan id, hendrerit at, nibh. Praesent accumsan urna quis tortor. Proin erat libero, facilisis nec, rhoncus ut, malesuada ut, ipsum. Donec id nibh.
      </TextBlock>
    </Expander>
    <Expander Margin="5" Padding="5" Header="Region Three" IsExpanded="True"
              BorderThickness="1" BorderBrush="Black">
      <Button Padding="3">Hidden Button Two</Button>
    </Expander>
</StackPanel>
View Code

我們還可以選擇擴展器的擴展方向。標准方向是Down,但是也可以將ExpandDirection屬性設置為Up、Left或Right,箭頭總是指向將要展開的方向。

  通常,當展開一個Expander時,它會增大以適應所包含的內容。當所有內容都展開后,如果窗口不足以顯示所有內容,這可能帶來問題。下面是處理問題的幾種方法:

  • 為窗口設置最小尺寸(使用MinWidth和MinHeight屬性),以確保窗口在最小時也可以適合所有內容。
  • 設置窗口的SizeToContent屬性,從而當打開或關閉Expander控件時,使窗口自動擴展為所需要的大小。通常將SizeToContent屬性設置為Manual,但是也可以使用Width或Height,以使窗口為了適應所包含的內容在任意方向上擴展或收縮。
  • 通過硬編碼Expander控件的Height和Width屬性來限制其尺寸。但當Expander控件中的內容太長時,可能會裁剪掉部分內容。
  • 使用ScrollViewer控件創建一個可滾動的擴展區域。

6.5 文本控件

  WPF提供了三個用於輸入文本的控件:TextBox、RichTextBox和PasswordBox。PasswordBox控件直接繼承自Control類。TextBox和RichTextBox控件間接繼承自TextBoxBase類。文本框能夠包含的內容類型是有限制的。TextBox控件總是存儲字符串。PasswordBox控件也處理字符串內容(由Password屬性提供),盡管為了減輕特定類型的攻擊,它在內部使用SecureString屬性。只有RichTextBox控件可以存儲更復雜的內容:可以包含復雜元素組合的FlowDocument對象。

6.5.1 多行文本

  通常,TextBox控件存儲單行文本(可以通過設置MaxLength屬性來限制字符的數量)。然而,去多情況下需要處理大量內容,從而會希望創建多行文本框。可以將TextWrapping屬性設置為Wrap或WrapWithOverflow。如果將TextWrapping屬性設置為Wrap,總會在控件的邊緣換行,甚至會將一個特別長的單詞放置在兩行中。如果將TextWrapping屬性設置為WrapWithOverflow,這時如果換行算法發沒發現合適的位置進行換行,WrapWithOverflow就允許拉伸某些行超出邊緣。為了能夠自動在文本框中看到更多行文本,需要將尺寸設置得足夠大。不應該設置一個硬編碼的高度,而可以使用方便的MinLines和MaxLines屬性。通過設置VerticalScrollBarVisibility屬性設置為Visible或Auto,添加始終顯示或按需顯示的滾動條是有意義的。為了確保文本框支持Enter鍵,需要將AcceptsRuturn屬性設置為true,也可以設置AcceptsTabs屬性,從而允許用戶插入Tab鍵,否則,Tab鍵會根據Tab焦點順序將焦點移動到下一個可以得到焦點的控件上。IsReadOnly 屬性設置是否可以編輯文本,IsEnabled屬性設置是否禁用文本框。

6.5.2 選擇文本

  TextBox類還提供了使用SelectionStart、SelectionLength以及SelectedText屬性,通過編程決定選擇哪些文本或改變當前所選文本的能力。SelectionStart屬性標識所選文本的開始位置,該位置是從0開始的。SelectionLength屬性指示選中的字符的總數量。使用SelectedText屬性可以快速檢查或改變在文本框中選中的文本。可以通過處理SelectionChanged事件對文本選擇變化做出響應。TextBox類還提供了一個可以控制文本選擇行為的屬性:AutoWordSelection。如果將該屬性設為true,當在文本中拖動鼠標時文本框每次會選擇整個單詞。TextBox控件的另一個功能是UNDO,該功能允許用戶撤銷最近的操作。只要CanUndo屬性沒有設置為false,就可以通過代碼獲得Undo功能(調用Undo()方法),並且可以使用Ctlr+Z快捷鍵獲得該功能。

6.5.3 拼寫檢查

  TextBox的拼寫檢查功能會在文本中不能識別的單詞下面添加紅色的波浪線。用戶可以右擊不能識別的單詞並從可能正確的單詞列表中進行選擇。要為TextBox控件開啟拼寫檢查,只需要簡單的設置SpellCheck.IsEnabled依賴項屬性。如下:

<TextBox SpellCheck.IsEnbled="True">...</TextBox>

拼寫檢查是WPF特有的功能,並且該功能不依賴於其他軟件。拼寫檢查根據為鍵盤配置的輸入語言來決定使用哪個詞典。WPF拼寫檢查目前只局限於:英語、西班牙語、法語和德語。

6.5.4 PasswordBox

  PasswordBox通過顯示一個圓圈符號字來屏蔽它的實際字符(可以設置PasswordChar屬性改變隱藏字符)。PasswordBox不支持剪貼板,從而不能復制文本。PasswordBox控件提供了MaxLength屬性;Clear()、Paste()以及SelectAll()方法;並且提供了一個當文本發生變化時觸發的事件PasswordChanged事件。盡管可以使用password屬性作為普通字符串讀取和設置文本,但是在內部PasswordBox類只使用System.Security.SecureString對象。SecureString對象是一個純文本對象。區別是在內存中的存儲方式。SecureString已加密的方式在內存中保存。用於加密字符串的密鑰是隨機生成的,並且存儲在一塊從不會寫入到磁盤的內存中。SecureString類還提供了根據需要丟棄內容的功能。當調用SecureString.Dispose()方法時,內存中的密碼數據就會被重寫。

6.6 列表控件

  WPF提供了許多包裝項目集合的控件,包括在本節介紹的ListBox和ComboBox控件以及更特殊的控件,例如:ListView、TreeView和ToolBar控件,這些控件將在以后介紹。所有的這些控件都繼承自ItemsControl類(ItemsControl類本身又繼承自Control類)。ItemsControl類添加了所有基於列表的控件都是用的基本功能。它提供了填充列表項的兩種方式。最直接的方法是使用代碼或XAML將列表直接添加到Items集合中。WPF中使用數據綁定的方式更為普遍。使用數據綁定方法,需要將ItemsSource屬性設置為希望顯示的具有數據項集合的對象。ItemsControl類之后的繼承層次有些混亂。一個主要分支是選擇器(selector),包括ListBox、ComboBox以及TabControl。這些控件都繼承自Selector類,並且都具有跟蹤當前選擇項(SelectedItem)或其位置(SelectedIndex)的屬性。包裝列表項的控件是另一個分支,以不同的方式選擇列表項。該分支包括用於菜單、工具欄以及樹的類——所有這些類都屬於ItemsControl但不是選擇器。

6.6.1 ListBox

  ListBox類代表了一種最常用的Windows設計——允許用戶從長度可變的列表中選擇一項。為向ListBox控件中添加項,可在ListBox元素中嵌套ListBoxItem元素。如下:

<ListBox>
    <ListBoxItem>Green</ListBoxItem>
    <ListBoxItem>Red</ListBoxItem>
    <ListBoxItem>Yellow</ListBoxItem>
    <ListBoxItem>Blue</ListBoxItem>
</ListBox>
View Code

ListBox控件不僅可以包含ListBoxItem對象,還可以嵌套其他任意元素。因為ListBoxItem類繼承自ContentControl類,從而ListBoxItem能夠包含一段嵌套的內容。而且ListBox控件足夠智能,它能夠隱式的創建所需的ListBoxItem對象。這意味着可以直接在ListBox元素中放置對象。如下:

  <ListBox Margin="5" SelectionMode="Multiple" Name="lst"  SelectionChanged="lst_SelectionChanged">
    <StackPanel Orientation="Horizontal">
      <Image Source="happyface.jpg"  Width="30" Height="30"></Image>
      <Label VerticalContentAlignment="Center">A happy face</Label>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
      <Image Source="redx.jpg" Width="30" Height="30"></Image>
      <Label VerticalContentAlignment="Center">A warning sign</Label>
    </StackPanel>
    <StackPanel Orientation="Horizontal">
      <Image Source="happyface.jpg"  Width="30" Height="30"></Image>
      <Label VerticalContentAlignment="Center">A happy face</Label>
    </StackPanel>
  </ListBox>
View Code

當在一個列表內部使用不同的元素時需要謹慎。當讀取SelectedItem值時(以及SelectedIems和Items集合),看不到ListBoxItem對象——反而將看到放入到列表中的對象。下面的CheckedListBox示例:

//XAML部分
    <ListBox Name="lst" SelectionChanged="lst_SelectionChanged"
             CheckBox.Click="lst_SelectionChanged" >
      <CheckBox Margin="3">Option 1</CheckBox>
      <CheckBox Margin="3">Option 2</CheckBox>
      <CheckBox Margin="3">Option 3</CheckBox>
    </ListBox>
    <StackPanel Grid.Row="1" Margin="0,10,0,0">
      <TextBlock>Current selection: </TextBlock>
      <TextBlock  Name="txtSelection" TextWrapping="Wrap"></TextBlock>
      <Button Margin="0,10,0,0" Click="cmd_CheckAllItems">Examine All Items</Button>
    </StackPanel>
//代碼部分
        private void lst_SelectionChanged(object sender, RoutedEventArgs e)
        {
           
            if (e.OriginalSource is CheckBox)
            {
                lst.SelectedItem = e.OriginalSource;
            }
            
            if (lst.SelectedItem == null) return;
            txtSelection.Text = String.Format(                
                "You chose item at position {0}.\r\nChecked state is {1}.",
                lst.SelectedIndex,
                ((CheckBox)lst.SelectedItem).IsChecked);
        }

        private void cmd_CheckAllItems(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (CheckBox item in lst.Items)
            {
                if (item.IsChecked == true)
                {
                    sb.Append(
                        item.Content + " is checked.");
                    sb.Append("\r\n");                      
                }
            }
            txtSelection.Text = sb.ToString();
        }
View Code

6.6.2 ComboBox

  ComboBox控件和ListBox控件類似。該控件包含一個ComboBox對象的集合,即可顯式的也可以隱式的創建該集合。與ListBoxItem類似,ComboBoxItem也是一個可以包含任何嵌套元素的內容控件。ComboBox控件使用下拉列表,一次只能選一個項目。如果希望用戶在組合框中通過輸入文本選擇一個項目,必須將IsEditable屬性設置為true,並且必須確保項目集合中存儲的是普通的純文本的ComboBoxItem對象,或者是提供了有意義的ToString()表示的對象。

6.7 基於范圍的控件

  WPF提供了三個使用范圍概念的控件,這些控件使用一個在特定最小值和最大值之間的數值。這些控件——ScrollBar、 ProgressBar以及Slider都繼承自RangeBase類(該類繼承自Control類)。盡管它們使用相同的抽象概念,但是它們的工作方式卻有很大的區別。RangeBase類定義的屬性如下:

Value 控件的當前值(必須在最大值和最小值之間)。默認從0開始。Value屬性值不是整數——而是雙精度浮點數,所以它接受小數值。如果當Value屬性值發生變化時希望得到通知,可以響應ValueChanged事件
Maximum 上限
Minimum 下限
SmallChange Value屬性為"小變化"向上或向下調整的數量。小變化的含義和控件相關(而且有的控件可能根本不使用小變化)。對於ScrollBar和Slider控件,這是當使用箭頭鍵時值改變的量,對於ScrollBar控件還可以使用滾動條兩端的箭頭按鈕。
LargeChange Value屬性為"大變化"向上或向下調整的數量。大變化的含義和控件相關(而且有的控件可能根本不適用大變化)。對於ScrollBar和Slider控件,這是使用PageUp和PageDown鍵或單擊滑塊兩側時值改變的量

通常,不需要直接使用ScrollBar控件。高級的ScrollViewer控件(包裝了兩個ScrollBar控件)通常更有用。Slider和ProgressBar控件更實用,並且經常單獨使用。

6.7.1 Slider控件

  Slider控件是偶爾使用的特殊控件——例如,當數字本身不是特別重要時可以使用該控件設置數值。再比如,播放器的音量調節。Slider控件的重要屬性是在RangeBase類中定義的。除了這些屬性,還可以使用如下屬性:

Orientation 在豎直滑動和水平滑動條之間切換
Delay和Interval 當單擊並按下滑動條的兩側時,控制滑塊沿軌跡移動的速度。這兩個屬性都是毫秒值。Delay是單擊后在滑塊移動一個單位之前的時間,而Interval是如果繼續保持鼠標按下狀態滑塊再次移動之前的時間。
TickPlacement 決定刻度顯示的位置(刻度是在滑動條附近用於幫助觀察數值的刻痕記號),默認情況下,TickPlacement屬性被設置為None,並且不顯示刻度表計。如果是水平滑動條,可以在上面放置刻度標記(TopLeft)或在下面放置刻度標記(BottomRight)。對於豎直滑動條,可以在左邊(TopLeft)和右邊(BottomRight)放置刻度標記(TickPlacement的名稱有些令人迷惑,因為根據滑動條的方向兩個值包含了4中可能)
TickFrequency 設置刻度之間的間隔,他決定了顯示多少刻度。例如每隔5個單位放置一個刻度
Ticks 如果希望在特定的不規則的位置放置刻度,可以使用Ticks集合。簡單的為每個刻度標記向該集合添加一個數值(雙精度浮點數)。例如可以通過添加相應的數值,在1、1.5、2和10刻度位置放置一個刻度記號
IsSnapToTickEnabled 如果該屬性為true,當移動滑動條時,會自動跳轉到合適的位置——最近的刻度標記,默認值是false
IsSelectionRangeEnabled 如果為true,可以使用一個選擇范圍使滑動條的一部分顯示陰影。使用SelectionStart和SelectionEnd屬性設置位置選擇范圍。選擇范圍沒有嚴格的含義,但是可以為任何有意義的目的的使用它。例如:播放器有時使用陰影北京工具條指示媒體文件的下載進度
<StackPanel Margin="10">
        <TextBlock Margin="0,0,0,5">Normal Slider (Max=100, Val=10)</TextBlock>
        <Slider Maximum="100" Value="10"></Slider>
        <TextBlock Margin="0,15,0,5">Slider with Tick Marks (TickFrequency=10, TickPlacement=BottomRight)</TextBlock>
        <Slider Maximum="100" Value="10" TickFrequency="10" TickPlacement="BottomRight"></Slider>
        <TextBlock Margin="0,15,0,5">Slider with Irregular Tick Marks (Ticks=0,5,10,15,25,50,100)</TextBlock>
        <Slider Maximum="100" Value="10" Ticks="0,5,10,15,25,50,100"  TickPlacement="BottomRight"></Slider>
        <TextBlock Margin="0,15,0,5" TextWrapping="Wrap">Slider with a Selection Range (IsSelectionRangeEnabled=True, SelectionStart=25, SelectionEnd=75)</TextBlock>
        <Slider Maximum="100" Value="10" TickFrequency="10" TickPlacement="BottomRight"
                IsSelectionRangeEnabled="True" SelectionStart="25" SelectionEnd="75"></Slider>
      </StackPanel>
View Code

6.7.2 進度條

  進度條用於指示一個長時間運行任務的進度。與滑動條控件不同,ProgressBar控件不能和用戶進行交互。反而,需要由代碼遞增Value屬性值。ProgressBar控件具有4個設備無關單位的最小高度。如果希望看到一個更大、更傳統的進度條,需要設置Height屬性(或將它放入具有適當固定尺寸的容器中)。使用ProgressBar控件的通常方式是將它作為一個長時間運行狀態的指示器,甚至可能不知道該任務需要執行多長時間。可以通過將IsIndeterminate屬性設置為true來完成這一工作。

<ProgressBar Height="18" Width="200" IsIndeterminate="true"></ProgressBar>

當設置IsIndeterminate屬性時,不再使用Minimum、Maximum以及Value屬性。ProgressBar控件會周期性地顯示從左向右的綠色脈沖,這是通用的Windows約定,表示正在工作當中。

6.8 日期控件

  WPF4添加了兩個日期控件:Calendar和DatePicker。這兩個控件都允許用戶選擇一個日期。Calendar控件顯示一個日歷,與在Windows操作系統中看到的日歷很相似。該控件每次顯示一個月份,並且允許從一個月份跳刀另一個月份,或跳到一個特定的月份DatePicker控件需要更少的空間。他模仿簡單的文本控件,該文本框以長日期格式或短日期格式保存一個日期字符串。DatePicker控件提供了一個下拉箭頭,當單擊時,會彈出一個完整的日歷視圖,該視圖和Calendar控件顯示的視圖相同。Calendar和DatePicker控件提供的屬性,允許你確定顯示哪些日期以及哪些日期是能夠選擇的。可使用的屬性如下:

 DisplayDateStart和DisplayDateEnd  設置在日歷視圖中顯示的日期范圍,從第一個最早的日期(DisplayDateStart)到最后最近的日期(DisplayDateEnd)。用戶不能導航到沒有包含能夠顯示的日期的月份。為了顯示所有日期,可以將DisplayDateStart屬性設置為DateTime.MinValue,並將DisplayDateEnd屬性設置為DateTime.MaxValue。
BackouttDates  保存在日歷中將被禁用或不能選擇的日期集合。如果這些日期不在可以顯示的日期范圍內,或者如果已經選擇了這些日期中的某個日期,將接收到一個異常。為了阻止選擇任何過去的日期,可以調用BlackoutDates.AddDatesInPast()方法。 
SelectedDate  作為一個DateTime對象提供選擇的日期(或者沒有日期被選中時使用null值)。可以通過代碼、通過單擊日歷中的日期、或通過用戶鍵入一個日期字符串(在DatePicker控件中)設置該屬性。在日歷視圖中,選擇的日期使用一個 具有陰影的方框標識,只有當日期控件具有焦點時才會顯示該方框。
SelectedDates  作為DateTime對象的集合提供選擇的日期。Calendar控件支持該屬性,並且只有當修改了SelectionMode屬性,以允許選擇多個日期時,該屬性才有用。 
DisplayDate  確定在日歷視圖中最初顯示的日期。如果該屬性為空,顯示SelectedDate屬性的值。如果DisplayDate和SelectedDate屬性均為空,使用當前日期。顯示的日期決定了日歷視圖中最初的月份頁面。當日期控件具有焦點時,在該月份中恰當的某天周圍顯示一個方形邊框 
FirstDayOfWeek  確定在日歷中每行的開始位置(最左邊的位置)顯示一星期中的哪一天 
IsTodayHightlighted  確定日歷視圖是否通過突出顯示指出當前日期 
DisplayMode(只用於Calendar控件)  確定日歷最初的月份顯示模式。如果將該該屬性設置為Month,Calendar控件顯示標准的單一月份視圖。如果設置為Year,Calendar控件顯示當前年份中的月份(與當用戶單擊月份題頭時顯示的內容類似)。一旦用戶單擊了一個月份,Calendar控件就會顯示該月份的完整日歷視圖 
SelectionMode(只用於Calendar控件)  確定允許的日期選擇類型。默認值是SingleDate,該設置允許選擇單個日期。其它選項包括None(完全禁止選擇日期)、SingRange(可以選擇一組聯系的日期)以及MultipleRange(可以選擇任意日期組合)。在SingRange和MultipleRange模式下,用戶可以拖動選擇多個日期,或當按下Ctrl鍵時通過單擊選擇多個日期可以使用SelectedDates屬性獲取包含所有選擇日期的集合。 
IsDropDownOpen(只用於DatePicker控件)  確定是否打開DatePicker控件中的下拉日歷視圖。可以通過代碼設置該屬性以顯示或隱藏日歷 
SelectedDateFormat(只用於DatePicker控件)  確定在DatePicker控件的文本部分顯示選擇的日期的方式。可以選擇Short或Long。實際的顯示格式取決於客戶計算機的區域設置。例如,如果使用Short,可能以yyyy/mm/dd格式或dd/mm/yyyy格式顯示日期。長日期通常包含月份和天的名稱。 

日期控件還提供了幾個不同的事件。最有用的事件是(DatePicker中的)SelectedDateChanged,或(Calendar控件)類似的SelectedDatesChanged,該事件添加了多個日期選擇的支持。可以響應這些事件已拒絕特定的日期選擇,例如周末的日期:

        private void Calendar_SelectedDatesChanged(object sender, SelectionChangedEventArgs e)
        {
            // Check all the newly added items.
            foreach (DateTime selectedDate in e.AddedItems)
            {
                if ((selectedDate.DayOfWeek == DayOfWeek.Saturday) ||
                    (selectedDate.DayOfWeek == DayOfWeek.Sunday))
                {
                    lblError.Text = "Weekends are not allowed";

                    ((Calendar)sender).SelectedDates.Remove(selectedDate);
                }
            }

        }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM