WPF教程嘗試(修正部分格式)


抱歉,格式還是不夠順眼,從word復制過來,格式有了一些變化,雖然用Live Writer重排,但實在是麻煩。改天,我放Word附件上來。^_^

另外,請各位指點,教程怎樣寫,讀者會更有興趣。

01. 創建軟件雛形

這個雛形包括4個項目(Project):

  1. 一個主程序(WPF Application)項目,命名為:DataTracer
  2. 一個組件庫(WPF User Control Library)項目,命名為:K3UcLib
  3. 一個控件庫(WPF Custom Control Library)項目,命名為:K3CcLib
  4. 一個算法庫(Class Library)項目,命名為:K3Helper

作為入門,這看起來有點復雜,不過實現起來還算簡單。

菜單:File > New > Project…

 

clip_image001

clip_image003

菜單:File > Add > New Project…

clip_image005

clip_image007

clip_image009

THINKING:

通常,復雜是由簡單構成的,只要我們合理的分解它;
復雜的設計,並不意味着復雜的實現;同樣,簡單的設計,也不意味着簡單的實現;
不過,沒有准備迎接復雜挑戰的簡單設計,卻通常是小小噩夢的開始。

F5 運行,看看結果!

 

02. 制作一個組件

我習慣將User Control稱為組件,將Custom Control稱為控件。

他們的區分,簡單說:User Control通常通過組合多個控件產生,Custom Control通常通過擴展單個控件產生。

現在,我們先制作一個准備用來替換現有窗口標題的組件,命名為:K3WindowHeader。

Project à Add User Control,然后修改XAML,並編譯(Shift F6)

 

<Border CornerRadius="0, 0, 10, 10" Background="DarkBlue">

<DockPanel LastChildFill="True">

<Button Content="關閉" Width="75" Height="23" DockPanel.Dock="Right" />

<TextBlock Text="Window Header" DockPanel.Dock="Left" Foreground="White"/>

</DockPanel>

</Border>

這個組件包括兩個控件Button,TextBlock。

CornerRadius用於設定Border四個角的弧度

= ”LeftTop, RightTop, RightBottom, LeftBottom”

DockPanel.LastChildFill,很有用的屬性。

注意DockPanel所包含組件的順序,並在組件中正確的使用DockPanel.Dock屬性。

在DataTracer中使用這個組件。

Project à Add References,添加K3UcLib,然后修改MainWindow.XAML:

 

<Window …

xmlns:K3UcLib="clr-namespace:K3UcLib;assembly=K3UcLib"

WindowStyle="None"

>

<Grid>

<Grid.RowDefinitions>

<RowDefinition Height="Auto"/>

<RowDefinition Height="*"/>

<RowDefinition Height="Auto"/>

</Grid.RowDefinitions>

<K3UcLib:K3WindowHeader Height="25" />

</Grid>

將WindowStyle設為None,將窗口標題隱掉,從而為DIY新的窗口標題做好准備。

Height, Width可取值包括:

Auto(自適應),*(全部剩余),NaN(相當於Auto),數值

F5 à 運行,看看結果!

這個窗口怎么關掉?Alt + F4!

這個窗口好丑!別着急,如果你真的很急,可以先試着使用 Margin屬性及xxxAlignment屬性,調整一下位置(試一試我的調整,如下)。

 

<Border CornerRadius="0, 0, 10, 10" Background="DarkBlue" Margin="3,0,3,0">

<DockPanel LastChildFill="True">

<Button Content="關閉" Width="75" Height="23" DockPanel.Dock="Right" Margin="0, 0, 10, 0" HorizontalAlignment="Center" VerticalAlignment="Center" />

<TextBlock Text="Window Header" DockPanel.Dock="Left" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" />

</DockPanel>

</Border>

F5 à 運行,看看結果!

 

03. 添加事件,關閉窗口

需求:當用戶點擊“關閉”按鈕時,關閉主窗口。

實現:為“關閉”按鈕添加Click事件處理。有兩種實現方式:

(1) 通過XAML文件中實現:<Button Name=”buttonClose” Content=”” …… Click=”buttonClose_Click” …… />

