代码改变世界

Binding的数据转换与校验(WPF)

2011-12-15 23:30  木木子  阅读(621)  评论(0编辑  收藏  举报

大概

  • 一些闲话
  • Binding对数据转换
  • Binding对数据校验

 

闲话

离上次做完Binding基础的笔记有段日子了。主要天气冷了,人的惰性就起作用了,打字真是手冷啊。但,这样懒下去也不是办法,男人就是要对自己狠点。就今晚了,一把鼻涕一把热茶地把Binding的剩余部分回顾下,把笔记也做了,fighting……

Binding的数据校验

Binding的Validation属性类型是Collection<ValidationRule>,即可以为一个Binding设置多个Validation条件。Validation类是一个抽象类,使用时需要创建派生类,并且实现它的Validation方法。Validation方法返回ValidationResult类型对象。ValidationResult构造函数需要传入两个参数,分别为Boolean型isValid: true表示校验通过;反之false。还有一个为Object型errorContent。

Binding默认是校验来自Target的数据,加入需要校验Source的数据正确性,需要将ValidationRule类中的ValidatesOnTargetUpdated属性设置为true。

有些时候,还需要为显示Validation方法返回的ValidationResult中的errorContent这条消息。这需用将Binding的NotifyOnValidationError设为true,这样才能将Binding发出的信号传播出去,这叫做路由(Route)。

Coding:

<Window x:Class="BindindValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="140" Width="300">
    <StackPanel>
        <TextBox x:Name="tb1" Width="200" Margin="5"></TextBox>
        <Slider x:Name="sd1" Width="200" Margin="5" Maximum="100" Minimum="-10"></Slider>
    </StackPanel>
</Window>
public class RangeValidationRule : ValidationRule
{
    public override ValidationResult Validate(object value, System.Globalization.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!");
    }
}
public MainWindow()
{
    InitializeComponent();
 
    Binding binding = new Binding("Value") { Source = this.sd1 };
    binding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;
    RangeValidationRule rvr = new RangeValidationRule();
    rvr.ValidatesOnTargetUpdated = true;
    binding.ValidationRules.Add(rvr);
    binding.NotifyOnValidationError = true;
    this.tb1.SetBinding(TextBox.TextProperty, binding);
 
    this.tb1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(this.ValidationError));
}

Binding的数据装换

有时候,Binding的Source与Target两边的Binding的值类型不一样,就会用到Binding的一种机制叫做数据转换。比如以上列子,Textbox的Text属性为String类型,Slider的Value属性为Double类型,这里就用到了这种机制实现的,简单的转换,WPF已经帮我们实现了。

自己写Converter,是要创建一个实现了IValueConverter接口,定义如下:

public interface IValueConverter
{
    object Convert(object value, Type targetType, object parameter, CultureInfo cultrue);
    object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultrue);
}

Convert方法用于Source流向Target时,反之ConvertBack。

Coding:

<Window x:Class="BindindValidation.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local ="clr-namespace:BindindValidation"
        Title="MainWindow" Height="272" Width="300">
    <Window.Resources>
        <local:CategoryToSourceConverter x:Key="cts"></local:CategoryToSourceConverter>
        <local:StateToNullableBoolConverter x:Key="sts"/>
    </Window.Resources>
    <StackPanel>
        <ListBox x:Name="PlaneListBox" Height="160" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <Image Width="20" Height="20" Source="{Binding Path=Category,Converter={StaticResource cts}}"></Image>
                        <TextBlock Text="{Binding Path=Name}" Width="60" Margin="50,0"></TextBlock>
                        <CheckBox IsThreeState="True" IsChecked="{Binding Path=State, Converter={StaticResource sts}}"></CheckBox>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox> 
        <Button x:Name="buttonLoad" Content="Load" Height="25" Margin="5,0" Click="buttonLoad_Click"></Button>
        <Button x:Name="buttonSave" Content="Save" Height="25" Margin="5,0" Click="buttonSave_Click"></Button>
    </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.Plane,Name = "P-1", State = State.Available},
                new Plane(){Category=Category.Glider,Name = "G-1", State = State.Available},
                new Plane(){Category=Category.Plane,Name = "P-2", State = State.Locked},
                new Plane(){Category=Category.Glider,Name = "G-2", State = State.UnKnown},
                new Plane(){Category=Category.Plane,Name = "P-3", State = State.UnKnown},
                new Plane(){Category=Category.Plane,Name = "P-5", State = State.Available},
            };
            this.PlaneListBox.ItemsSource = planeList;
        }
 
        private void buttonSave_Click(object sender, RoutedEventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            foreach (Plane p in this.PlaneListBox.Items)
            {
                sb.AppendLine(string.Format("Category={0},Name={1},State={2}", p.Category, p.Name, p.State));
            }
            File.WriteAllText(@"E:\PlaneList.txt", sb.ToString());
        }
 
       
    }
 
    public class CategoryToSourceConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            Category c = (Category)value;
            switch (c)
            {
                case Category.Glider:
                    return @"\img\glider.png";
                case Category.Plane:
                    return @"\img\plane.png";
                default:
                    return null;
            }
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
 
    public class StateToNullableBoolConverter : IValueConverter
    {
        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;
            }
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            bool? b = (bool?)value;
            switch (b)
            {
                case true:
                    return State.Available;
                case false:
                    return State.Locked;
                case null:
                default:
                    return State.UnKnown;
            }
        }
    }
 
    public enum Category
    {
        Glider,
        Plane
    }
 
    public enum State
    {
        Available,
        Locked,
        UnKnown
    }
 
    public class Plane
    {
        public Category Category { get; set; }
        public string Name { get; set; }
        public State State { get; set; }
    }

Run:

image