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

 

 



posted @ 2024-08-19 14:29  【君莫笑】  阅读(165)  评论(0编辑  收藏  举报