WPF學習筆記:Binding的數據轉換

前面我們講解的數據綁定都是非常簡單的數據類型,基本上都是int或者string,都可以很容易地顯示在界面上。現在想象一個這樣的場景:我們定義了一個枚舉,這個枚舉有2個枚舉值,checked和unchecked。界面上有一個checkbox,當枚舉值爲checked時,複選框被選中。因爲checkbox是無法識別枚舉值的,所以這裏需要一個數據的轉換,把枚舉值轉換成bool值。

下面我們看一個例子:

xaml代碼:

<Window x:Class="BindValidationRule.Window1"
        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:BindValidationRule"
        mc:Ignorable="d"
        Title="Window1" Height="450" Width="800">
    <Window.Resources>
        <local:CategoryToSourceConverter x:Key="cts"/>
        <local:StateToNullableBoolConverter x:Key="stnb"/>
    </Window.Resources>
        
    <StackPanel>
        <ListBox x:Name="listBoxPlane" Height="160" Margin="5">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Width="60" Text="{Binding Path=Category, Converter={StaticResource cts}}"/>
                        <TextBlock Text="{Binding Path=Name}" Width="60"/>
                        <CheckBox IsThreeState="True" IsChecked="{Binding Path=State,Converter={StaticResource stnb}}"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button x:Name="btnLoad" Content="Load" Height="30" Click="btnLoad_Click"/>
    </StackPanel>
</Window>

c#代碼:

    public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
        }

        private void btnLoad_Click(object sender, RoutedEventArgs e)
        {
            List<Plane> planes = new List<Plane>()
            {
                new Plane(){Category= Category.Bomber,Name="B-1",State= State.Unknown},
                new Plane(){Category= Category.Bomber,Name="B-2",State= State.Avalible},
                new Plane(){Category= Category.Fighter,Name="B-3",State= State.Locked},
            };

            listBoxPlane.ItemsSource = planes;
        }
    }

    public enum Category
    {
        Bomber,
        Fighter
    }

    public enum State
    {
        Avalible,
        Locked,
        Unknown
    }

    public class Plane
    {
        public Category Category { get; set; }
        public State State { get; set; }
        public string Name { get; set; }
    }

    public class CategoryToSourceConverter:IValueConverter
    {
        public object Convert(object value,Type targetType,object parameter,CultureInfo cultureInfo)
        {
            Category category = (Category)value;
            switch(category)
            {
                case Category.Bomber:
                    return "A";
                case Category.Fighter:
                    return "B";
                default:
                    return null;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
        {
            throw new NotImplementedException();
        }
    }

    public class StateToNullableBoolConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo cultureInfo)
        {
            State state = (State)value;
            switch (state)
            {
                case State.Avalible:
                    return true;
                case State.Locked:
                    return false;
                default:
                    return null;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo cultureInfo)
        {
            bool? nb = (bool?)value;
            switch(nb)
            {
                case true:
                    return State.Avalible;
                case false:
                    return State.Locked;
                default:
                    return State.Unknown;
            }
        }
    }

 當我們點擊load按鈕時,界面顯示效果如下:

 我們這裏給第一列的TextBlock的Text屬性指定了binding,path=Category,而我們定義了Category是一個枚舉。所以我們也給這個binding指定了一個Converter。這個轉換器定義在Window.Resources裏面。下面我們重點看一下它是如何實現轉換的:

我們看CategoryToSourceConverter類,它繼承自IValueConverter接口,這個接口的定義是這樣的:

 它只有2個函數,Convert是把源數據轉換成目標數據,ConvertBack則相反。在我們這個例子裏面,源指的就是Category這個枚舉,目標數據指的就是TextBlock的Text屬性值。

 第一個參數value是源的值,第二個參數用於確定方法的返回類型;第三個參數用於把額外的信息傳入方法,若需要傳遞多個信息則可以把信息放入一個集合對象來傳入方法;第四個參數用於提供有關特定區域性的信息。

在這個例子裏面,因爲我們知道value的值是Category,所以直接把value強制轉換成Category。然後根據不同的枚舉值返回相應的數據,我做的例子是爲了方便隨便寫的字符串。

 前臺設置轉換器,後臺實現轉換邏輯,這樣一個完整的轉換器就做好了。我們這裏暫時不考慮把目標數據轉換到源數據,所以並沒有實現ConvertBack方法。

 下面checkbox的轉換思想和上面TextBlock是一樣的,這裏就不再贅述了。

但是這裏有個地方要提一下,我們看到checkbox有一個屬性IsThreeState=true。checkbox默認是2種狀態,選中或者沒選中,但是它還有一種狀態就是半選中。當IsChecked=null時,它就是半選中狀態。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章