首页 > 代码库 > WPF之Binding对数据的转换(第五天)

WPF之Binding对数据的转换(第五天)

Binding在Slider控件与TextBox控件之间建立关联,值可以互相绑定,但是它们的数据类型是不同的,Slider是Double类型,Text为String。原来,Binding有一种机制称为数据转换(Data Converter),当数据绑定的源与目标不同类型时,处理比较简单时,系统就自动的进行了类型转换,但是对于相对复杂的类型转换时,就需要我们手动进行了。

下面用一个例子来说明Convert的应用,程序的用途是在列表里面向玩家显示一些球的状态。

首先创建几个自定义数据类型:

public enum Category    {        Basketball,        football    }    public enum State    {        Available,        Locked,        Unknown    }    public class ball    {        public Categroy Categroy { get;set; }        public string Name { get; set; }        public State State { get; set; }    }

程序后面要用到的图片已经加载到程序中,球的State属性在UI里被映射为CheckBox。因为存在两个映射关系,我们需要提供两个Convert:一个是由Category类型单向转换为string,另一个State与bool?类型之间相互转换。代码如下:

public class CategoryToSourceConverter : IValueConverter    {        //将Category转换为Uri        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)        {            Category c = (Category)value;            switch (c)            {                case Category.Basketball:                    return @"basketball.png";                case Category.football:                    return @"football.png";                default:                    return null;            }        }        //不会被调用        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)        {            throw new NotImplementedException();        }    }    public class StateToNullableBoolConvert : IValueConverter    {        //将state转换为bool?        public object Convert(object value, Type targetType, object parameter, System.Globalization.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, System.Globalization.CultureInfo culture)        {            bool? nb = (bool?)value;            switch (nb)            {                case true:                    return State.Available;                case false:                    return State.Locked;                case null:                default:                    return State.Unknown;            }        }    }

下面我们看看如何在XAML里消费这些Converter。XAML代码的框架如下:

<Window x:Class="DataConverter.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:DataConverter"        Title="MainWindow" Height="350" Width="525">        <Window.Resources>        <local:CategoryToSourceConverter x:Key="cts"/>        <local:StateToNullableBoolConvert x:Key="stnb"/>    </Window.Resources>    <Grid>        <StackPanel Background="LightBlue">            <ListBox x:Name="listBoxPlan" Height="160" Margin="5,0"></ListBox>            <Button x:Name="buttonLoad" Content="Load" Height="25" Margin="5,0"></Button>            <Button x:Name="buttonSave" Content="Save" Height="25" Margin="5,5"></Button>                    </StackPanel>    </Grid></Window>

XAML代码中已经添加了对程序集的引用并映射为名称空间local,以资源的形式创建了两个Convert的实例。名为ListBoxPlan的ListBox控件需要为它添加用于显示数据的DataTemplate。我们把焦点集中在ListBox控件的ItemTemplate属性上:

<ListBox x:Name="listBoxPlan" Height="160" Margin="5,0">                <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="80,0"/>                            <CheckBox IsThreeState="True"                                      IsChecked="{Binding Path=State,Converter={StaticResource stnb}}"/>                        </StackPanel>                    </DataTemplate>                </ListBox.ItemTemplate>            </ListBox>

Load按钮的Click事件处理负责把一组球的数据赋值给ListBox的ItemSource属性,Save按钮的Click事件处理器负责把用户更改过的数据写入文件:

//Load按钮Click事件处理器        private void buttonLoad_Click(object sender, RoutedEventArgs e)        {            List<Ball> ballList = new List<Ball>()            {                new Ball(){Category = Category.Basketball,Name = "NBA",State = State.Unknown},                new Ball(){Category = Category.Basketball,Name = "CBA",State = State.Unknown},                new Ball(){Category = Category.football,Name = "世界杯",State = State.Unknown},                new Ball(){Category = Category.football,Name = "欧冠",State = State.Unknown},                new Ball(){Category = Category.Basketball,Name = "WNBA",State = State.Unknown},                new Ball(){Category = Category.football,Name = "英超",State = State.Unknown}            };            this.listBoxPlan.ItemsSource = ballList;        }        //Save按钮Click事件处理器        private void buttonSave_Click(object sender, RoutedEventArgs e)        {            StringBuilder sb = new StringBuilder();            foreach (Ball b in listBoxPlan.Items)            {                sb.AppendLine(string.Format("Category={0},Name={1},State={2}", b.Category, b.Name, b.State));            }            File.WriteAllText(@"D:\BallList.txt", sb.ToString());        }

运行程序并单击CheckBox更改State,效果图如下:

QQ截图20140710142657

单击Save按钮后打开D:\BallList.txt:

QQ截图20140710133155

注*读《深入浅出WPF》读书笔记