深入淺出WPF——如何實現類的Property與標籤的Attribute映射

小序:
咳咳,我知道這個標題不太好讓人明白。
它的意思是這樣——我們知道,用C#代碼編寫的類也可以在XAML文檔裏聲明實例,聲明之後我們可以使用XAML的Attribute對實例的 Property進行賦值。但XAML標籤的Attribute只能接受string類型的值,如果像int、double這類簡單的值還好辦,如果是復 雜的值呢?我們應該怎麼辦?
 
正文:
我們知道,XAML標籤會對應一個實例。如果在XAML裏初始化實例的屬性,我們有兩種語法可以選擇:
  • 直接使用Attribute="Value"的方法
  • 屬性元素(Property Element)方法
今天我們討論的核心就是——第一種方法是如何實現的。
先看一個例子。我爲一個Grid設置了矢量漸變畫刷:
  1.     <Grid>
  2.         <Grid.Background>
  3.             <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
  4.                 <GradientStop Offset="0" Color="White"/>
  5.                 <GradientStop Offset="0.5" Color="LawnGreen"/>
  6.                 <GradientStop Offset="1" Color="White"/>
  7.             </LinearGradientBrush>
  8.         </Grid.Background>
  9.     </Grid>
效果是這樣:
 
請大家注意StartPoint="0,0" EndPoint="1,1這兩個Attribute,它們實際上對應的是實例的兩個屬性。如果查看MSDN,你會發現這兩個屬性的數據類型是Point而不是String。那麼,一個string類型值是如何被轉換成Point類型值的呢?
 
讓我們自己動手DIY一個!
 
首先,我們準備了一個類:
 
  1.     public class Human
  2.     {
  3.         public string Name { getset; }
  4.         public Human Child { getset; }
  5.     }
這個類具有兩個屬性
  • string類型的Name
  • Human類型的Child
現在我的期望是,如果我在XAML裏這樣寫:
  1.     <Window.Resources>
  2.         <local:Human x:Key="human" Child="ABC"/>
  3.     </Window.Resources>
則能夠爲Human實例的Child賦一個Human類型的值,並且Child.Name就是這個字符串的值。
我們先看看直接寫行不行……
我在UI上添加了一個按鈕button1,並在它的Click事件處理器裏寫上:
  1.         private void button1_Click(object sender, RoutedEventArgs e)
  2.         {
  3.             Human h = (Human)this.FindResource("human");
  4.             MessageBox.Show(h.Child.Name);
  5.         }
編譯沒有問題,但在我點擊按鈕之後程序拋出異常——告訴我Child不存在。那我們應該怎麼做呢?
辦法是使用TypeConverter和TypeConverterAttribute這兩個類。
 
首先,我們要從TypeConverter類派生出自己的類,並重寫它的一個ConvertFrom方法。這個方法有一個參數名爲value,這個值就是在XAML文檔裏爲它設置的值。我們要做的就是把這個值“翻譯”成合適類型的值、賦給對象的屬性:
  1.     public class StringToHumanTypeConverter : TypeConverter
  2.     {
  3.         public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
  4.         {
  5.             if (value is string)
  6.             {
  7.                 Human h = new Human();
  8.                 h.Name = value as string;
  9.                 return h;
  10.             }
  11.             return base.ConvertFrom(context, culture, value);
  12.         }
  13.     }
有了這個類還不夠,還要使用TypeConverterAttribute這個特徵類把StringToHumanTypeConverter這個類“粘貼”到作爲目標的Human類上。
  1.     [TypeConverterAttribute(typeof(StringToHumanTypeConverter))]
  2.     public class Human
  3.     {
  4.         public string Name { getset; }
  5.         public Human Child { getset; }
  6.     }
因爲特徵類在使用的時候可以省略Attribute這個詞,所以我們也可以寫成:
  1.     [TypeConverter(typeof(StringToHumanTypeConverter))]
  2.     public class Human
  3.     {
  4.         public string Name { getset; }
  5.         public Human Child { getset; }
  6.     }
但這樣寫,我們需要認清寫在方括號裏的是TypeConverterAttribute而不是TypeConverter。
 
完成之後,再次點擊按鈕,我們想要的結果就出來了!
 
 
 
TO BE CONTINUED...
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章