# WPF快速入門系列(1)——WPF布局概覽
## 一、引言
關于WPF早在一年前就已經看過《深入淺出WPF》這本書,當時看完之后由于沒有做筆記,以至于我現在又重新撿起來并記錄下學習的過程,本系列將是一個WPF快速入門系列,主要介紹WPF中主要的幾個不同的特性,如依賴屬性、命令、路由事件等。
在正式介紹之前,我還想分享下為什么我又要重新撿起來WPF呢?之前沒有記錄下來的原來主要是打算走互聯網方向的,后面發現互聯網方向經常加班,又累,有時候忙的連自己寫了什么都不知道的,所以后面機緣巧合地進了一家外企,在外企不像互聯網行業那樣,比較清楚,有更多的時間去理清楚自己所學習到的知識,其中同時也發現了WPF的重要性和應用場景,在一些美資企業和印度的公司,客戶端都非常喜歡用WPF來做演示的客戶端,所以,自然走上外企這條路,所以就打算好好研究下WPF了,所以也就有了這個系列。
## 二、WPF的自我介紹
Windows Presentation Foudation,WPF是下一代顯示系統,用來生成能帶給用戶震撼視覺體驗的Windows客戶端應用程序。WPF的核心是一個與分辨率無關并且基于向量的程序引擎,目的在于利用現代圖形硬件的優勢。WPF在.NET Framework 3.0中被微軟引入到.NET Framework類庫中,并且在.NET 3.5、4.0 和4.5都有所更新。WPF可以理解為是實現下一代Windows 桌面應用程序的技術,在之前我們通常會使用MFC或Winform來實現Windows桌面程序。
WPF除了引入了新的API之前,還引入了一些新的概念,這些新的概念會在本系列中一一介紹。眾所周知,在實現桌面應用程序之前,第一步必然是對窗體進行布局,WPF為了更好地實現布局,提供了很多布局控件,下面就讓我們一起去看看WPF布局組件。
## 三、WPF布局詳解
WPF的布局控件都繼承于System.Windows.Controls.Panel這個類,本文主要介紹在Panel基類下的幾個常用的布局控件。下圖是布局控件的繼承關系:

