本文主要讲解如何使用IValueConverter和TypeConverter。我们通过两个思考问题来引入如何使用IValueConverter和TypeConverter!
IValueConverter主要用于将数据源的数据转换为需要在界面上显示的数据,例如:将Url地址转换为图片显示到界面上、将float类型数据显示为货币类型、bool值和Visibility转换等等。
TypeConverter主要用于在XAML代码中的字符串类型转换为其他类型的数值,比如将一段字符串转为Double类型以供Width属性使用。
思考一:我的数据集合的其中一个集合中的属性为某个图片的URL,如何将这个URL地址转换为图片显示到DataGrid行中呢?
IValueConverter的使用方法:
一、首先编写一个ImageConverter类型,此类继承于IValueConverter接口,然后实现此接口的Convert和 ConvertBack方法。注意Convert方法是将数据源的数据转为需要显示的数据,而ConvertBack方法用于将显示出来的数据在 TwoWay模式下回传给数据源。如下面的代码以编制:
- public class ImageConverter : IValueConverter
- {
- //在载入数据的时候将数据转换为图片类型
- public object Convert(object value, Type targetType, object parameter,
- System.Globalization.CultureInfo culture)
- {
- try
- {
- Uri uri = new Uri((string)value, UriKind.RelativeOrAbsolute);
- BitmapImage img = new BitmapImage(uri);
- return img;
- }
- catch
- {
- return new BitmapImage();
- }
- }
- //在页面上操作的时候,将图片类型转换为数据,这里只有再TwoWay的时候才有用
- public object ConvertBack(object value, Type targetType, object parameter,
- System.Globalization.CultureInfo culture)
- {
- BitmapImage img = value as BitmapImage;
- return img.UriSource.AbsoluteUri;
- }
- }
二、在UserControl的资源中申明ImageConverter以供DataGrid的数据源绑定时转换数据
- <UserControl.Resources>
- <this:ImageConverter x:Key="ImageCoverter"/>
- </UserControl.Resources>
三、在DataGrid中使用Converter转换,代码如下:
- <sdk:DataGrid HorizontalAlignment="Left" AutoGenerateColumns="False" Name="ShowCityList" VerticalAlignment="Top" >
- <sdk:DataGrid.Columns>
- <sdk:DataGridTextColumn Header="省会" Binding="{Binding AddrName}" IsReadOnly="True"/>
- <sdk:DataGridTextColumn Header="城市" Binding="{Binding CityName}" IsReadOnly="True" />
- <sdk:DataGridTextColumn Header="电话区号" Binding="{Binding TelNum}" IsReadOnly="True" />
- <sdk:DataGridTemplateColumn Header="城市图片">
- <sdk:DataGridTemplateColumn.CellTemplate>
- <DataTemplate>
- <Image Source="{Binding CityImageUrl, Mode=TwoWay, Converter={StaticResource ImageCoverter}}"></Image>
- </DataTemplate>
- </sdk:DataGridTemplateColumn.CellTemplate>
- </sdk:DataGridTemplateColumn>
- </sdk:DataGrid.Columns>
- </sdk:DataGrid>
四、为这个DataGrid绑定数据源如下代码:
- public partial class MainPage : UserControl
- {
- public MainPage()
- {
- InitializeComponent();
- List<CityInformation> listCity = new List<CityInformation>()
- {
- new CityInformation(){
- AddrName="四川",
- CityName="成都",
- TelNum="028-28884482",
- CityImageUrl="http://sc.admin5.com/uploads/allimg/100211/105R34217-0.png"
- },
- new CityInformation()
- {
- AddrName="广东",
- CityName="广州",
- TelNum="021-22332884",
- CityImageUrl="http://sc.admin5.com/uploads/allimg/100211/105R333J-4.png"
- },
- new CityInformation()
- {
- AddrName="上海",
- CityName="上海",
- TelNum="020-33245566",
- CityImageUrl="http://sc.admin5.com/uploads/allimg/100211/105R31S6-9.png"
- },
- new CityInformation()
- {
- AddrName="北京",
- CityName="北京",
- TelNum="010-77534222",
- CityImageUrl="http://sc.admin5.com/uploads/allimg/100211/105R33342-7.png"
- }
- };
- this.ShowCityList.ItemsSource = listCity;
- }
- }
- /// <summary>
- /// 城市信息的实体类
- /// </summary>
- public class CityInformation
- {
- private string _AddrName;
- private string _CityName;
- private string _TelNum;
- private string _cityImageUrl;
- public string AddrName
- {
- get { return _AddrName; }
- set { _AddrName = value; }
- }
- public string CityName
- {
- get { return _CityName; }
- set { _CityName = value; }
- }
- public string TelNum
- {
- get { return _TelNum; }
- set { _TelNum = value; }
- }
- public string CityImageUrl
- {
- get { return _cityImageUrl; }
- set { _cityImageUrl = value; }
- }
- }
思考二:我需要做一个自定义控件,自定义控件是以厘米为单位来设置其宽度,而不是以像素为单位来设置,应该如何实现?
TypeConverter的使用方法:
一、编写一个SLConverter类型继承于TypeConverter类,重写了CanConvertFrom方法和ConvertFrom方法将XAML中的String类型的数据转换为Double类型赋值给自定义控件。
- public class CustomLengthConverter : TypeConverter
- {
- //返回一个值,该值指示类型转换器能否将指定类型的对象转换为此转换器的类型
- public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
- {
- if (sourceType == typeof(string))
- {
- return true;
- }
- return base.CanConvertFrom(context, sourceType);
- }
- //从指定值转换为此转换器的预期转换类型。
- public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
- {
- if (value == null)
- {
- return new Double();
- }
- if (value is string)
- {
- string s = (string)value;
- if (s.Length == 0)
- {
- return new Double();
- }
- //将流入的字符串分割为两部分,使用第一部分2cm*40=80=设置的像素
- string[] arguments = s.Split(' ');
- if (arguments.Length != 2)
- {
- return new Double();
- }
- else
- {
- //假设1cm=40px
- return InternalParseInput((double.Parse(arguments[0])*40).ToString());
- }
- }
- return base.ConvertFrom(context, culture, value);
- }
- //将String数据格式化为Double类型数据返回给属性
- public Double InternalParseInput(String inputString)
- {
- Double doubleValue;
- try
- {
- doubleValue = Double.Parse(inputString);
- }
- catch (Exception)
- {
- doubleValue = new Double();
- }
- return doubleValue;
- }
- }
二、编写一个自定义控件RichTextBlock,并且为这个自定义控件新增了两个自定义属性,其中一个是将cm转换为px以显示在屏幕上,这里使用TypeConverter的特性如下代码:
- public partial class RichTextBlock : UserControl
- {
- public RichTextBlock()
- {
- InitializeComponent();
- }
- [TypeConverter(typeof(CustomLengthConverter))]
- public Double txtWidth
- {
- get { return this.txtBlock.Width; }
- set { this.txtBlock.Width = value; }
- }
- public Double txtHeight
- {
- get { return this.txtBlock.Height; }
- set { this.txtBlock.Height = value; }
- }
- }
三、在引用这个自定义控件的时候可以设置其自定义属性如下代码所示:
< this :RichTextBlock VerticalAlignment = " Top " txtHeight = " 150 " txtWidth = " 2 cm " />
最后我们来看代码运行的效果图如下,另外如需源码请点击 SLConverter.zip 下载。