背水一戰 Windows 10 之 控制項(自定義控制項): 自定義控制項的基礎知識,依賴屬性和附加屬性 ...
背水一戰 Windows 10 (78) - 自定義控制項: 基礎知識, 依賴屬性, 附加屬性
作者:webabcd
介紹
背水一戰 Windows 10 之 控制項(自定義控制項)
- 自定義控制項的基礎知識,依賴屬性和附加屬性
示例
演示自定義控制項的基礎知識,依賴屬性和附加屬性
1、自定義控制項的示例
/MyControls/themes/generic.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <!-- 在 themes/generic.xaml 中定義自定義控制項的預設樣式 --> <ResourceDictionary.MergedDictionaries> <!-- 註意: 此處在指定 xaml 路徑時,要以“項目名”為根路徑(因為這個自定控制項的項目是要被別的項目引用的) 這個是對的 ms-appx:///MyControls/themes/MyControl1.xaml 這個是錯的 ms-appx:///themes/MyControl1.xaml(編譯時不會報錯,運行時會報錯 Failed to assign to property 'Windows.UI.Xaml.ResourceDictionary.Source' because the type 'Windows.Foundation.String' cannot be assigned to the type 'Windows.Foundation.Uri') --> <ResourceDictionary Source="ms-appx:///MyControls/themes/MyControl1.xaml"/> <ResourceDictionary Source="ms-appx:///MyControls/themes/MyControl3.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>
/MyControls/themes/MyControl1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:MyControls"> <Style TargetType="local:MyControl1"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:MyControl1"> <!-- 綁定基類中定義的依賴屬性 --> <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> <StackPanel> <!-- 綁定自定義依賴屬性 --> <TextBlock Text="{TemplateBinding Title}" Foreground="White" FontSize="24" /> <!-- 綁定自定義附加屬性 --> <TextBlock Text="{TemplateBinding local:MyAttachedProperty.SubTitle}" Foreground="Orange" FontSize="24" /> </StackPanel> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>
/MyControls/MyAttachedProperty.cs
/* * 定義一個附加屬性(Attached Property) * * 依賴屬性:可以用於樣式, 模板, 綁定, 動畫 * 附加屬性:全局可用的依賴屬性 */ using Windows.UI.Xaml; namespace MyControls { /// <summary> /// 定義一個附加屬性(Attached Property) /// </summary> public sealed class MyAttachedProperty { // 獲取附加屬性 public static string GetSubTitle(DependencyObject obj) { return (string)obj.GetValue(SubTitleProperty); } // 設置附加屬性 public static void SetSubTitle(DependencyObject obj, string value) { obj.SetValue(SubTitleProperty, value); } // 註冊一個附加屬性(winrc 中不支持 public 類型的 field,如果是 dll 項目則無此限制) private static readonly DependencyProperty SubTitlePropertyField = DependencyProperty.RegisterAttached( "SubTitle", // 附加屬性的名稱 typeof(string), // 附加屬性的數據類型 typeof(MyAttachedProperty), // 附加屬性所屬的類 new PropertyMetadata("", PropertyMetadataCallback)); // 指定附加屬性的預設值,以及值發生改變時所調用的方法 // 用屬性的方式封裝一下 SubTitlePropertyField public static DependencyProperty SubTitleProperty { get { return SubTitlePropertyField; } } private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args) { object newValue = args.NewValue; // 發生改變之後的值 object oldValue = args.OldValue; // 發生改變之前的值 } } }
/MyControls/MyControl1.cs
/* * 開發一個自定義控制項,並定義一個依賴屬性(Dependency Property) * * 依賴屬性:可以用於樣式, 模板, 綁定, 動畫 * 附加屬性:全局可用的依賴屬性 */ using Windows.UI.Xaml.Controls; using Windows.UI.Xaml; namespace MyControls { /// <summary> /// 開發一個自定義控制項,並定義一個依賴屬性(Dependency Property) /// </summary> // 註意: // 在 winrc 中用 c# 寫的類必須是 sealed 的(否則編譯時會報錯 Exporting unsealed types is not supported.Please mark type 'MyControls.MyControl1' as sealed) // 如果是 dll 項目則無此限制 public sealed class MyControl1 : Control { public MyControl1() { // 指定預設樣式為 typeof(MyControl1),即使用 TargetType 為 MyControl1 的樣式,即 <Style xmlns:local="using:MyControls" TargetType="local:MyControl1" /> // 如果不指 DefaultStyleKey 的話,則預設使用基類即 Control 的樣式 this.DefaultStyleKey = typeof(MyControl1); } // 通過 DependencyObject.GetValue() 和 DependencyObject.SetValue() 訪問依賴屬性,這裡由 Title 屬性封裝一下,以方便對依賴屬性的訪問 public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } // 註冊一個依賴屬性 // 註意: // 在 winrc 中不支持 public 類型的 field(在 dll 項目無此限制),所以這裡改為 private 的,之後再用 public 屬性的方式封裝一下即可 // 如果使用了 public 類型的 field 的話,編譯時會報錯 Type 'MyControls.MyControl1' contains externally visible field 'Windows.UI.Xaml.DependencyProperty MyControls.MyControl1.TitlePropertyField'. Fields can be exposed only by structures private static readonly DependencyProperty TitlePropertyField = DependencyProperty.Register( "Title", // 依賴屬性的名稱 typeof(string), // 依賴屬性的數據類型 typeof(MyControl1), // 依賴屬性所屬的類 new PropertyMetadata("", PropertyMetadataCallback)); // 指定依賴屬性的預設值,以及值發生改變時所調用的方法 // 用屬性的方式封裝一下 TitlePropertyField public static DependencyProperty TitleProperty { get { return TitlePropertyField; } } private static void PropertyMetadataCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args) { object newValue = args.NewValue; // 發生改變之後的值 object oldValue = args.OldValue; // 發生改變之前的值 } } }
2、調用自定義控制項的示例
Controls/CustomControl/Demo1.xaml
<Page x:Class="Windows10.Controls.CustomControl.Demo1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Windows10.Controls.CustomControl" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" xmlns:myControls="using:MyControls"> <Grid Background="Transparent"> <StackPanel Margin="10 0 10 10"> <!-- 演示自定義控制項的基礎知識,依賴屬性和附加屬性 本例所用到的自定義控制項請參看:MyControls/MyControl1.cs --> <!-- 依賴屬性和附加屬性可以用於綁定 --> <myControls:MyControl1 x:Name="control1" Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="200" HorizontalAlignment="Left" Margin="5" Title="{Binding Value, ElementName=slider}" myControls:MyAttachedProperty.SubTitle="{Binding Value, ElementName=slider}"> </myControls:MyControl1> <Slider Name="slider" Width="200" Minimum="0" Maximum="200" IsThumbToolTipEnabled="False" HorizontalAlignment="Left" Margin="5" Foreground="Orange" Background="White" Style="{StaticResource MySliderStyle}" /> <!-- 依賴屬性和附加屬性可以用於 Storyboard 動畫 但是無法通過 Storyboard 對自定義附加屬性做動畫,在文檔中找到了這樣一句話“However, an existing limitation of the Windows Runtime XAML implementation is that you cannot animate a custom attached property.” --> <myControls:MyControl1 x:Name="control2" Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="200" HorizontalAlignment="Left" Margin="5"> <myControls:MyControl1.Resources> <BeginStoryboard x:Name="storyboard1"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetName="control2" Storyboard.TargetProperty="Title" Duration="0:0:10" RepeatBehavior="Forever"> <DiscreteObjectKeyFrame KeyTime="0:0:1" Value="w" /> <DiscreteObjectKeyFrame KeyTime="0:0:2" Value="we" /> <DiscreteObjectKeyFrame KeyTime="0:0:3" Value="web" /> <DiscreteObjectKeyFrame KeyTime="0:0:4" Value="weba" /> <DiscreteObjectKeyFrame KeyTime="0:0:5" Value="webab" /> <DiscreteObjectKeyFrame KeyTime="0:0:6" Value="webabc" /> <DiscreteObjectKeyFrame KeyTime="0:0:7" Value="webabcd" /> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </myControls:MyControl1.Resources> </myControls:MyControl1> <!-- 在 code-behind 中設置依賴屬性和附加屬性 --> <myControls:MyControl1 x:Name="control3" Background="Blue" BorderBrush="Yellow" BorderThickness="1" Width="200" HorizontalAlignment="Left" Margin="5" /> </StackPanel> </Grid> </Page>
Controls/CustomControl/Demo1.xaml.cs
/* * 本例用於演示自定義控制項的基礎知識,依賴屬性和附加屬性 */ using MyControls; using Windows.UI.Xaml.Controls; namespace Windows10.Controls.CustomControl { public sealed partial class Demo1 : Page { public Demo1() { this.InitializeComponent(); this.Loaded += Demo1_Loaded; } private void Demo1_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e) { // 設置依賴屬性 control3.Title = "我是依賴屬性"; // 設置附加屬性 control3.SetValue(MyAttachedProperty.SubTitleProperty, "我是附加屬性"); } } }
OK
[源碼下載]