(2) 通過后台代碼實現:this.buttonClose.Click += new new RoutedEventHandler(buttonClose_Click);

這里,我們采用后者,即后台代碼方式,完整代碼如下:

 

public K3WindowHeader() {

InitializeComponent();

this.Init();

}

void Init() {

this.buttonClose.Click += new RoutedEventHandler(Button_Click);

}

void Button_Click(object sender, RoutedEventArgs e) {

throw new NotImplementedException();

}

注:

使用Init()方法,是為了使代碼整潔。

在你鍵入“+=”時,系統將為你自動生成事件代碼。你可以先修改所生成的事件處理方法的名字,然后再按“TAB”鍵,這樣就可以生成你想要的名字的方法。在這里,我將默認的buttonClose_click改為Button_Click。

接下來,我們添加事件處理的內容,以實現關閉主窗體。

注意,因為我們使用的是另一個組件項目中的組件,而非主程序自身項目中的組件,所以實現起來稍微有點麻煩,不是簡單的一個Close()就可以完成。

在這種情況下,有多重實現方式:

(1) 假定組件自身知道自己是如何被使用的,如本案例中,它被放在主窗體的Grid中,那么可以這樣實現:

 

((this.Parent as Grid).Parent as Window).Close();

這種實現方式,屬於hard code,使組件失去了靈活性,不是一個好方法,但它是一個思路,即:只要你能找到你想要的,你就可以做你想做的。

(2) 將點擊“關閉”按鈕事件,轉化成一個新的事件,告訴引用這個組件的窗體:有人請求關掉你!這個設計有點麻煩,但使組件具有了組件該有的特性:靈活性,或稱為適應性,以保證你可以相對隨意的使用它。

 

#region >>>>> 自定義事件 ...

public static readonly RoutedEvent PreviewWindowHeaderEvent;

public event RoutedEventHandler PreviewWindowHeaderEventHandler {

add { this.AddHandler(PreviewWindowHeaderEvent, value); }

remove { this.RemoveHandler(PreviewWindowHeaderEvent, value); }

}

static K3WindowHeader() {

PreviewWindowHeaderEvent = EventManager.RegisterRoutedEvent(

"PreviewWindowHeaderEventHandler",

RoutingStrategy.Tunnel,

typeof(RoutedEventHandler),

typeof(K3WindowHeader));

}

#endregion

……

void Button_Click(object sender, RoutedEventArgs e) {

RoutedEventArgs eventArgs = new RoutedEventArgs();

eventArgs.RoutedEvent = PreviewWindowHeaderEvent;

RaiseEvent(eventArgs);

}

這段代碼,加在K3WindowHeader中。

#region #endregion的合理使用,有利於提升代碼的可讀性。你可以加上注釋。BTW,我添加>>>>> … 是為了美觀,讀者可以試試去掉它,或改變它,看看你自己更喜歡哪一個。

注意,我添加了static 類型的構造函數,以便注冊自定義事件。

Event有兩種類型,其關鍵參數是:RoutingStrategy,其取值的不同,將生成兩種傳遞方向不同事件。詳述如下:

     
 

public static readonly RoutedEvent PreviewWindowHeaderEvent;

public event RoutedEventHandler PreviewWindowHeaderEventHandler {

add { this.AddHandler(PreviewWindowHeaderEvent, value); }

remove { this.RemoveHandler(PreviewWindowHeaderEvent, value); }

}

static MainWindow() {

PreviewWindowHeaderEvent = K3WindowHeader.PreviewWindowHeaderEvent.AddOwner(typeof(MainWindow));

}

void Init() {

this.PreviewWindowHeaderEventHandler += new RoutedEventHandler(CustomEventHandler);

}

void CustomEventHandler(object sender, RoutedEventArgs e) {

this.Close();

}

這段代碼,加在DataTracer中。

注意這段代碼與上段代碼的不同,在於靜態構造中,我們通過事件的AddOwner方法,將這兩個自定義事件關聯起來,從而保證了可以捕獲到該事件。

同樣,我使用了Init來使代碼整潔,並在其中添加了對該特定事件的處理程序。別忘了將Init()放入構造函數中。

F5 à 運行,看看結果!

 


免責聲明!

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



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