WPF学习:4.类型转换和标记扩展

  在上一章,主要介绍了Border和Brush,这一章主要介绍下类型转换和标记扩展。相关代码链接如下:

  http://files.cnblogs.com/keylei203/4.WPFSampleDemo.zip

Type Converter

  在XAML中,所有的对象都是字符串,XAML解析器通过类型转换器跨越字符和非字符的鸿沟,类型转换器就是将这些字符串转换为相应的CLR对象。

  WPF学习:4.类型转换和标记扩展

  所有类型转换器都是派生自TypeConverter,派生的类有100多个,比较常用的比如BrushConverter,就可以实现从字符串转换成相应的画刷,又如Margin,Margin=10,20,0,30,解析器会自动按照左,上,右,下的顺序将数据转换为宽度数据。

  TypeConverter都4个重要方法是CanConvertToCanConvertFromConvertToConvertFrom

  CanConvertTo:检测CLR对象是否能转换成相应的字符串。

  CanConvertFrom:检测能否从字符串转换成相应的CLR对象。

  ConvertTo:将CLR对象转换成相应的字符串。

  ConvertFrom:从字符串转换成相应的CLR对象。

  XAML解析器解析任何属性值时都包含两部分信息:Value Type-决定了字符串转化后的类型。Actual Value-属性值大小。解析器通过两个步骤来查找类型转换器:

  (1)检查属性声明查找TypeConvert特性,如窗口的Width和Height属性(派生自FrameworkElement)前面都会声明一个类型转换器。下面代码通过Reflector查看到的FrameworkElement的源代码片段:

1 public class FrameworkElement....

2 {

3     [......TypeConverter(typeof(LengthConverter))] 

4     public double Height{get;set;}

5     [......TypeConverter(typeof(LengthConverter))]

6     public double Width{get;set;}         

7 }

  (2)如果属性声明中没有TypeConverter特征,XAML解析器会检查对应的数据类型的类的声明。如按钮Background属性声明是Brush,并在Brush类头部就声明了一个BrushConverter转换器,这样在设置Background属性时XAML解析器会自动应用该转换器。下面代码为用过Reflector查看到的Brush片段。

