• WPF Converter(转)


    WPF Binding 用于数据有效性校验的关卡是它的 ValidationRules 属性,用于数据类型转换的关卡是它的 Converter 属性。下面是实例:

    1. Binding 的数据校验

    <Window x:Class="WpfStudy.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
            xmlns:local="clr-namespace:WpfStudy"
            Title="MainWindow" 
            Height="266" Width="300">
        <StackPanel>
            <TextBox x:Name="textBox1" Margin="5"/>
            <Slider x:Name="slider1" Minimum="0" Maximum="100" Margin="5"/>
        </StackPanel>
    </Window>
       public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                Binding binding = new Binding("Value") { Source = this.slider1 };
                binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
                binding.NotifyOnValidationError = true;
                RangeValidationRule rvr = new RangeValidationRule();
                rvr.ValidatesOnTargetUpdated = true;
                binding.ValidationRules.Add(rvr);
                this.textBox1.SetBinding(TextBox.TextProperty, binding);
    
                this.textBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
            }
    
            public void ValidationError(object sender, RoutedEventArgs e)
            {
                if (Validation.GetErrors(this.textBox1).Count > 0)
                {
                    this.textBox1.ToolTip = Validation.GetErrors(this.textBox1)[0].ErrorContent.ToString();
                }
            }
        }
       public class RangeValidationRule : ValidationRule
        {
            //需要实现 Validate 方法
            public override ValidationResult Validate(object value, CultureInfo cultureInfo)
            {
                double d = 0;
                if(double.TryParse(value.ToString(),out d))
                {
                    if (d >= 0 && d <= 100)
                    {
                        return new ValidationResult(true, null);
                    }
                }
    
                return new ValidationResult(false, "Validation Failed");
            }
        }

         完成后运行程序,当输入0到100之间的值时程序正常显示,但输入这个区间之外的值或不能被解析的值时 TextBox 会显示红色边框,表示值是错误的,不能把它传递给 Source。

     Binding 进行校验时的默认行为是认为来自 Source 的数据总是正确的,只有来自 Target 的数据(因为 Target 多为 UI 控件,所以等价于用户输入的数据)才有可能有问题,为了不让有问题的数据污染 Source 所以需要校验。换句话说,Binding 只在 Target 被外部方法更新时校验数据,而来自 Binding 的 Source 数据更新 Target 时是不会进行校验的。如果想改变这种行为,或者说当来自 Source 的数据也有可能出现问题时,我们就需要将校验的条件的 ValidateOnTargetUpdated 属性设为 true。

    2. Binding 的数据转换

        当数据从 Binding 的 Source 流向 Target 时,Convert 方法将被调用;反之,ConvertBack 方法将被调用。这两个方法的参数列表一模一样:第一个参数为 object,最大限度地保证了 Converter 的重用性(可以在方法体内对实际类型进行判断);第二个参数用于确定方法的返回类型(个人认为形参名字叫 outputType 比 targetType 要好,可以避免与 Binding  的 Target 混淆);第三个参数用于把额外的信息传入方法,若需要传递多个信息则可把信息放入一个集合对象来传入方法。

     Binding 对象的 Mode 属性会影响到这两个方法的调用。如果 Mode 为 TwoWay 或 Default 行为与 TwoWay 一致则两个方法都有可能被调用;如果 Mode 为 OneWay 或 Default 行为与 OneWay 一致则只有 Convert 方法会被调用;其他情况同理。

    <Window x:Class="WpfStudy.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
            xmlns:local="clr-namespace:WpfStudy"
            Title="MainWindow" 
            Height="266" Width="300">
        <Window.Resources>
            <local:CategoryToSourceConverter x:Key="cts"/>
            <local:StateToNullableBoolConverter x:Key="stnb"/>
        </Window.Resources>
        <StackPanel Background="LightBlue">
            <ListBox x:Name="listBoxPanel" Height="160" Margin="5">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Width="20" Height="20" Source="{Binding Path=Category,Converter={StaticResource cts}}"/>
                            <TextBlock Text="{Binding Path=Name}" Width="60" Margin="80,0"/>
                            <CheckBox IsThreeState="True" IsChecked="{Binding Path=State,Converter={StaticResource stnb}}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
            <Button x:Name="buttonLoad" Content="Load" Height="25" Margin="5,0" Click="ButtonLoad_Click"/>
            <Button x:Name="buttonSave" Content="Save" Height="25" Margin="5,5" Click="ButtonSave_Click"/>
        </StackPanel>
    </Window>
       public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void ButtonLoad_Click(object sender, RoutedEventArgs e)
            {
                List<Plane> planeList = new List<Plane>()
                {
                    new Plane() { Category = Category.Bomber, Name = "B-1", State = State.Unknown },
                    new Plane() { Category = Category.Bomber, Name = "B-2", State = State.Unknown },
                    new Plane() { Category = Category.Fighter, Name = "F-22", State = State.Unknown },
                    new Plane() { Category = Category.Fighter, Name = "Su-47", State = State.Unknown },
                    new Plane() { Category = Category.Bomber, Name = "B-52", State = State.Unknown },
                    new Plane() { Category = Category.Fighter, Name = "J-10", State = State.Unknown }
                };
    
                this.listBoxPanel.ItemsSource = planeList;
            }
    
            private void ButtonSave_Click(object sender, RoutedEventArgs e)
            {
                StringBuilder sb = new StringBuilder();
                foreach(Plane p in listBoxPanel.Items)
                {
                    sb.AppendLine(string.Format("Category={0},Name={1},State={2}", p.Category, p.Name, p.State));
                }
                File.WriteAllText(@"D:PlaneList.txt", sb.ToString());
            }
        }
        // Converters
        public class CategoryToSourceConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo cultureinfo)
            {
                Category c = (Category)value;
                switch (c)
                {
                    case Category.Bomber:
                        return @"IconsBomber.png";
                    case Category.Fighter:
                        return @"IconsFighter.png";
                    default:
                        return null;
                }
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureinfo)
            {
                throw new NotImplementedException();
            }
        }
    
        public class StateToNullableBoolConverter : IValueConverter
        {
            // 将 State 转换为 bool?
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                State s = (State)value;
                switch (s)
                {
                    case State.Locked:
                        return false;
                    case State.Available:
                        return true;
                    case State.Unknown:
                    default:
                        return null;
                }
            }
    
            // 将 bool? 转换为 State
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                bool? nb = (bool?)value;
                switch (nb)
                {
                    case true:
                        return State.Available;
                    case false:
                        return State.Locked;
                    case null:
                    default:
                        return State.Unknown;
                }
            }
        }
      //种类
        public enum Category
        {
            Bomber,
            Fighter
        }
    
        //状态
        public enum State
        {
            Available,
            Locked,
            Unknown
        }
    
        //飞机
        public class Plane
        {
            public Category Category { get; set; }
            public string Name { get; set; }
            public State State { get; set; }
        }

     3. MultiBinding(多路 Binding)

    <Window x:Class="WpfStudy.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
            xmlns:local="clr-namespace:WpfStudy"
            Title="MainWindow" 
            Height="266" Width="300">
        <StackPanel Background="LightBlue">
            <TextBox x:Name="textBox1" Height="23" Margin="5"/>
            <TextBox x:Name="textBox2" Height="23" Margin="5,0"/>
            <TextBox x:Name="textBox3" Height="23" Margin="5"/>
            <TextBox x:Name="textBox4" Height="23" Margin="5,0"/>
            <Button x:Name="button1" Content="Submit" Width="80" Margin="5"/>
        </StackPanel>
    </Window>
    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
    
                this.SetMultiBinding();
            }
    
            private void SetMultiBinding()
            {
                //准备基础Binding
                Binding b1 = new Binding("Text") { Source = this.textBox1 };
                Binding b2 = new Binding("Text") { Source = this.textBox2 };
                Binding b3 = new Binding("Text") { Source = this.textBox3 };
                Binding b4 = new Binding("Text") { Source = this.textBox4 };
    
                //准备MultiBinding
                MultiBinding mb = new MultiBinding() { Mode = BindingMode.OneWay };
                mb.Bindings.Add(b1); //注意:MultiBinding对Add子Binding的顺序是敏感的
                mb.Bindings.Add(b2);
                mb.Bindings.Add(b3);
                mb.Bindings.Add(b4);
                mb.Converter = new LogonMultiBindingConverters();
    
                //将 Button 与 MultiBinding 对象关联
                this.button1.SetBinding(Button.IsEnabledProperty, mb);
            }
        }
    public class LogonMultiBindingConverters : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                if(!values.Cast<string>().Any(text=>string.IsNullOrEmpty(text))
                    && values[0].ToString() == values[1].ToString()
                    && values[2].ToString() == values[3].ToString())
                {
                    return true;
                }
                return false;
            }
    
            public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }

        转自:《深入浅出 WPF》 第六章

  • 相关阅读:
    [原][python]把python文件编译成exe(解决安装pyinstaller出现的错误)
    [原][c++][公式]计算球弧面体积------球缺
    Java运行时动态生成类几种方式
    Flink窗口Window机制详解
    Bootstrap 提示工具(Tooltip)插件
    Bootstrap-table 使用说明--如何在表格td里增加一个按钮
    如何在列表操作列区域添加按钮及控制已有按钮显示
    fastadmin 如何去掉 权重拖拽 图标
    如何设置select下拉禁止选择
    js引用cdn,如果cdn挂了,用本地js替补
  • 原文地址:https://www.cnblogs.com/hellowzl/p/11579053.html
Copyright © 2020-2023  润新知