目錄
- 控制元件概述
- WPF的內容模型
- 各類內容模型詳解
- ContentControl族
- HeaderedContentControl族
- ItemsControl族
- ListBox:在XAML中添加資料
- ListBox:在代碼中添加資料
- HeaderedItemsControl族
- Decorator族
- TextBlock和TextBox
- Shape族元素
- Panel族元素
- UI布局(Layout)
- 布局元素
- Grid
- 定義Grid的行與列
- 行高和列寬的單位
- 行高和列寬的取值
- 為控制元件指定行和列遵循的規則
- StackPanel
- Canvas
- DockPanel
- WrapPanel
- 總結
- 參考資料
控制元件概述
程式的本質是“資料+演算法”——用戶輸入原始資料,演算法處理原始資料并得到結果資料,程式可以使用LED陣列、格式字串、圖形化用戶界面(Graphic User Interface,GUI)將結果資料顯示給用戶,其中圖形化用戶界面最方便、直觀,
在Windows上實作圖形化的界面有多種方法,每種方法又擁有自己的一套開發理念和工具并組成一種方法論,常見的有:
- Windows APl(Win APl):呼叫Windows底層繪圖函式,使用C語言,最原始也最基礎,
- Microsoft Foundation Class(MFC):使用C++語法將原始的Win32API函式封裝成控制元件類,
- Visual Component Library(VCL):Delphi和C++Builder使用的與MFC相近的控制元件類別庫,
- Visual Basic+ActiveX控制元件(VB6):使用組件化的思想把WinAPI封裝成UI控制元件,以期多語言共用,
- Java Swing/AWT:Java SDK中用于跨平臺開發GUI程式的控制元件類別庫,
- Windows Form:.NET平臺上進行GUl開發的老牌勁旅,完全組件化但需要.NET運行時支持,
- Windows Presentation Foundation(WPF):后起之秀,使用全新的資料驅動UI的理念,
可以把上述這些方法論分為四代:
- WinAPI時代:函式呼叫+Windows訊息處理,
- 封裝時代:使用面向物件理念把WinAPI封裝成類;由來自UI的訊息驅動程式處理資料,
- 組件化時代:使用面向組件理念在類的基礎上封裝成組件;訊息被封裝成事件,變成事件驅動,
- WPF時代:在組件化的基礎上,使用專門的UI設計語言并引入由資料驅動UI的理念,
注:目前流行使用前端的方式實作GUI,如Electron、NanUI等,
WPF中是資料驅動UI,資料是核心、是主動的;UI從屬于資料并表達資料、是被動的,WPF把那些能夠展示資料、回應用戶操作的UI元素稱為控制元件(Control),控制元件所展示的資料稱之為控制元件的“資料內容”,控制元件在回應用戶的操作后會執行自己的一些方法或以事件(Event)的形式通知應用程式稱之為控制元件的“行為”或“演算法內容”,
WPF中的控制元件是個非常抽象的概念——Control是資料和行為的載體,而無需具有固定的形象,如只要是用來顯示一個bool型別值并允許用戶通過單擊來切換true/false/null的UI元素就是一個CheckBox(關注抽象的資料和行為而不是控制元件具體的形象),
日常作業中打交道最多的控制元件無外乎6類,即:
- 布局控制元件:可以容納多個控制元件或嵌套其他布局控制元件,用于在UI上組織和排列控制元件,如Grid、StackPanel、DockPanel 等控制元件(共同的父類是Panel),
- 內容控制元件:只能容納一個其他控制元件或布局控制元件作為它的內容,如Window、Button等控制元件(經常需要借助布局控制元件來規劃其內容,共同父類是ContentControl),
- 帶標題內容控制元件:相當于一個內容控制元件,但可以加一個標題(Header),標題部分亦可容納一個控制元件或布局,GroupBox、Tabltem等是這類控制元件的典型代表(共同父類是HeaderedContentControl),
- 條目控制元件:可以顯示一列資料,一般情況下這列資料的型別相同,此類控制元件包括ListBox、ComboBox等(共同基類是ltemsControl,在顯示集合型別資料方面功能非常強大),
- 帶標題條目控制元件:相當于一個條目控制元件加上一個標題顯示區,Tree Viewltem、Menultem都屬于此類控制元件(往往用于顯示層級關系資料,結點顯示在其Header區域,子級結點則顯示在其條目控制元件區域,共同基類是HeaderedltemsControl),
- 特殊內容控制元件:這類控制元件相對比較獨立,比如TextBox容納的是字串、TextBlock可以容納可自由控制格式的文本、Image容納圖片型別資料,
6類控制元件的派生關系如下圖所示:

