2009年9月25日 星期五

在WPF中自訂事件(Event)

在WPF中自訂控制項很容易
但是如果自訂控制項的時候除了提供一些函式之外
有時候希望可以提供一些事件

自訂事件的概念基本上跟callback的概念是一樣的
也就是註冊一個事件處理函式給某個事件
當事件發生的時候可以觸發該事件處理函式(常見的像MouseDown, Click等)
.net2.0之後提供了很方便的EventHandler機制

參考在WPF中新增自訂控制項,我們先制定了一個新的控制項
這個控制項裡面只有一個Rectangle

<UserControl x:Class="test_wpf.NewButton"
...>
<Rectangle />
</UserControl>

因為Rectangle沒有Click事件,所以我們就幫這個控制項新增Click事件

首先,每個事件處理都具有兩個參數
sender代表是哪個物件被觸發了這個事件
而e則是代表該事件的一些特性(比如滑鼠事件都會攜帶滑鼠訊息)
所以如果不希望用已經被制定好的事件屬性的話
那就自訂一個繼承EventArgs的事件屬性

public class MsgEventArgs : EventArgs
{
/// the only string argument
private string _Msg;

/// constructor of the event argument
public MsgEventArgs(string s)
{
_Msg = s;
}

/// define a readonly string argument
public string Msg
{
get { return _Msg; }
}
}

這邊我們定義了一個只帶有一個字串的事件屬性
但如果沒有特別需要傳遞的資訊,那也可以直接用EventArgs類別
就不需要做上面這步驟

之後再新增的這個控制項中宣告一個使用這個事件屬性的事件

public partial class NewButton : UserControl
{
/// an event with our custom event argment
public event EventHandler<MsgEventArgs> Click;

/// original constructor
public NewButton()
{
InitializeComponent();
}
}

同樣的,如果不需要自訂自訂屬性的話
紅字的部分就可以省略

一般習慣來說,會為了每個事件作一個事件觸發函式
這函式可以宣告成virtual,以便之後如果有繼承的子類別可以直接修改

protected virtual void OnClick(MsgEventArgs e)
{
/// if there exists handler for the event, run it
if (Click != null)
{
Click(this, e);
}
}

接下來就是在適當的時間觸發這個事件就好了
因為是Click,所以我們在滑鼠按下又放開的時候觸發
(這邊只是示範,並不是一般嚴謹定義的Click)

/// flag to show if left button is down
private bool IsDown = false;

private void Rectangle_PreviewMouseLeftButtonDown(
object sender, MouseButtonEventArgs e)
{
/// left button is down
IsDown = true;
}

private void Rectangle_PreviewMouseLeftButtonUp(
object sender, MouseButtonEventArgs e)
{
if (IsDown)
{
/// left button is up after down, click
OnClick(new MsgEventArgs("Button Click"));
}

/// reset the flag
IsDown = false;
}

這樣就完成宣告了,接下來就是在使用這個控制項的時候
(參考在WPF的XAML裡面使用自訂的控制項)
定義相關的事件處理函式

<Window ...
xmlns:test_wpf="clr-namespace:test_wpf">
<test_wpf:NewButton Click="Btn_Click"/>
</Window>


private void Btn_Click(object sender, MsgEventArgs e)
{
Console.WriteLine(e.Msg);
}

因為我們只有一個message對應的事件處理
所以這邊的事件處理,我們只將他show到console上面
(可以參考在WPF中滑鼠事件(Event)傳遞中的設定)

--
參考資料
HOW TO:發行符合 .NET Framework 方針的事件 (C# 程式設計手冊)
C#的事件處理和自定義事件(轉)
C# - Delgate(委派)和Event(事件)

沒有留言:

張貼留言