WPF 类型转换器和值转换器
它可以将任何特定类型的数据转换为其他类型,同理,也可以将其他任何类型转换为特定的数据类型。比如刚才咱们介绍的那种情况。赋值赋的是字符串类型,但是渲染出来还是颜色。其实XAML解析器通过两个步骤查找到了对应的类型转换器。
1)检查对应的属性声明。比如Foreground属性,查看是否存在TypeConverter特性。如果提供了,即证明将指定哪种类型进行转换。
【比如Width、Height等】如果要深究LengthConverter等是怎么工作的之后可以看看WPF源码,简单介绍下,
所欲的类型转换器都继承于TypeConverter 都重写了CanConvertFrom CanConvertTo 和 ConvertFrom。
赋值时会先判断所输入是否能够完成转换。其他的可以直接去看源代码
[TypeConverter(typeof(LengthConverter))] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public double Height { get { return (double)GetValue(HeightProperty); } set { SetValue(HeightProperty, value); } }
2)如果再属性声明中没有TypeConverter特性,XAML解析器将检查对应类的声明,如,Foreground属性使用了Brush对象,
由于Brush使用TypeConverter(typeof(BrushConverter))特性声明进行了修饰,因此Brush类及其子类使用BrushConverter类型转换器。可以直接F12查看
[Bindable(true)] [Category("Appearance")] public Brush Foreground { get { return (Brush)GetValue(ForegroundProperty); } set { SetValue(ForegroundProperty, value); } }
我们写个Demo来验证下对应的映射关系
首先新建一个Person类
/// <summary> /// Person 人员类 /// </summary> public class Person { //人员姓名 public string PerName { get; set; } //人员类别 public Person PerChild { get; set; } }
此时我们在界面上使用新建的类(其中部分语法可能看不懂之后会说到)
<Window.Resources> <local:Person x:Key="per" PerChild="李四" PerName="张三" /> </Window.Resources>
新建一个Button按钮,当点击的时候我们获取到PerChild并弹窗
<Button 2 Width="120" 3 Height="50" 4 Click="Button_Click" 5 Content="点 我" />
1 private void Button_Click(object sender, RoutedEventArgs e) 2 { 3 var per = this.FindResource("per") as Person; 4 MessageBox.Show(per.PerChild.PerName); 5 }
/// <summary> /// string类型转换Person转换器 /// </summary> public class StringToPersonTypeConverter : TypeConverter { public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) { //如果值为string类型的值时 if (value is string) { Person per = new Person(); per.PerName = value as string; return per; } return base.ConvertFrom(context, culture, value); }
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
}
2) 声明完成之后再Person上边加上对应特性 1 [TypeConverterAttribute(typeof(StringToPersonTypeConverter))]
扩展:
1、MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<DockPanel HorizontalAlignment="Left" Height="322" LastChildFill="False" VerticalAlignment="Top" Width="515" Margin="0,0,0,-2">
<Button DockPanel.Dock="Left" Background="AliceBlue" Width="264">
<local:Book Name="CookBook" Price="$0.1">
内容:梦里花落知多少
</local:Book>
</Button>
<Button DockPanel.Dock="Right" Width="249">
<Button.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="Yellow" Offset="0.0"/>
<GradientStop Color="Aquamarine" Offset="0.25"/>
<GradientStop Color="Bisque" Offset="0.75"/>
<GradientStop Color="Coral" Offset="1.0"/>
</LinearGradientBrush>
</Button.Background>
Hello XAML
</Button>
</DockPanel>
</Window>
第一个Button的Content属性的值设置成一个自定义的Book类,该Book对象调用ToString()方法返回的字符串就会显示在Button上,注意该Book对象的Price属性设置为"$0.1",即0.1美元,
通过类型转换器,将会把这个值转换为"0.8"(人民币)。
第二个Button使用了渐变画刷来设置背景。
2、Book.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
//ContenProperty所在的命名空间
using System.Windows.Markup;
namespace WpfApplication1
{
[ContentProperty("Text")] //声明Content属性
public class Book
{
public Book()
{
}
//Name属性
public string Name
{
get;
set;
}
//Price属性的数据类型是一个MoneyType类,该类声明了类型转换器,可以将带有美元符号的价格转换为人民币
public MoneyType Price
{
get;
set;
}
//Text属性
public string Text { get; set; }
public override string ToString()
{
string str = Name + "售价为:" + Price + "元\n"+Text;
return str;
}
}
}
Book类中声明了三个自动属性,其中将Text属性声明为ContentProperty,这样不必使用Property-Element语法就可以直接成为Button元素的子类;Price属性是MoneyType类型,该类声明了一个类型转换器,可以将美元转换为人民币。
3、MoneyType.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//TypeConverter所在的命名空间
using System.ComponentModel;
namespace WpfApplication1
{
//声明类型转换器
[TypeConverter(typeof(MoneyConverter))]
public class MoneyType
{
private double _value;
public MoneyType() { _value = 0; }
public MoneyType(double value)
{
_value = value;
}
public override string ToString()
{
return _value.ToString();
}
//价格转换方法,这里只考虑美元和人民币,不考虑其他币种
public static MoneyType Parse(string value)
{
string str = (value as string).Trim();
if (str[0] == '$')
{
//将美元转换为人民币
string newprice = str.Remove(0, 1);
double price = double.Parse(newprice);
return new MoneyType(price * 8);
}
else
{
//不带特殊符号的字符串默认识别为人民币
double price = double.Parse(str);
return new MoneyType(price);
}
}
}
}
MoneyType类中声明了类型转换器,并且实现了一个类方法Parse(),在该方法中完成对字符串的转换。
4、MoneyConverter.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
//TypeConverter所在的命名空间
using System.ComponentModel;
namespace WpfApplication1
{
public class MoneyConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
//转换为字符串类型其实不需要重写此方法
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(string))
{
return true;
}
return base.CanConvertTo(context, destinationType);
}
//将string转换为MoneyType
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
return MoneyType.Parse((string)value);
return base.ConvertFrom(context, culture, value);
}
//将MoneyType转换为string
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string))
{
return ((MoneyType)value).ToString();
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
}
来源:https://www.cnblogs.com/tt2015-sz/p/4744181.html
WPF 值转换器(Converter)的使用
示例一、ViewModel层int型属性Gender绑定界面表示性别的两个RadioButton,Gender=1表示男,Gender=2表示女;
<Window.Resources> <converter:GenderConverter x:Key="genderConverter"/> </Window.Resources> <Grid HorizontalAlignment="Center" VerticalAlignment="Center"> <StackPanel Orientation="Horizontal"> <TextBlock Text="性别:" Margin="10 0"/> <RadioButton Content="男" IsChecked="{Binding Gender,Converter={StaticResource genderConverter},ConverterParameter=1}" Margin="0 0 10 0"/> <RadioButton Content="女" IsChecked="{Binding Gender,Converter={StaticResource genderConverter},ConverterParameter=2}"/> </StackPanel> </Grid>
后台代码:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); this.DataContext = new MainWindowModel(); } }
MainWindowModel代码:
namespace WpfApp1 { class MainWindowModel { public int Gender { get; set; } public MainWindowModel() { Gender = 2; } } }
转换器代码:
namespace WpfApp1.Converter { public class GenderConverter : IValueConverter { //model->view转换 public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value == null || parameter == null) return false; return value.ToString() == parameter.ToString(); //throw new NotImplementedException(); } //view->model转换 public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { //throw new NotImplementedException(); return parameter; } } }
示例二、多值转换器
下图:只有当第一个ComboBox值为A,第二个ComboBox值为B时,下面的文本字体才为红色,否则均为灰色。
class MyConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if(values[0] == null || values[1] == null) return Brushes.Gray; if (values[0].ToString() == "A" && values[1].ToString() == "B") { return Brushes.Red; } return Brushes.Gray; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
MainWindow.xaml代码:
<Window x:Class="WpfApp2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfApp2" mc:Ignorable="d" Title="MainWindow" Height="250" Width="400"> <Window.Resources> <local:MyConverter x:Key="myConverter"/> </Window.Resources> <StackPanel> <ComboBox Name="cb_001" Width="100" Height="25" Margin="0 30 0 0"> <ComboBoxItem Content="A"/> <ComboBoxItem Content="B"/> <ComboBoxItem Content="C"/> </ComboBox> <ComboBox Name="cb_002" Width="100" Height="25" Margin="0 10 0 0"> <ComboBoxItem Content="A"/> <ComboBoxItem Content="B"/> <ComboBoxItem Content="C"/> </ComboBox> <TextBlock Margin="0 20 0 0" Text="Hello World!" HorizontalAlignment="Center"> <TextBlock.Foreground> <MultiBinding Converter="{StaticResource myConverter}"> <Binding Path="Text" ElementName="cb_001"></Binding> <Binding Path="Text" ElementName="cb_002"></Binding> </MultiBinding> </TextBlock.Foreground> </TextBlock> </StackPanel> </Window>
示例四三、多值转换器的使用二
下图:如果质量和服务评分都在60以上,则评价为✔;否则评价为✘;
class GradeConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (int.Parse(values[0].ToString()) >= 60 && int.Parse(values[1].ToString()) >= 60) return "✔"; else return "✘"; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
<Window.Resources> <local:GradeConverter x:Key="gradeConverter"/> </Window.Resources> <Grid> <ListView ItemsSource="{Binding products}"> <ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="Height" Value="30"/> <Setter Property="HorizontalContentAlignment" Value="Center"/> </Style> </ListView.ItemContainerStyle> <ListView.View> <GridView> <GridView.ColumnHeaderContainerStyle> <Style TargetType="GridViewColumnHeader"> <Setter Property="Height" Value="30"/> </Style> </GridView.ColumnHeaderContainerStyle> <GridViewColumn Header="名称" Width="100" DisplayMemberBinding="{Binding Name}"/> <GridViewColumn Header="质量" Width="100" DisplayMemberBinding="{Binding Score}"/> <GridViewColumn Header="服务" Width="100" DisplayMemberBinding="{Binding Service}"/> <GridViewColumn Header="评价" Width="100" > <GridViewColumn.DisplayMemberBinding> <MultiBinding Converter="{StaticResource gradeConverter}"> <Binding Path="Score"/> <Binding Path="Service"/> </MultiBinding> </GridViewColumn.DisplayMemberBinding> </GridViewColumn> </GridView> </ListView.View> </ListView> </Grid>
public partial class MainWindow : Window { public MainWindow() { products = new List<object>(); InitializeComponent(); products.Add(new { Name = "产品一", Score = 90, Service = 40}); products.Add(new { Name = "产品二", Score = 70, Service = 70 }); products.Add(new { Name = "产品三", Score = 50, Service = 80 }); DataContext = this; } public List<object> products { get; set; } }
来源:https://blog.csdn.net/qq_43024228/article/details/109586572