## 3.1 WPF布局過程
WPF布局包括兩個階段:**一個測量(measure)階段和一個排列(arrange)階段**。在測量階段,容器遍歷所有子元素,并詢問子元素它們所期望的大小。在排列階段,容器在合適的位置放置子元素。WPF布局可以理解為一個遞歸過程,它會遞歸對布局控件內的每個子元素進行大小調整,定位和繪制,最后進行呈現,直到遞歸所有子元素為止,這樣也就完成了整個布局過程。
布局系統為每個子元素完成了兩個處理過程:測量處理和排列處理。每個Panel都提供了自己的**[MeasureOverride](http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.measureoverride(v=vs.110).aspx)**和**[ArrangeOverride](http://msdn.microsoft.com/zh-cn/library/system.windows.frameworkelement.arrangeoverride(v=vs.110).aspx)**方法,以實現自己特定的布局行為。所以,你如果想自定義布局控件,也可以重新這兩個方法來達到,關于自定義布局控件會在后面介紹到。
## 3.2 Canvas 布局控件
Canvas面板是最輕量級的布局容器,它不會自動調整內部元素的排列和大小,不指定元素位置,元素將默認顯示在畫布的左上方。Canvas主要用來畫圖。Canvas默認不會自動裁剪超過自身范圍的內容,即溢出的內容會顯示在Canvas外面,這是因為Canvas的ClipToBounds屬性默認值是false,我們可以顯式地設置為true來裁剪多出的內容。下面XAML代碼簡單演示了Canvas面板的使用。
上面XAML實現的效果如下圖所示:

其中,矩形的右邊區域以溢出Canvas面板區域,如向右拉動邊框,此時Canvas會拉伸以填滿可用空間,此時就可以看到矩形溢出的部分。但Canvas面板內的控件不會改變其尺寸和位置。對應的C#代碼實現如下所示:
```
1 public partial class CanvasDemo : Window
2 {
3 public CanvasDemo()
4 {
5 InitializeComponent();
6
7 Canvas canv = new Canvas();
8 canv.Margin = new Thickness(10, 10, 10, 10);
9 canv.Background = new SolidColorBrush(Colors.White);
10
11 // 把canv添加為窗體的子控件
12 this.Content = canv;
13
14 // Rectangle
15 Rectangle rect = new Rectangle();
16 rect.Fill = new SolidColorBrush(Colors.Black);
17 rect.Stroke = new SolidColorBrush(Colors.Red);
18 rect.Width = 200;
19 rect.Height = 200;
20 rect.SetValue(Canvas.LeftProperty, (double)300);
21 rect.SetValue(Canvas.TopProperty, (double)180);
22 canv.Children.Add(rect);
23
24 // Ellipse
25 Ellipse el = new Ellipse();
26 el.Fill = new SolidColorBrush(Colors.Azure);
27 el.Stroke = new SolidColorBrush(Colors.Green);
28 el.Width = 180;
29 el.Height = 180;
30 el.SetValue(Canvas.LeftProperty, (double)160);
31 // 必須轉換為double,否則執行會出現異常
32 // 詳細介紹見:http://msdn.microsoft.com/zh-cn/library/system.windows.controls.canvas.top(v=vs.110).aspx
33 el.SetValue(Canvas.TopProperty, (double)150);
34 el.SetValue(Panel.ZIndexProperty, -1);
35 canv.Children.Add(el);
36
37 // Print Zindex Value
38 int zRectIndex = (int)rect.GetValue(Panel.ZIndexProperty);
39 int zelIndex = (int)el.GetValue(Panel.ZIndexProperty);
40 Debug.WriteLine("Rect ZIndex is: {0}", zRectIndex);
41 Debug.WriteLine("Ellipse ZIndex is: {0}", zelIndex);
42 }
43 }
```
從上面可以看出,即使C#代碼可以實現完全一樣的效果,但是需要書寫更多的代碼,所以,在平時開發中,對于控件的布局,一般采用XAML的方式,C#代碼一般用于在運行時加載某個控件到界面中的實現。
## 3.3 StackPanel 布局控件
StackPanel就是將子元素按照堆棧的形式一一排列,可以通過設置StackPanel的Orientation屬性設置兩種排列方式:橫排(Horizontal,該值為默認值)和豎排(Vertical)。縱向的StackPanel每個元素默認寬度與面板一樣寬,反之橫向是高度和面板一樣高。如果包含的元素超過了面板控件,它會被截斷多出的內容。可以通過Orientation屬性來設置StackPanel是橫排(設置其值為Vertical)還是豎排(設置其值為Horizontal)。下面XAML代碼演示了StackPanel的使用:
```
1 <Window x:Class="WPFLayoutDemo.StackPanelDemo"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="StackPanel" Height="300" Width="200">
5 <StackPanel Margin="10,10,10,10" Background="Azure">
6 <Label>A Button Stack</Label>
7 <Button Content="Button 1"></Button>
8 <Button>Button 2</Button>
9 <Button>Button 3</Button>
10 <Button Content="Button 4"></Button>
11 </StackPanel>
12 </Window>
```
對應的C#實現代碼如下所示:
```
1 public partial class StackPanelDemo : Window
2 {
3 public StackPanelDemo()
4 {
5 InitializeComponent();
6 StackPanel sp = new StackPanel();
7 sp.Margin = new Thickness(10, 10, 10, 10);
8 sp.Background = new SolidColorBrush(Colors.Azure);
9 sp.Orientation = Orientation.Vertical;
10 // 把sp添加為窗體的子控件
11 this.Content = sp;
12
13 // Label
14 Label lb = new Label();
15 lb.Content = "A Button Stack";
16 sp.Children.Add(lb);
17
18 // Button 1
19 Button btn1 = new Button();
20 btn1.Content = "Button 1";
21 sp.Children.Add(btn1);
22
23 // Button 2
24 Button btn2 = new Button();
25 btn2.Content = "Button 2";
26 sp.Children.Add(btn2);
27
28 // Button 3
29 Button btn3 = new Button();
30 btn3.Content = "Button 3";
31 sp.Children.Add(btn3);
32
33 // Button 4
34 Button btn4 = new Button();
35 btn4.Content = "Button 4";
36 sp.Children.Add(btn4);
37 }
38 }
```
上面代碼的實現效果如下圖所示:

如果將StackPanel的Orientation屬性設置為“Horizontal”的話,此時的效果如下圖所示:

盡管布局由容器決定,但子元素仍然有一定的決定權,布局面板支持一些布局屬性,以便與子元素結合使用,在下圖中列出了這些布局屬性:

## 3.4 WrapPanel 布局控件
WrapPanel面板在可能的空間中,一次以一行或一列的方式布置控件。默認情況下,WrapPanel.Orientation屬性設置為Horizontal,控件從左向右進行排列,然后再在下一行中排列,但你可將WrapPanel.Orientation設置為Vertical,從而在多個列中放置元素。與StackPanel面板不同,WrapPanel面板實際上用來控制用戶界面中一小部分的布局細節,并非用于控制整個窗口布局。
下面示例中定義了一系列具有不同對齊方式的按鈕,并將這些按鈕放在一個WrapPanel面板中。
```
1 <Window x:Class="WPFLayoutDemo.WrapPanelDemo"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="WrapPanelDemo" Height="300" Width="500">
5 <WrapPanel Margin="10" Background="Azure">
6 <Button VerticalAlignment="Top" Margin="5">Top Button</Button>
7 <Button MinHeight="50"> Tall Button 2</Button>
8 <Button VerticalAlignment="Bottom">Bottom Button</Button>
9 <Button>Stretch Button</Button>
10 <Button VerticalAlignment="Center">Center Button</Button>
11 <Button>Next Button</Button>
12 </WrapPanel>
13 </Window>
```
下圖顯示了如何對這些按鈕進行換行以適應WrapPanel面板的當前尺寸,WrapPanel面板的當前尺寸由包含它的窗口尺寸決定的。在上面的例子中,WrapPanel面板水平地創建一系列假象的行,每一行的搞定都被設置為所包含元素中最高元素的高度。其他空間可能被拉伸以適應該高度,或根據VerticalAlignment屬性設置進行對齊。

當縮小窗口大小時,對應的WrapPanel也會改變,從而改變WrapPanel面板中控件的排列,具體效果如下圖所示:

## 3.5 DockPanel 布局控件
DockPanel面板定義一個區域,在此區域中,你可以使子元素通過錨點的形式進行排列。DockPanel類似于WinForm中Dock屬性的功能。對于在DockPanel中的元素的停靠可以通過Panel.Dock的附加屬性來設置,如果設置LastChildFill屬性為true,則最后一個元素將填充剩余的所有空間。
下面XAML代碼演示了DockPanel控件的使用:
```
1 <Window x:Class="WPFLayoutDemo.DockPanelDemo"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="DockPanelDemo" Height="300" Width="300">
5 <DockPanel Margin="10" Background="Azure" LastChildFill="True">
6 <Button DockPanel.Dock="Top" Background="Red">Top Button</Button>
7 <Button DockPanel.Dock="Left" Background="Gray">Left Button</Button>
8 <Button DockPanel.Dock="Right" Background="Green">Right Button</Button>
9 <Button DockPanel.Dock="Bottom" Background="White">Bottom Button</Button>
10 <Button>Remaining Button</Button>
11 </DockPanel>
12 </Window>
```
運行的效果如下圖所示:

## 3.6 Grid 布局控件
Grid比起其他Panel,功能是最多最為復雜的布局控件。它由<Grid.ColumnDefinitions>列元素集合和<Grid.RowDefinitions>行元素集合兩種元素組成。而放在Grid面板中的元素必須顯式采用附加屬性定義其所在行和列,否則元素均默認放置在第0行第0列。下面XAML演示了Grid面板的使用:
```
1 <Window x:Class="WPFLayoutDemo.GridDemo"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="GridDemo" Height="300" Width="480">
5 <Grid Width="Auto" Height="Auto">
6 <Grid.RowDefinitions>
7 <RowDefinition Height="*"/>
8 <RowDefinition Height="Auto"/>
9 </Grid.RowDefinitions>
10 <Grid.ColumnDefinitions>
11 <ColumnDefinition Width="120"/>
12 <ColumnDefinition Width="150"/>
13 <ColumnDefinition Width="*"/>
14 <ColumnDefinition Width="2*"/>
15 </Grid.ColumnDefinitions>
16 <Rectangle Grid.Row="0" Grid.Column="0" Fill="Green" Margin="10,10,10,20"/>
17 <Rectangle Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2" Fill="Blue" Margin="10,10,10,20"/>
18 <Rectangle Grid.Row="0" Grid.Column="4" Fill="Orange"/>
19 <Button Grid.Row="1" Grid.Column="0">Button 2</Button>
20 <Rectangle Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" Fill="Red"/>
21 </Grid>
22 </Window>
```
定義Grid的列寬和行高可采用固定、自動和按比例三種方式定義。
第一種:固定長度——寬度不夠時,元素會被裁剪,單位是pixel;
第二種:自動長度——自動匹配行中最寬元素的高度。
第三種:比例長度——"*"表示占用剩余的全部寬度或高度,兩行都是*,則將剩余高度平分。像上面的一個2*,一個*,表示前者2/3寬度。
其運行效果如下圖所示:

## 3.7 UniformGrid 布局控件
UniformGrid是Grid簡化版本,不像Grid面板,UniformGrid不需要預先定義行集合和列集合,反而,通過簡單設置Rows和Columns屬性來設置尺寸。每個單元格始終具有相同的大小。UniformGrid每個單元格只能容納一個元素,將自動按照在其內部的元素個數,自動創建行和列,并通過保存相同的行列數。
下面XAML演示了UniformGrid控件的使用:
```
1 <Window x:Class="WPFLayoutDemo.UniformGridDemo"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="UniformGridDemo" Height="300" Width="300">
5 <UniformGrid>
6 <Ellipse Margin="10" Fill="Gray"/>
7 <Ellipse Margin="10" Fill="Gray"/>
8 <Ellipse Margin="10" Fill="Green"/>
9 <Ellipse Margin="10" Fill="Green"/>
10 <Ellipse Margin="10" Fill="Red"/>
11 </UniformGrid>
12 </Window>
```
在上面,并沒有顯示指定UniformGrid的行和列數,此時UniformGrid將自動按照元素的個數,自動創建行和列。運行效果如下圖所示。最好是顯式指定Rows和Columns屬性,這樣才能確保布局是按照你的思路去進行的。

## 3.8 ScrollViewer 控件
通常用戶界面中的內容比計算機屏幕的顯示區域大的時候,可以利用[ScrollViewer](http://msdn.microsoft.com/zh-cn/library/system.windows.controls.scrollviewer(v=vs.110).aspx)控件可以方便地使應用程序中的內容具備滾動功能。具體的使用示例如下所示:
```
1 <Window x:Class="WPFLayoutDemo.ScrollViewerDemo"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 Title="ScrollViewerDemo" Height="300" Width="300">
5 <Grid>
6 <ScrollViewer **HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Auto"**>
7 <Rectangle Width="500" Height="400" Fill="Green"/>
8 </ScrollViewer>
9 </Grid>
10 </Window>
```
運行效果如下圖所示:

## 四、布局綜合運用
前面例子都是單獨介紹每個布局控件的,然而在實際開發中,程序的界面布局都是由多個布局控件一起來完成的,這里演示一個綜合實驗的小例子。要實現的效果圖如下所示:

具體的XAML代碼實現如下所示:
```
1 <Window x:Class="WPFLayoutDemo.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 WindowStartupLocation="CenterScreen"
5 Title="布局綜合運用實例" Height="400" Width="480">
6 <DockPanel Width="Auto" Height="Auto" LastChildFill="True">
7 <!--頂部菜單區域-->
8 <Menu Width="Auto" Height="20" Background="LightGray" DockPanel.Dock="Top">
9 <!--File菜單項-->
10 <MenuItem Header="文件">
11 <MenuItem Header="保存"/>
12 <Separator/>
13 <MenuItem Header="退出"/>
14 </MenuItem>
15 <!--About 菜單項-->
16 <MenuItem Header="幫助">
17 <MenuItem Header="關于本產品"/>
18 </MenuItem>
19 </Menu>
20
21 <!--狀態欄-->
22 <StackPanel Width="Auto" Height="25" Background="LightGray" Orientation="Horizontal" DockPanel.Dock="Bottom">
23 <Label Width="Auto" Height="Auto" Content="狀態欄" FontFamily="Arial" FontSize="12"/>
24 </StackPanel>
25 <!--Left-->
26 <StackPanel Width="130" Height="Auto" Background="Gray" DockPanel.Dock="Left">
27 <Button Margin="10" Width="Auto" Height="30" Content="導航欄"/>
28 <Button Margin="10" Width="Auto" Height="30" Content="導航欄"/>
29 <Button Margin="10" Width="Auto" Height="30" Content="導航欄"/>
30 </StackPanel>
31
32 <!--Right-->
33 <Grid Width="Auto" Height="Auto" Background="White">
34
35 <Grid.ColumnDefinitions>
36 <ColumnDefinition Width="*"/>
37 <ColumnDefinition Width="*"/>
38 </Grid.ColumnDefinitions>
39
40 <Grid.RowDefinitions>
41 <RowDefinition Height="*"/>
42 <RowDefinition Height="*"/>
43 </Grid.RowDefinitions>
44
45 <Rectangle Fill="Gray" Margin="10,10,10,10" Grid.Row="0" Grid.Column="0"/>
46 <Rectangle Fill="Gray" Margin="10,10,10,10" Grid.Row="0" Grid.Column="1"/>
47 <Rectangle Fill="Gray" Margin="10,10,10,10" Grid.Row="1" Grid.Column="0"/>
48 <Rectangle Fill="Gray" Margin="10,10,10,10" Grid.Row="1" Grid.Column="1"/>
49 </Grid>
50 </DockPanel>
51
52 </Window>
```
## 五、自定義布局控件
在實際開發中,自然少不了自定義控件的開發,下面介紹下如何自定義布局控件。在前面介紹過布局系統的工作原理是先測量后排列,測量即是確定面板需要多大空間,排列則是定義面板內子元素的排列規則。所以,要實現自定義布局控件,需要繼承于Panel類并重寫MeasureOverride和ArrangeOverride方法即可,下面實現了一個簡單的自定義布局控件:
```
1 namespace CustomLayoutControl
2 {
3 public class CustomStackPanel: Panel
4 {
5 public CustomStackPanel()
6 : base()
7 {
8 }
9
10 // 重寫默認的Measure方法
11 // avaiableSize是自定義布局控件的可用大小
12 protected override Size MeasureOverride(Size availableSize)
13 {
14 Size panelDesiredSize = new Size();
15 foreach (UIElement child in this.InternalChildren)
16 {
17 child.Measure(availableSize);
18
19 // 子元素的期望大小
20 panelDesiredSize.Width += child.DesiredSize.Width;
21 panelDesiredSize.Height += child.DesiredSize.Height;
22 }
23
24 return panelDesiredSize;
25 }
26
27 // 重寫默認的Arrange方法
28 protected override Size ArrangeOverride(Size finalSize)
29 {
30 double x = 10;
31 double y = 10;
32 foreach (UIElement child in this.InternalChildren)
33 {
34 // 排列子元素的位置
35 child.Arrange(new Rect(new Point(x, y), new Size(finalSize.Width - 10, child.DesiredSize.Height)));
36 y += child.RenderSize.Height + 5;
37 }
38
39 return finalSize;
40 }
41 }
42 }
```
控件的最終大小和位置是由該控件和父控件共同完成的,父控件會先給子控件提供可用大小(MeasureOverride中availableSize參數),子控件再反饋給父控件一個自己的期望值(DesiredSize),父控件最后根據自己所擁有的空間大小與子控件期望的值分配一定的空間給子控件并返回自己的大小。這個過程是通過MeasureOverride和ArrangeOverride這兩個方法共同完成的,這里需要注意:父控件的availableSize是減去Margin、Padding等的值。
接下來,創建一個測試上面自定義布局控件的WPF項目,然后添加自定義布局控件的程序集,然后在WPF項目中MainWindows添加如下代碼:
```
1 <Window x:Class="TestCustomerPanel.MainWindow"
2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4 ** xmlns:custom="clr-namespace:CustomLayoutControl;assembly=CustomLayoutControl"**
5 Title="測試自定義布局控件" Height="350" Width="525">
6 <custom:CustomStackPanel Background="Red">
7 <Button Content="Button 1"></Button>
8 <Button Content="Button 2"></Button>
9 <Button Content="Button 3"></Button>
10 </custom:CustomStackPanel>
11 </Window>
```
運行成功后的效果如下圖所示:

## 六、小結
到這里,WPF布局的內容就介紹結束了,這里最后只是簡單地定義了一個類似StackPanel的布局控件,你還可以自定義更加復雜的布局控件,關于更復雜的自定義控件,你可以參考如下一些文章。在下面一篇文章將分享WPF中依賴屬性的內容。
* [FishEyePanel/FanPanel](http://www.codeproject.com/Articles/15705/FishEyePanel-FanPanel-Examples-of-custom-layout-pa)
* [PlotPanel](http://msdn2.microsoft.com/en-us/library/ms771626.aspx), Windows SDK Sample
本文所有源碼下載:[WPFLayouDemo.zip](http://files.cnblogs.com/zhili/WPFLayouDemo.zip)
- C# 基礎知識系列
- C# 基礎知識系列 專題一:深入解析委托——C#中為什么要引入委托
- C# 基礎知識系列 專題二:委托的本質論
- C# 基礎知識系列 專題三:如何用委托包裝多個方法——委托鏈
- C# 基礎知識系列 專題四:事件揭秘
- C# 基礎知識系列 專題五:當點擊按鈕時觸發Click事件背后發生的事情
- C# 基礎知識系列 專題六:泛型基礎篇——為什么引入泛型
- C# 基礎知識系列 專題七: 泛型深入理解(一)
- C# 基礎知識系列 專題八: 深入理解泛型(二)
- C# 基礎知識系列 專題九: 深入理解泛型可變性
- C#基礎知識系列 專題十:全面解析可空類型
- C# 基礎知識系列 專題十一:匿名方法解析
- C#基礎知識系列 專題十二:迭代器
- C#基礎知識 專題十三:全面解析對象集合初始化器、匿名類型和隱式類型
- C# 基礎知識系列 專題十四:深入理解Lambda表達式
- C# 基礎知識系列 專題十五:全面解析擴展方法
- C# 基礎知識系列 專題十六:Linq介紹
- C#基礎知識系列 專題十七:深入理解動態類型
- 你必須知道的異步編程 C# 5.0 新特性——Async和Await使異步編程更簡單
- 全面解析C#中參數傳遞
- C#基礎知識系列 全面解析C#中靜態與非靜態
- C# 基礎知識系列 C#中易混淆的知識點
- C#進階系列
- C#進階系列 專題一:深入解析深拷貝和淺拷貝
- C#進階系列 專題二:你知道Dictionary查找速度為什么快嗎?
- C# 開發技巧系列
- C# 開發技巧系列 使用C#操作Word和Excel程序
- C# 開發技巧系列 使用C#操作幻燈片
- C# 開發技巧系列 如何動態設置屏幕分辨率
- C# 開發技巧系列 C#如何實現圖片查看器
- C# 開發技巧 如何防止程序多次運行
- C# 開發技巧 實現屬于自己的截圖工具
- C# 開發技巧 如何使不符合要求的元素等于離它最近的一個元素
- C# 線程處理系列
- C# 線程處理系列 專題一:線程基礎
- C# 線程處理系列 專題二:線程池中的工作者線程
- C# 線程處理系列 專題三:線程池中的I/O線程
- C# 線程處理系列 專題四:線程同步
- C# 線程處理系列 專題五:線程同步——事件構造
- C# 線程處理系列 專題六:線程同步——信號量和互斥體
- C# 多線程處理系列專題七——對多線程的補充
- C#網絡編程系列
- C# 網絡編程系列 專題一:網絡協議簡介
- C# 網絡編程系列 專題二:HTTP協議詳解
- C# 網絡編程系列 專題三:自定義Web服務器
- C# 網絡編程系列 專題四:自定義Web瀏覽器
- C# 網絡編程系列 專題五:TCP編程
- C# 網絡編程系列 專題六:UDP編程
- C# 網絡編程系列 專題七:UDP編程補充——UDP廣播程序的實現
- C# 網絡編程系列 專題八:P2P編程
- C# 網絡編程系列 專題九:實現類似QQ的即時通信程序
- C# 網絡編程系列 專題十:實現簡單的郵件收發器
- C# 網絡編程系列 專題十一:實現一個基于FTP協議的程序——文件上傳下載器
- C# 網絡編程系列 專題十二:實現一個簡單的FTP服務器
- C# 互操作性入門系列
- C# 互操作性入門系列(一):C#中互操作性介紹
- C# 互操作性入門系列(二):使用平臺調用調用Win32 函數
- C# 互操作性入門系列(三):平臺調用中的數據封送處理
- C# 互操作性入門系列(四):在C# 中調用COM組件
- CLR
- 談談: String 和StringBuilder區別和選擇
- 談談:程序集加載和反射
- 利用反射獲得委托和事件以及創建委托實例和添加事件處理程序
- 談談:.Net中的序列化和反序列化
- C#設計模式
- UML類圖符號 各種關系說明以及舉例
- C#設計模式(1)——單例模式
- C#設計模式(2)——簡單工廠模式
- C#設計模式(3)——工廠方法模式
- C#設計模式(4)——抽象工廠模式
- C#設計模式(5)——建造者模式(Builder Pattern)
- C#設計模式(6)——原型模式(Prototype Pattern)
- C#設計模式(7)——適配器模式(Adapter Pattern)
- C#設計模式(8)——橋接模式(Bridge Pattern)
- C#設計模式(9)——裝飾者模式(Decorator Pattern)
- C#設計模式(10)——組合模式(Composite Pattern)
- C#設計模式(11)——外觀模式(Facade Pattern)
- C#設計模式(12)——享元模式(Flyweight Pattern)
- C#設計模式(13)——代理模式(Proxy Pattern)
- C#設計模式(14)——模板方法模式(Template Method)
- C#設計模式(15)——命令模式(Command Pattern)
- C#設計模式(16)——迭代器模式(Iterator Pattern)
- C#設計模式(17)——觀察者模式(Observer Pattern)
- C#設計模式(18)——中介者模式(Mediator Pattern)
- C#設計模式(19)——狀態者模式(State Pattern)
- C#設計模式(20)——策略者模式(Stragety Pattern)
- C#設計模式(21)——責任鏈模式
- C#設計模式(22)——訪問者模式(Vistor Pattern)
- C#設計模式(23)——備忘錄模式(Memento Pattern)
- C#設計模式總結
- WPF快速入門系列
- WPF快速入門系列(1)——WPF布局概覽
- WPF快速入門系列(2)——深入解析依賴屬性
- WPF快速入門系列(3)——深入解析WPF事件機制
- WPF快速入門系列(4)——深入解析WPF綁定
- WPF快速入門系列(5)——深入解析WPF命令
- WPF快速入門系列(6)——WPF資源和樣式
- WPF快速入門系列(7)——深入解析WPF模板
- WPF快速入門系列(8)——MVVM快速入門
- WPF快速入門系列(9)——WPF任務管理工具實現
- ASP.NET 開發
- ASP.NET 開發必備知識點(1):如何讓Asp.net網站運行在自定義的Web服務器上
- ASP.NET 開發必備知識點(2):那些年追過的ASP.NET權限管理
- ASP.NET中實現回調
- 跟我一起學WCF
- 跟我一起學WCF(1)——MSMQ消息隊列
- 跟我一起學WCF(2)——利用.NET Remoting技術開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(3)——利用Web Services開發分布式應用
- 跟我一起學WCF(4)——第一個WCF程序
- 跟我一起學WCF(5)——深入解析服務契約 上篇
- 跟我一起學WCF(6)——深入解析服務契約 下篇
- 跟我一起學WCF(7)——WCF數據契約與序列化詳解
- 跟我一起學WCF(8)——WCF中Session、實例管理詳解
- 跟我一起學WCF(9)——WCF回調操作的實現
- 跟我一起學WCF(10)——WCF中事務處理
- 跟我一起學WCF(11)——WCF中隊列服務詳解
- 跟我一起學WCF(12)——WCF中Rest服務入門
- 跟我一起學WCF(13)——WCF系列總結
- .NET領域驅動設計實戰系列
- .NET領域驅動設計實戰系列 專題一:前期準備之EF CodeFirst
- .NET領域驅動設計實戰系列 專題二:結合領域驅動設計的面向服務架構來搭建網上書店
- .NET領域驅動設計實戰系列 專題三:前期準備之規約模式(Specification Pattern)
- .NET領域驅動設計實戰系列 專題四:前期準備之工作單元模式(Unit Of Work)
- .NET領域驅動設計實戰系列 專題五:網上書店規約模式、工作單元模式的引入以及購物車的實現
- .NET領域驅動設計實戰系列 專題六:DDD實踐案例:網上書店訂單功能的實現
- .NET領域驅動設計實戰系列 專題七:DDD實踐案例:引入事件驅動與中間件機制來實現后臺管理功能
- .NET領域驅動設計實戰系列 專題八:DDD案例:網上書店分布式消息隊列和分布式緩存的實現
- .NET領域驅動設計實戰系列 專題九:DDD案例:網上書店AOP和站點地圖的實現
- .NET領域驅動設計實戰系列 專題十:DDD擴展內容:全面剖析CQRS模式實現
- .NET領域驅動設計實戰系列 專題十一:.NET 領域驅動設計實戰系列總結