1. 程式人生 > 實用技巧 >WPF 的內部世界(控制元件與佈局)

WPF 的內部世界(控制元件與佈局)

目錄

一、控制元件與佈局

前言

為什麼要寫WPF呢?

我一開始算是比較牴觸WPF的,因為用的人少嗎。感覺都是窗體應用能和Winform有什麼區別。可是我錯了,非常感謝我的講師,給我推薦劉鐵猛的《深入淺出WPF》,讓我瞭解到了WPF的魅力——資料驅動UI 。

所以,這麼優秀的框架,我想寫下來,都知道WPF開發人員非常少,以至於大部分教程視訊都是10年前的。我記錄下來,不是為了什麼,是真的喜歡WPF,那種“怪誕不經”的感覺。

一、UI佈局

俗話說:“人靠衣裝馬靠鞍”

什麼意思呢?意思是人穿上一身得體的衣服,就會顯得分外精神;馬備上一副講究的鞍韉,就會顯得特別駿美。指衣服對人體的形象美有極大的影響。出自《薛仁貴徵爾》

那麼,我們把這句話引入到WPF中

  • WPF作為專門的使用者介面技術,佈局的功能是它的核心功能之一。友好的使用者介面和良好的使用者體驗離不開設計精良的佈局。
  • WPF設計師工作量最大的倆部分就是佈局和動畫,佈局是靜態的,動畫是動態的,使用者體驗就是用 戶在這動靜之中與軟體功能產生互動時的感受。
  • 也就是說,佈局就是WPF的衣服!

二、控制元件

"我老生涯鷗水相依,他舊風流鴻塞荒投。”

意思是野生動物和野生環境鷗水相依,不可分離

那麼到WPF中呢? 一個頁面的佈局,顯示。都是由一個個控制元件組成的。控制元件們離不開WPF這個賴以生存的環境,組成了一幅幅美麗生動的畫面(佈局)。

在開始學習這些佈局元素前,我們要知道每個佈局元素都有自己的特點,我們要靈活使用。切莫不要無所不用其極,要合理搭配。

(就像生態環境一樣,要合理搭配,否則就會出現“生物入侵”這種“偷雞不成蝕把米”的行為,加重了生態環境的負擔。破壞)

1、 控制元件的分類

粗略而言,日常工作中我們打交道最多的控制元件無外乎6類,即:

  • 1、佈局控制元件:可以容納多個控制元件或巢狀其他佈局控制元件,用於UI上組織和排列控制元件,如:StackPanel,Grid,Dock,WrapPanel,,Canvas;
  • 2、內容控制元件:只能容納一個其他控制元件或佈局控制元件作為它的內容,如:Button,Window;
  • 3、帶標題的內容控制元件:相當於一個內容控制元件,但可以加一個標題,如:Group Box,TabItem;
  • 4、條目控制元件:可以顯示一列資料,一般情況下這列資料的型別相同。如ListBox,ComboBox;
  • 5、帶標題的條目控制元件:相當於給一個條目控制元件加上一個標題顯示區,如:TreeViewItem,MenuItem,往往用於顯示層級資料;
  • 6、特殊的內容控制元件:比如TextBox容納的是字串,TeztBlock可以容納可自由控制格式的文字,Image容納圖片型別資料……這類的控制元件相對比較獨立。

至於,為什麼這麼分類呢,其實我們只需要細細體會一下,就明白了。實在不行,你從工具欄拖出來,看著它的樣子,在看著我的話。“什麼?你還不懂”………………………………作者卒

好,我們不對這些控制元件做太多詳細介紹,我們主要介紹佈局控制元件,其他相信屬性可以參考下面:
WPF 基本控制元件使用介紹:https://blog.csdn.net/niewq/article/details/50244227

三、佈局控制元件

好了,終於來到我們的重點了。 WPF為我們提供了5中佈局方式,他們的特點各不相同,可以相互巢狀,讓我們來認識一下吧。

  • 1、Grid :列表佈局
  • 2、StackPanel :堆疊面板佈局
  • 3、WrapPanel : 流佈局面板(當元素水平對齊,內容超過寬度時,自動換行;當元素垂直對齊,內容超過高度時,自動換列)
  • 4、DockPanel:停靠面板
  • 5、Canvas:座標面板

1、Grid列表佈局

Grid一詞譯為“網格;格子,柵格”
沒錯,它就像一個網格一樣把我們的頁面分割成一塊又一塊。


我們在窗體放置了2個TextBlock和2個TextBox,想實現登入視窗的樣式,可是不進人意,他們都重疊在了一起。

為什麼都重疊在了一起呢?

因為,我們沒有對Grid這個容器做相關調整,他現在是一個一行一列的“大格子”。在一個各自當然就重疊了,除非去設定Magin屬性,當然我們想要實現的並不是這種效果。

所以,我們通過設定

  • 列<Grid.ColumnDefinitions></Grid.ColumnDefinitions>
  • 行<Grid.RowDefinitions></Grid.RowDefinitions>

“分割Grid”

我們可以通過新增ColumnDefinitions節點和RowDefinitions節點 ,來確定把我們的“Grid分割成幾個格子”。

如圖,分割成了四個格子:

通過看設計視窗,我們也會發現,Grid被線條分割成了四塊:

唉?不對啊,為什麼我們的控制元件還重疊的呢?是因為我們沒有去設定他們處於哪個格子,接下載,我們設定一下。

