前面我們講解的數據綁定都是非常簡單的數據類型,基本上都是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時,它就是半選中狀態。