WPF是構建在.NET Framework上的一個子系統,它也是一個用于開發應用程式的框架(Framework),FrameworkElement的Framework指的就是WPF Framework,而FrameworkElement類在UIElement類的基礎上添加了很多專門用于WPF開發的API(比如SetBinding方法),所以從這個類開始才算是進入WPF開發柜架,
WPF的內容模型
根據是否可以裝載內容、能夠裝載什么樣的內容,WPF的UI元素可以分為如下型別:
| 名稱 | 注釋 |
|---|---|
| ContentControl | 單一內容控制元件 |
| HeaderedContentControl | 帶標題的單一內容控制元件 |
| ltemsControl | 以條目集合為內容的控制元件 |
| HeaderedltemsControl | 帶標題的以條目集合為內容的控制元件 |
| Decorator | 控制元件裝飾元素 |
| Panel | 面板類元素 |
| Adorner | 文字點綴元素 |
| Flow Text | 流式文本元素 |
| TextBox | 文本輸入框 |
| TextBlock | 靜態文字 |
| Shape | 圖形元素 |
控制元件的內容可以直接是資料,也可以是控制元件,當控制元件的內容還是控制元件的時候就形成了控制元件的嵌套(UI布局時尤為常見),被嵌套的控制元件稱為子級控制元件,所以WPF的UI會形成一個樹形結構,
- 邏輯樹(Logical Tree):不考慮控制元件內部的組成結構,只觀察由控制元件組成的“樹”,
- 可視元素樹(Visual Tree):WPF控制元件往往是由更基本的控制元件構成的(控制元件本身就是一棵樹),連控制元件本身的樹也考慮在內,比邏輯樹更“繁茂”的樹,
控制元件是記憶體中的物件,控制元件的內容也是記憶體中的物件,控制元件通過自己的某個屬性參考著作為其內容的物件,這個屬性稱為內容屬性(Content Property),“內容屬性”是個統稱,具體到每種控制元件上,內容屬性都有自己確切的名字——Content、Child、Items或Children,
控制元件的內容屬性與XAML標簽的內容存在一定的對應關系,XAML標簽的內容區域專門映射了控制元件的內容屬性,下面從語法和常理來解釋一下:
- 嚴格按照語法來說,控制元件有內容屬性,在XAML里就應該能夠使用Atribute=Value 或者屬性標簽的形式來為內容賦值,如:
<Button Content="OK"/>
<!--或-->
<Button>
<Button.Content>
<sys:String>OK</sys:String>
</Button.Content>
</Button>
- 按照常理來說,控制元件對應到XAML檔案里就是標簽,控制元件的內容就應該是標簽的內容、子級控制元件就應該是標簽的子級元素(簡稱標簽的元素),標簽的內容是夾在起始標簽和結束標簽間的代碼,上面的代碼可以寫成:
<Button>
<sys:String>OK</sys:String>
</Button>
各類內容模型詳解
把符合某類內容模型的UI元素稱為一個族,每個族用它們共同基類來命名,
ContentControl族
本族元素的特點如下:
- 均派生自ContentControl類,
- 它們都是控制元件(Control),
- 內容屬性的名稱為Content,
- 只能由單一元素充當其內容,
“只能由單一元素充當其內容”以Button為例,Buton只能接受一個元素作為它的Content,需要一個帶圖示、文字的Button時要先用一個可以包含多個元素的布局控制元件把圖片和文字包裝起來,再把這個布局控制元件作為Buton的內容(控制元件的內容也可以是控制元件),
ContentControl族包含的控制元件:Button、ButtonBase、CheckBox、ComboBoxItem、ContentControl、Frame、GridViewColumnHeader、GropItem、Label、ListBoxItem、ListViewItem、NavigationWindow、RadioButton、RepeatButton、ScrollViewer、StatusBarItem、ToggleButton、ToolTip、UserControl、Window,
HeaderedContentControl族
本族元素的特點如下:
- 它們都派生自HeaderedContentControl類,HeaderedContentControl是ContentControl類的派生類,
- 它們都是控制元件,用于顯示帶標題的資料,
- 除了用于顯示主體內容的區域外,控制元件還具有一個顯示標題(Header)的區域,
- 內容屬性為Content和Header,
- 無論是Content 還是Header都只能容納一個元素作為其內容,
HeaderedContentControl族包含的控制元件:Expender、GroupBox、HeaderedContentControl、TabItem,
下面演示一個以圖示為Header、以文字為主體內容的GroupBox,代碼如下:
<!--GroupBox.Content標簽可以省略-->
<GroupBox Margin="10" BorderBrush="SlateBlue">
<GroupBox.Header>
<Image Source="img.jpg" Width="20" Height="20"></Image>
</GroupBox.Header>
<GroupBox.Content>
<TextBlock TextWrapping="WrapWithOverflow" Margin="10" Text="測驗內容"></TextBlock>
</GroupBox.Content>
</GroupBox>
ItemsControl族
本族元素的特點如下:
- 均派生自ItemsControl類,
- 它們都是控制元件,用于顯示串列化的資料,
- 內容屬性為Items或ItemsSource,
- 每種ItemsControl都對應有自己的條目容器(Item Container),
本族的包含的控制元件:Menue、MenuBase、ContextMenu、ComboBox、ItemsControl、ListBox、ListViewe、TabControl、TreeView、Selector、StatusBar,對應的Item Container如下:
| ItemsControl名稱 | 對應的Item container |
|---|---|
| ComboBox | ComboBoxItem |
| ContextMenu | MenuItem |
| ListBox | ListBoxItem |
| ListView | ListViewItem |
| Menu | MenuItem |
| StatusBar | StatusBarItem |
| TabControl | TabItem |
| TreeView | TreeViewItem |
下面列出屬于ItemsControl族元素和其對應的Item Container有ComboBox——ComboBoxItem,ContextMenu——MenuItem,ListBox——ListBoxItem,ListView——ListViewItem,Menu——MenuItem,StatusBar——StatusBarItem,TabControl——TabItem,TreeView——TreeViewItem.
ListBox:在XAML中添加資料
ListBox除了可以顯示中規中矩的字串條目還能夠顯示更多的元素,如CheckBox、RadioButton、TextBox等,例如下面這段代碼:
<!--ListBoxItem標簽已省略-->
<ListBox x:Name="listbox" Margin="5">
<CheckBox x:Name="chb1" Content="選擇1"/>
<CheckBox x:Name="chb2" Content="選擇2"/>
<CheckBox x:Name="chb3" Content="選擇3"/>
<CheckBox x:Name="chb4" Content="選擇4"/>
<Button x:Name="btn1" Content="按鈕1"/>
<Button x:Name="btn2" Content="按鈕2"/>
<Button x:Name="btn3" Content="按鈕3"/>
</ListBox>
表面看上去是ListBox直接包含了一些CheckBox和Buton,實際上這些CheckBox和Buton的父級容器是ListBoxItem,為按鈕添加如下的事件代碼查看父容器:
private void btn1_Click(object sender, RoutedEventArgs e)
{
Button btn = (sender) as Button;
DependencyObject level1 = VisualTreeHelper.GetParent(btn);
DependencyObject level2 = VisualTreeHelper.GetParent(level1);
DependencyObject level3 = VisualTreeHelper.GetParent(level2);
StringBuilder sbr = new StringBuilder();
sbr.AppendLine("level1:"+level1.GetType().ToString());
sbr.AppendLine("level2:" + level2.GetType().ToString());
sbr.AppendLine("level3:" + level3.GetType().ToString());
MessageBox.Show(sbr.ToString());
}
ListBox:在代碼中添加資料
除非串列里的元素自始至終都是固定的才使用這種直接把UI元素作為ItemsControl內容的方法,如日期等,大多數情況下,UI上的串列會用于顯示動態的后臺資料,此時交給ltemsControl的就是程式邏輯中的資料了,在代碼中為ListBox添加資料的代碼如下:
<Grid>
<ListBox x:Name="listbox" Margin="5"/>
</Grid>
List<Employee> empList = new List<Employee>()
{
new Employee(){Id = 1, Name ="Tim", Age = 30},
new Employee(){Id = 2, Name="Tom",Age=26},
new Employee(){Id = 3,Name="Guo",Age=26},
new Employee(){Id = 4,Name="Yan",Age=25},
new Employee(){Id = 5,Name="Owen",Age=30},
new Employee(){Id=6,Name="Victor",Age=30 }
};
this.listbox.DisplayMemberPath = "Name";
this.listbox.SelectedValuePath = "Id";
this.listbox.ItemsSource= empList;
//Employee類
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
- DisplayMemberPath:這個屬性告訴ListBox顯示每條資料的哪個屬性,ListBox會去呼叫這個屬性值的ToString()方法,把得到的字串放入一個TextBlock(最簡單的文本控制元件),然后再按前面說的辦法把TextBlock包裝進一個ListBoxItem里,
- SelectedValuePath:這個屬性將與其SelectedValue屬性配合使用,當呼叫SelectedValue屬性時ListBox先找到選中的Item所對應的資料物件,然后把SelectedValuePath的值當作資料物件的屬性名稱并把這個屬性的值取出來,
DisplayMemberPath 和Selected ValuePath 是兩個相當簡化的屬性,DisplayMemberPath只能顯示簡單的字串,想用更加復雜的形式顯示資料需要使用DataTemplate;SelectedValuePath也只能回傳單一的值,如果想進行一些復雜的操作可直接使用ListBox的SelectedItem和SelectedItems屬性,這兩個屬性回傳的是資料集合中的物件,
HeaderedItemsControl族
本族控制元件*除了具有ItemsControl的特性外,還具顯示標題的能力**,本族元素的特點如下:
- 均派生自HeaderedItemsControl類,
- 它們都是控制元件,用于顯示串列化的資料,同時可以顯示一個標題,
- 內容屬性為Items、ItemsSource和Header,
本族控制元件只有3個:MenuItem、TreeViewItem、ToolBar,
Decorator族
本族中的元素是在UI上起裝飾效果的,本族元素的特點如下:
- 均派生自Decorator類,
- 起UI裝飾作用,
- 內容屬性為Child,
- 只能由單一元素充當內容,
本族元素有:ButtonChrome、ClassicBorderDecorator、ListBoxChrome、SystemDropShadowChrome、Border、InkPresenter、BulletDecorator、Viewbox、AdornerDecorator,
可以使用Border元素為一些組織在一起的內容加個邊框,使用ViewBox元素讓組織在一起的內容能夠自由縮放,
TextBlock和TextBox
兩個控制元件最主要的功能是顯示文本:
- TextBlock只能顯示文本,不能編輯,又稱靜態文本,可以使用豐富的印刷級的格式控制標記顯示專業的排版效果,由于需要操縱格式它的內容屬性是Inlines(印刷中的“行”),同時也保留一個名為Text的屬性(當簡單地顯示一個字串時可以使用)
- TextBox則允許用戶編輯其中的內容,由于不需要太多的格式顯示它的內容是簡單的字串,內容屬性為Text,
TextBlock屬于比較底層的控制元件,因此它的性能要比Label好一些,如果需求只是純文本的顯示,并且不提供Access key的支持,那么TextBlock是個不錯的選擇,
Shape族元素
Shape族元素(只是簡單的視覺元素,不是控制元件)是專門用來在UI上繪制圖形的一類元素,本族元素的特點如下:
- 均派生自Shape類,
- 用于2D圖形繪制,
- 無內容屬性,
- 使用Fill屬性設定填充,使用Stroke屬性設定邊線,
注:該族控制元件一般較少使用,用于自定義控制元件外觀,
Panel族元素
所有用于UI布局的元素都屬于這一族,本族元素的特點如下:
- 均派生自Panel抽象類,
- 主要功能是控制UI布局,
- 內容屬性為Children
- 內容可以是多個元素,Panel元素將控制它們的布局,
ItemsControl和Panel元素內容都可以是多個元素,但ItemsControl強調以串列的形式來展現資料而Panel則強調對包含的元素進行布局,所以ItemsControl的內容屬性是Items和ItemsSource而Panel的內容屬性名為Children,
本族元素有:Canvas、DockPanel、Grid、TabPanel、ToolBarOverflowPanel、StackPanel、ToolBarPanel、UniformGrid、VirtualizingPanel|VirtualizingStackPanel、WrapPanel,
UI布局(Layout)
WPF的布局是依靠各種布局元素實作的,
布局元素
WPF中的布局元素有如下幾個:
- Grid:網格,可以自定義行和列并通過行列的數量、行高和列寬來調整控制元件的布局,近似于HTML中的Table,
- StackPanel:堆疊式面板,可將包含的元素在豎直或水平方向上排成一條直線,移除元素時后面的元素會自動向前移動填充空缺,
- Canvas:畫布,內部元素可以使用以像素為單位的絕對坐標進行定位,類似于Windows Form編程的布局方式,
- DockPanel:泊靠式面板,內部元素可以選擇泊靠方向,類似于在Windows Form編程中設定控制元件的Dock屬性,
- WrapPanel:自動折行面板,內部元素在排滿一行后能夠自動折行,類似于HTML中的流式布局,
Grid
Grid元素會以網格的形式對內容元素們(即它的Children)進行布局,
Grid的特點如下:
- 可以定義任意數量的行和列,非常靈活,
- 行的高度和列的寬度可以使用絕對數值、相對比例或自動調整的方式進行精確設定,并可設定最大和最小值,
- 內部元素可以設定自己的所在的行和列,還可以設定自己縱向跨幾行、橫向跨幾列,
- 可以設定Children元素的對齊方向,
Grid適用的場合有:
- UI布局的大框架設計,
- 大量UI元素需要成行或者成列對齊的情況,
- UI整體尺寸改變時,元素需要保持固有的高度和寬度比例,
- UI后期可能有較大變更或擴展,
定義Grid的行與列
Grid類具有ColumnDefinitions和RowDefinitions兩個屬性,分別是ColumnDefinition和RowDefinition的集合,表示Grid定義了多少列、多少行,
XAML代碼如下:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
C#代碼如下:
//添加列
grid.ColumnDefinitions.Add(new ColumnDefinition());
grid.ColumnDefinitions.Add(new ColumnDefinition());
//添加行
grid.RowDefinitions.Add(new RowDefinition());
grid.RowDefinitions.Add(new RowDefinition());
行高和列寬的單位
計算機圖形設計的標準單位是像素(Pixel),所以Grid的寬度和高度單位就是像素,此外,Grid還接受英寸(Inch)、厘米(Centimeter)和點(Point),如下表所示:
| 英文名稱 | 中文名稱 | 簡寫 | 換算 |
|---|---|---|---|
| Pixel | 像素 | px(默認單位,可省略) | 圖形基本單位 |
| Inch | 英寸 | in | 1inch=96pixel |
| Centimeter | 厘米 | cm | 1cm=(96/2.54)pixel |
| Point | 點 | pt | 1pt=(96/72)pixel |
實際使用如下所示:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30px"/>
<RowDefinition Height="30"/>
<RowDefinition Height="0.5in"/>
<RowDefinition Height="1cm"/>
<RowDefinition Height="30pt"/>
</Grid.RowDefinitions>
</Grid>
- 屬性的值為double型別,
- 因為像素是默認單位,所以px可以省略,
- 其他單位也會被轉換成像素并顯示在Grid的邊緣處,
行高和列寬的取值
對于Grid的行高和列寬,可以設定三類值:
- 絕對值:double數值加單位后綴(如上例),一經設定就不會再改變,又稱固定值,適用于當控制元件的寬度和高度不需要改變或者使用空行、空列作為控制元件間隔時,
- 比例值:double數值后加一個星號(“*”),比例值的最終像素數=比例值的數值/所有比例值的數值和*未被占用空間的像素數,當改變容器的尺寸時使用比例值的行高會保持固有比例,行高和列寬的默認形式就是比例值,沒有顯式指定行高或列寬時默認值就是1*(1*又可以簡寫為*),
- 自動值:字串Auto,行高或列寬的實際值將由行列內控制元件的高度和寬度決定,控制元件會把行列“撐”到合適的寬度和高度,行列中沒有控制元件時行高和列寬均為0,
為控制元件指定行和列遵循的規則
- 行和列都是從0開始計數,
- 指定一個控制元件在某行,就為這個控制元件的標簽添加Grid.Row=“行編號“這樣一個Attribute,若行編號為0(即控制元件處于首行)則可省略這個Attribute,
- 指定一個控制元件在某列,就為此控制元件添加Grid.Column=”列編號”這樣的Attribute,若列編號為0則Attribute可以者略不寫,
- 若控制元件需要跨多個行或列,請使用Grid.RowSpan=“行數“和Grid.ColumnSpan=“列數“兩個Atribute,
StackPanel
StackPanel可以把內部元素在縱向或橫向上緊湊排列、形成堆疊式布局,StackPanel適合的場合有:
- 同類元素需要緊湊排列(如制作選單或者串列),
- 移除其中的元素后能夠自動補缺的布局或者影片,
StackPanel使用Orientation、HorizontalAlignment和VerticalAlignment這3個屬性來控制內部元素的布局,如下所示:
| 屬性名稱 | 可取值 | 描述 |
|---|---|---|
| Orientation | Horizontal Vertical |
決定內部元素是橫向累積還是縱向累積 |
| HorizontalAlignment | Left Center Right Stretch |
決定內部元素水平方向上的對齊方式 |
| VerticalAlignment | Top Center Bottom Stretch |
決定內部元素豎直方向上的對齊方式 |
Canvas
Canvas譯成中文就是“畫布”,在Canvas里布局就像在畫布上畫控制元件一樣,使用Canvas布局與在Windows Form表單上布局基本上是一樣的,只是WPF的控制元件沒有Left和Top等屬性,當控制元件被放置在Canvas里時就會被附加上Canvas.X和Canvas.Y屬性,
Canvas適用的場合包括:
- 一經設計基本上不會再有改動的小型布局(如圖示),
- 藝術性比較強的布局,
- 需要大量使用橫縱坐標進行絕對點定位的布局,
<Canvas>
<TextBlock Text="用戶名:" Canvas.Left="12" Canvas.Top="12"/>
<TextBox Height="23" Width="200" BorderBrush="Black" Canvas.Left="66" Canvas.Top="19"/>
<TextBlock Text="密碼:" Canvas.Left="12" Canvas.Top="40.72" Height="16" Width="36"/>
<TextBox Height="23" Width="200" BorderBrush="Black" Canvas.Left="66" Canvas.Top="38"/>
<Button Content="確定" Width="80" Height="22" Canvas.Left="100" Canvas.Top="67"/>
<Button Content="清除" Width="80" Height="22" Canvas.Left="186" Canvas.Top="67"/>
</Canvas>
除非你確定這個視窗的布局以后不會改變而且表單尺寸固定,不然還是用Grid進行布局彈性會更好,
DockPanel
DockPanel內的元素會被附加上DockPanel.Dock這個屬性,這個屬性的資料型別為Dock列舉(可取Left、Top、Right和Bottom四個值),根據Dock屬性值,DockPanel內的元素會向指定方向累積、切分DockPanel內部的剩余可用空間,
DockPanel還有一個重要屬性——bool型別的LastChildFill(默認值是True),當LastChildFill屬性的值為True時,DockPanel內最后一個元素的DockPanel.Dock屬性值會被忽略,這個元素會把 DockPanel內部所有剩余空間充滿,
實際使用如下:
<Grid>
<DockPanel>
<TextBox DockPanel.Dock="Top" Height="25" BorderBrush="Black" />
<TextBox DockPanel.Dock="Left" Width="150" BorderBrush="Black"/>
<TextBox BorderBrush="Black"/>
</DockPanel>
</Grid>
WrapPanel
WrapPanel內部采用的是流式布局,使用Orientation屬性來控制流延伸的方向,使用HorizontalAlignment和VerticalAlignment 兩個屬性控制內部控制元件的對齊,在流延伸的方向上,WrapPanel會排列盡可能多的控制元件,排不下的控制元件將會新起一行或一列繼續排列,
實際使用如下:
<WrapPanel>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
<Button Width="50" Height="50" Content="OK"/>
</WrapPanel>

總結
形而上者謂之道,形而下者謂之器,WPF的內部機理可以說是WPF的“道”,動手實踐寫程式可以說是WPF的“器”,
參考資料
WPF控制元件和布局
控制元件與布局(WPF)
WPF學習二:TextBlock和Label的區別
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/258597.html
標籤:.NET技术
上一篇:c#記兩個變數進行值交換
下一篇:C#中word匯出功能騷操作