確定位置,與合併單元格

當我們的容器處於Grid佈局容器裡時,會增加附加屬性:

  • 行所在位置: Grid.Row="0"
  • 列所在位置: Grid.Column="0"

預設不設定,值為0 ,所以才會出現重疊的情況,來我們調整一下位置。

好了,一切恢復正常了,在增加一個按鈕,登入怎麼能沒有按鈕呢!

通過設定

  • 行單元格合併: Grid.RowSpan="1"
  • 列單元格合併: Grid.ColumnSpan="1"

預設值位1,合併幾個就寫幾。
經過稍作修改,我們的介面變成了這樣:

額……長得有點醜,我們新增些屬性來調整一下,

設定寬高

我們通過對ColumnDefinition的Width來設定寬和RowDefinition的Height來設定高

Width和Height支援畫素,比例,以及自適應

  • 畫素: 直接用數字表示即可
  • 比例: 以*做單位
  • 自適應: 設定值位 auto

好,我們來運用上面的知識,調整一下我們的檢視:

總結

好,我們來總結一下上面的寬高:

  • 首先我們對Grid的列經行了比例設定1:3(*,3*),當我們拉動窗體大小時,會發現它們的大小是等比例變化的。
  • 其次,對Grid的行設定了倆個固定高度,我們可以發現無論窗體怎麼變化他們的高度是不變的。
  • 最後一行設定了自適應,我刻意把按鈕的高度設為100,我們可以看到表格最後一行也為100,可以知道auto是根據內容來自適應的。

2、StackPanel堆疊面板

大家都對“堆疊”倆個詞不陌生吧,堆疊面板就好像容器在“排隊”一樣,我們把Window下的Grid 換位StackPanel,來體驗一下吧。

設定方向


我們在StackPanel裡放置了很多按鈕,發現他們就像排隊一樣,一個接一個,水平方向。如果你不喜歡這樣,當然是可以改方向的啦!

通過設定Orientation

  • 水平對齊: Orientation="Horizontal"
  • 垂直對齊: Orientation="Vertical"(預設)


對於內部元素自身,也可以選擇對其對齊方式

  • HorizontalAlignment="left" Center,right
  • VerticalAlignment="Top" Bottom,Center,Stretch

3、WrapPanel 流動佈局

當元素水平對齊,內容超過寬度時,自動換行;當元素垂直對齊,內容超過高度時,自動換列)

它可能和上面的長得像,其實是不一樣的。當StackPanel的內部子元素數量超出寬度(高度)會溢位窗體,而流動佈局會自動換行。常用於動態資料生成。

這就不做詳細介紹了,屬性都和上面的一樣。

4、DockPanel 停靠佈局

做過winfrom開發的朋友,都知道一個Docl屬性吧,那麼我們的Dock佈局也是這個道理,我們來實踐一下。

在DockPanel的容器裡的控制元件,會增加一個附加屬性DockPanel.Dock

  • DockPanel.Dock="Top"
  • DockPanel.Dock="Bottom"
  • DockPanel.Dock="Left"
  • DockPanel.Dock="Right"

分別是上下左右停靠,要注意的是控制元件會隨著設定的先後順序,具有不同的寬高(或大小),預設最後一個停靠控制元件的大小佔剩下介面的全部

仔細看左 和 右 ,你就會知道我說的注意項,新停靠的控制元件佔剩餘頁面的所有區域。

5、Canvas 座標佈局

好吧,這個真的就相當於winform的佈局了, 設定座標,確定控制元件的位置。

在Canvas容器裡的控制元件,會增加附加屬性

  • 距離視窗上方: Canvas.Top="20"
  • 距離視窗左方:Canvas.Left="100"
  • 距離視窗下方:Canvas.Bottom="20"
  • 距離視窗右方:Canvas.Right="0"

四、綜合小案例

如果都看完的話,我們來做一個小案例吧。

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="4*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <StackPanel Grid.RowSpan="2" Grid.Column="0">
            <Button  Height="50">新建StackPanel</Button>
            <Button  Height="50">儲存StackPanel</Button>
            <Button  Height="50">增加StackPanel</Button>
            <Button  Height="50">匯入StackPanel</Button>
            <Button  Height="50">匯出StackPanel</Button>
            <Button  Height="50">關閉StackPanel</Button>
        </StackPanel>
        <DockPanel Grid.Row="0" Grid.Column="1">
            <TextBlock DockPanel.Dock="Top" HorizontalAlignment="Center">我是DockPanel</TextBlock>
            <WrapPanel>
                <Button Width="200">WrapPanel</Button>
                <Button Width="200">WrapPanel</Button>
                <Button Width="200">WrapPanel</Button>
                <Button Width="200">放不下啦WrapPanel</Button>
                <Button Width="200">WrapPanel</Button>
            </WrapPanel>
        </DockPanel>
        <Canvas Grid.Row="1" Grid.Column="1">
            <TextBlock Canvas.Top="100" Canvas.Left="100">Canvas賬號:</TextBlock>
            <TextBox Canvas.Top="100" Canvas.Left="200">Canvas請輸入賬號:</TextBox>
            <TextBlock Canvas.Top="130" Canvas.Left="100">Canvas密碼:</TextBlock>
            <TextBox Canvas.Top="130" Canvas.Left="200">Canvas請輸入密碼:</TextBox>
        </Canvas>
    </Grid>

結束語 “不要用不公平掩飾你不努力的樣子”