1 [......TypeConverter(typeof(BrushConverter))......

2 public abstract class Brush:Animatable

Custom TypeConverter

  建立一个CustomTypeConverter必须建立一个新类,在我的例子中,我建立了一个具有Latitude和Longitude属性的类,这个类实现地理位置。

 1 [global::System.ComponentModel.TypeConverter(typeof(GeoPointConverter))]

 2     public class GeoPointItem

 3     {

 4         public double Latitude { get; set; }

 5         public double Longitude { get; set; }

 6 

 7         public GeoPointItem()

 8         {

 9         }

10 

11         public GeoPointItem(double lat, double lon)

12         {

13             this.Latitude = lat;

14             this.Longitude = lon;

15         }

16 

17         public static GeoPointItem Parse(string data)

18         {

19             if (string.IsNullOrEmpty(data)) return new GeoPointItem();

20 

21             string[] items = data.Split(',');

22             if (items.Count() != 2)

23                 throw new FormatException("GeoPoint should have both latitude 

24                 and longitude");

25 

26             double lat, lon;

27             try

28             {

29                 lat = Convert.ToDouble(items[0]);

30             }

31             catch (Exception ex) { 

32                 throw new FormatException("Latitude value cannot be converted", ex); 

33             }

34 

35             try

36             {

37                 lon = Convert.ToDouble(items[1]);

38             }

39             catch (Exception ex) { 

40                 throw new FormatException("Longitude value cannot be converted", ex); 

41             }

42 

43             return new GeoPointItem(lat, lon);

44         }

45 

46         public override string ToString()

47         {

48             return string.Format("{0},{1}", this.Latitude, this.Longitude);

49         }

50     }

  上面的类具有Latitude和Longitude两个double型属性,我重写了ToString(),这对于得到一个完整的字符串来说是非常重要的,Parse方法能够解析字符串格式到地理坐标。

  接下俩就是为这个类写一个TypeConverter,将实现4个方法,关键的是ConvertFrom方法,通过GeoPointItem静态方法Parse将字符串转化为正确的类型。

 1 public class GeoPointConverter : global::System.ComponentModel.TypeConverter

 2     {

 3 

 4         //should return true if sourcetype is string

 5         public override bool CanConvertFrom(

 6          System.ComponentModel.ITypeDescriptorContext context, Type sourceType)

 7         {

 8             if (sourceType is string)

 9                 return true;

10             return base.CanConvertFrom(context, sourceType);

11         }

12         //should return true when destinationtype if GeopointItem

13         public override bool CanConvertTo(

14              System.ComponentModel.ITypeDescriptorContext context, Type destinationType)

15         {

16             if (destinationType is string)

17                 return true;

18 

19             return base.CanConvertTo(context, destinationType);

20         }

21         //Actual convertion from string to GeoPointItem

22         public override object ConvertFrom(

23      System.ComponentModel.ITypeDescriptorContext context, 

24          System.Globalization.CultureInfo culture, object value)

25         {

26             if (value is string)

27             {

28                 try

29                 {

30                     return GeoPointItem.Parse(value as string);

31                 }

32                 catch (Exception ex)

33                 {

34                     throw new Exception(string.Format(

35       "Cannot convert '{0}' ({1}) because {2}", value, value.GetType(), ex.Message), ex);

36                 }

37             }

38 

39             return base.ConvertFrom(context, culture, value);

40         }

41 

42         //Actual convertion from GeoPointItem to string

43         public override object ConvertTo(

44          System.ComponentModel.ITypeDescriptorContext context, 

45           System.Globalization.CultureInfo culture, object value, Type destinationType)

46         {

47             if(destinationType == null)

48                 throw new ArgumentNullException("destinationType");

49     

50              GeoPointItem gpoint = value as GeoPointItem;

51 

52             if(gpoint != null)

53             if (this.CanConvertTo(context, destinationType))

54                 return gpoint.ToString();

55             

56             return base.ConvertTo(context, culture, value, destinationType);

57         }

58     }

  接下去是使用这个类型转化器的时候了,建立一个用户控件,添加一个GeoPoint属性:

 1 <Grid>

 2         <Grid.RowDefinitions>

 3             <RowDefinition/>

 4             <RowDefinition/>

 5         </Grid.RowDefinitions>

 6         <Grid.ColumnDefinitions>

 7             <ColumnDefinition/>

 8             <ColumnDefinition/>

 9         </Grid.ColumnDefinitions>

10         <TextBlock Text="Latitude" Grid.Row="0" Grid.Column="0"></TextBlock>

11         <TextBox x:Name="txtlat" MinWidth="40" Grid.Row="0" Grid.Column="1" 

12               TextChanged="txtlat_TextChanged"/>

13         <TextBlock Text="Longitude" Grid.Row="1" Grid.Column="0"></TextBlock>

14         <TextBox x:Name="txtlon" MinWidth="40" Grid.Row="1" Grid.Column="1" 

15              TextChanged="txtlon_TextChanged"/>

16     </Grid>

  控件拥有两个Textboxes显示Latutude和Longitude,当textBox内容发生修改时,GeopointItem值也会相应更改。

 1 public partial class GeoPoint : UserControl

 2 {

 3         public static readonly DependencyProperty GeoPointValueProperty = 

 4        DependencyProperty.Register("GeoPointValue", typeof(GeoPointItem), 

 5              typeof(GeoPoint), new PropertyMetadata(new GeoPointItem(0.0, 0.0)));

 6         public GeoPoint()

 7         {

 8             InitializeComponent();

 9         }

10        

11         public GeoPointItem GeoPointValue

12         {

13             get

14             {

15                 return this.GetValue(GeoPointValueProperty) as GeoPointItem;

16             }

17             set

18             {

19                 this.SetValue(GeoPointValueProperty, value);

20             }

21         }

22 

23         private void txtlat_TextChanged(object sender, TextChangedEventArgs e)

24         {

25             GeoPointItem item = this.GeoPointValue;

26 

27             item.Latitude = Convert.ToDouble(txtlat.Text);

28             this.GeoPointValue = item;

29         }

30 

31         private void txtlon_TextChanged(object sender, TextChangedEventArgs e)

32         {

33             GeoPointItem item = this.GeoPointValue;

34 

35             item.Longitude = Convert.ToDouble(txtlon.Text);

36             this.GeoPointValue = item;

37         }

38 

39         private void UserControl_Loaded(object sender, RoutedEventArgs e)

40         {

41             GeoPointItem item = this.GeoPointValue;

42             this.txtlat.Text = item.Latitude.ToString();

43             this.txtlon.Text = item.Longitude.ToString();

44 

45         }

46     }

  对于窗体,需要添加这个自定义控件,设置它的初值。

1 <converter:GeoPoint x:Name="cGeoPoint" GeoPointValue="60.5,20.5" />

Markup Extension

  MarkupExtension提供一个XAML属性的灵活性,XAML中只要属性值被{}括起,XAML解析器就会认为这是一个扩展标记,而不是一个普通的字符串。

Extension

  在System.Windows.Markup命名空间内已经有了一些标记扩展:WPF学习:4.类型转换和标记扩展  

NullExtention

  是XAML提供的一种标记扩展,表示一个空值,这可能是所有标记扩展中最简单的了。

Content = "{x:Null}"

ArrayExtension

  用来创建一个数组集合。

Values = {x:Array Type=sys:String}

StaticExtension

  返回一个静态字段和引用

Text="{x:Static Member=local:MyClass.StaticProperty}"

  当你定义一个MyClass类的静态属性时,你可以使用它来将属性自动的赋给Text。

TypeExtension

 

TargetType="{x:Type Button}" 

  获得一个button对象的类型

Reference

Text="{x:Reference Name=Myobject}"

  引用一个在XAML中声明的对象,.NET4.0特性

StaticResourceExtension

1 <Grid.Resources>

2 

3 <Color x:Key="rKeyBlack">Black</Color>

4 <SolidColorBrush Color="{StaticResource rKeyBlack}" x:Key="rKeyBlackBrush"/>

5 

6 

7 </Grid.Resources>

8 

9 <TextBlock Background="{StaticResource ResourceKey=rKeyBlackBrush}" />

DynamicResourceExtension

<TextBlock Background="{DynamicResource ResourceKey=rKeyBlackBrush}" />

  似水无痕:http://www.cnblogs.com/keylei203/

 

你可能感兴趣的:(类型转换)