- 將多個現有的控件組合成一個可重用的“組”。
- 由一個XAML文件和一個后台代碼文件。
- 不能使用樣式和模板。
- 繼承自UserControl類。
自定義控件(擴展)
- 在現有的控件上進行擴展,增加一些新的屬性方法等。
- 包括一個代碼文件和一個默認的主題文件。
- 可以使用樣式和模板。
- 構建控件庫的好方法。
UserControl主要是現有控件的組合。組合是好組合啊,我隨便拖幾個控件往頁面里面一放,比如我弄個TextBox和一個button往頁面里面一方,起個名字就是UserControl了,問題是這個UserControl光能看不能用啊。比如說我在WPF窗體里面要對這個UserControl里面的TextBox賦值或者獲取它的值,咋獲取?我想點擊UserControl里的Button來觸發這個UserControl所在的WPF窗體后台代碼文件里面(暫不提MVVM模式)的某個事件,怎么觸發?這兩個問題才是創建UserControl的關鍵問題。
第一個問題:獲取或設置屬性。
建立一個wpf用戶控件項目,在UserControl1.xaml里添加一個Button和TextBox。用戶控件默認繼承自UserControl類,你也可以修改他的所繼承的類。若修改為其他類,UserControl則將擁有這個類的相應的方法和屬性。這里先不修改,保持其默認的繼承。
現在的主要任務是當這個用戶控件放到WPF窗體里面后,在窗體里能獲取或設置里面的 TextBox的值。
關鍵的一步是為這個用戶控件添加一個依賴屬性。
比如我要給這個用戶控件添加一個Text屬性,即當我將這個用戶控件放到WPF窗口里要獲取或者設置它的Text屬性。
添加這個Text依賴屬性的代碼如下:
這樣就為這個用戶控件
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UserControl1), new PropertyMetadata("TextBox", new PropertyChangedCallback(OnTextChanged))); public string Text { get { return (string)GetValue(TextProperty); } set { SetValue(TextProperty, value); } } static void OnTextChanged(object sender, DependencyPropertyChangedEventArgs args) { UserControl1 source = (UserControl1)sender; source.tb.Text = (string)args.NewValue; }
增加了一個名字為Text的屬性。若你剛好正在做這方面或者學習這方面的東西,你通過搜索看到了這篇文章估計有人會直接把上面的代碼一下看實現了,心里很高興。這樣是很快,但是這是哪走了魚而不是漁。這里面主要的句代碼是
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(UserControl1), new PropertyMetadata("TextBox", new PropertyChangedCallback(OnTextChanged)));
然后主要是DependencyProperty.Register方法。
第一個參數,是你要為這個用戶控件增加的屬性的名字,即你在第一個參數里面填寫什么字符串將來你的用戶控件將會增加以這個字符串為名字的屬性。
第二個參數是指這個屬性對應的數據類型。
第三個參數這個屬性所有者的類型。
第四個參數屬性改變時觸發的回調事件。
這個方法及其參數弄懂后,就很容易來為用戶控件增加屬性了。
下面第二個大問題,事件傳閱。
比如我們想讓這個用戶控件暴露給窗體一個MyButtonClick事件。代碼如下
public static readonly RoutedEvent MyButtonClickEvent = EventManager.RegisterRoutedEvent("MyButtonClick", RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler<object>), typeof(UserControl1)); public event RoutedPropertyChangedEventHandler<object> MyButtonClick { add { this.AddHandler(MyButtonClickEvent, value); } remove { this.RemoveHandler(MyButtonClickEvent, value); } } public void OnMyButtonClick(object oldValue, object newValue) { RoutedPropertyChangedEventArgs<object> arg = new RoutedPropertyChangedEventArgs<object>(oldValue, newValue, MyButtonClickEvent); this.RaiseEvent(arg); }
這樣通過這兩段代碼你的用戶控件就得到了一個Text屬性和一個MyButtonClick方法。
請注意以上兩段代碼中,特別是第二段注冊事件的代碼中要特別注意,當你的用戶控件繼承的基類不同時,注冊事件時可能所用的參數和事件的類型會有所不同,比如msdn上有個例子是繼承自Button的,其中的事件類型和參數就不同:
public class MyButtonSimple: Button { // Create a custom routed event by first registering a RoutedEventID // This event uses the bubbling routing strategy public static readonly RoutedEvent TapEvent = EventManager.RegisterRoutedEvent( "Tap", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyButtonSimple)); // Provide CLR accessors for the event public event RoutedEventHandler Tap { add { AddHandler(TapEvent, value); } remove { RemoveHandler(TapEvent, value); } } // This method raises the Tap event void RaiseTapEvent() { RoutedEventArgs newEventArgs = new RoutedEventArgs(MyButtonSimple.TapEvent); RaiseEvent(newEventArgs); } // For demonstration purposes we raise the event when the MyButtonSimple is clicked protected override void OnClick() { RaiseTapEvent(); } }