WPF Data Binding之資料的轉換和校正【四】

來源:互聯網
上載者:User

標籤:data binding   wpf   

    Binding的作用就是架在Source和Target之間的橋樑,資料可以在這座橋樑的協助下來流通。就像現實社會中橋樑需要設定安檢和關卡一樣,Binding這座橋上也可以設定關卡對資料進行驗證,不僅如此,如果Binding兩端需要不同的資料類型的時候我們還可以為資料設定轉換器。


    Binding用於資料有效性校正的關卡是他的ValidationRules屬性,用於資料類型轉換的關卡是它的Convert屬性。


1.1 Binding的資料校正


    Binding的ValidationRules屬性是Collection<ValidationRule>,從它的名稱和資料類型我們可以得知可以為每個Binding設定多個資料校正條件,每一個條件是一個ValidationRule對象。ValidationRule是一個抽象類別,在使用的時候我們需要建立它的衍生類別並實現它的Validate方法的返回值是ValidationResult類型對象,如果通過驗證,就把ValidationResult對象的IsValidate屬性設為true,反之,則需要將IsValidate設定為false並為其ErrorContent屬性設定一個合適的訊息內容(一般是字串)。

    下面這個程式的UI繪製一個TextBox和一個Slider,然後在後台C#代碼中建立Binding把它們關聯起來---- 以Slider為源,TextBox為目標。Slider的取值範圍是0~100,也就是說我們需要驗證TextBox中輸入的值是不是在0~100之間。


XAML:

<span style="font-family:Microsoft YaHei;font-size:14px;"><Window x:Class="WpfApplication6.wnd641"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="wnd641" Height="200" Width="300">    <StackPanel Background="LightSlateGray">        <!--大小寫敏感-->        <!--Text="{Binding Path=Value, ElementName=_slider , UpdateSourceTrigger=PropertyChanged}"-->        <TextBox x:Name="_txtBox" Margin="5" />        <Slider x:Name="_slider" Minimum="0" Maximum="100" Margin="5" />    </StackPanel></Window></span>

C# 資料校正繼承類:

<span style="font-family:Microsoft YaHei;font-size:14px;">    // 資料校正    public class RangValidationRule:ValidationRule    {        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 Error"));        }    }</span>

C#綁定:

<span style="font-family:Microsoft YaHei;font-size:14px;">    /// <summary>    /// wnd641.xaml 的互動邏輯    /// </summary>    public partial class wnd641 : Window    {        public wnd641()        {            InitializeComponent();            Binding binding = new Binding("Value")             {                 Source = _slider,                UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,            };            RangValidationRule val = new RangValidationRule();            // 目標更新時是否運行驗證規則,預設來自Source的是不校正的            val.ValidatesOnTargetUpdated = true;            binding.ValidationRules.Add(val);            binding.NotifyOnValidationError = true;            _txtBox.SetBinding(TextBox.TextProperty, binding);            // 添加錯誤提示的路由事件            _txtBox.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationError));        }        void ValidationError(object sender, RoutedEventArgs e)        {            if(Validation.GetErrors(_txtBox).Count > 0)            {                _txtBox.ToolTip = Validation.GetErrors(_txtBox)[0].ErrorContent.ToString();            }        }    }</span>

     完成後運行程式,當輸入0~100之間的值的時候程式正常顯示,但是輸入區間之外的值的時候TextBox會顯示為紅色邊框,表示值是錯誤的,不能傳值給Source。

1.2 Binding的資料轉換

    Binding還有另外一種機制稱為資料轉換,當Source端指定的Path屬性值和Target端指定的目標屬性不一致的時候,我們可以添加資料轉換器(DataConvert)。上面我們提到的問題實際上就是double和stirng類型相互轉換的問題,因為處理起來比較簡單,所以WPF類庫就自己幫我們做了,但有些資料類型轉換就不是WPF能幫我們做的了,當遇到這些情況,我們只能自己動手寫Converter,方法是建立一個類並讓這個類實現IValueConverter介面。


    當資料從Binding的Source流向Target的時候,Convert方法將被調用;反之ConvertBack將被調用。這兩個方法的參數列表一模一樣:第一個參數為Object。最大限度的保證了Convert的重要性。第二個參數用於確定返回參數的傳回型別。第三個參數為了將額外的參數傳入方法,若需要傳遞多個資訊,則需要將資訊做為一個集合傳入即可。


    Binding對象的Mode屬性將影響這兩個方法的調用;如果Mode為TwoWay或Default行為與TwoWay一致則兩個方法都有可能被調用。如果Mode是OneWay或者Default行為與OneWay一致則只有Convert方法會被調用。其它情況同理。
下面這個例子是一個Converter的綜合執行個體,程式的用途是向玩家顯示一些軍用飛機的狀態資訊。

C#:

using System;using System.Collections.Generic;using System.Globalization;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Controls;using System.Windows.Data;using System.Windows.Documents;using System.Windows.Input;using System.Windows.Media;using System.Windows.Media.Imaging;using System.Windows.Shapes;namespace WpfApplication6{    public enum Category    {        Bomber,        Fighter    }    public class Plane    {        public Category Category { get; set; }        public string Name { get; set; }    }    /// <summary>    /// 資料轉換    /// </summary>    public class CategoryToSourceCvt:IValueConverter    {        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)        {            Category c = (Category)value;            switch(c)            {                case Category.Bomber:                    return (@"E:\RefCode\C#\WPF\深入淺出WPF\第六章Binding\WpfApplication6\WpfApplication6\Bomber.png");                case Category.Fighter:                    return (@"E:\RefCode\C#\WPF\深入淺出WPF\第六章Binding\WpfApplication6\WpfApplication6\Fighter.png");            }            return(null);        }        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)        {            throw new NotImplementedException();        }    }    /// <summary>    /// wnd642.xaml 的互動邏輯    /// </summary>    public partial class wnd642 : Window    {        public wnd642()        {            InitializeComponent();            List<Plane> _listPanel = new List<Plane>()            {                new Plane(){Category = Category.Fighter, Name= "F-1"},                new Plane(){Category = Category.Bomber, Name= "B-1"},                new Plane(){Category = Category.Fighter, Name= "F-2"},            };            _listBox.ItemsSource = _listPanel;        }    }}

XAML:

<Window x:Class="WpfApplication6.wnd642"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:local="clr-namespace:WpfApplication6"        Title="wnd642" Height="200" Width="300">    <Window.Resources>        <local:CategoryToSourceCvt x:Key="cts" />    </Window.Resources>    <StackPanel>        <ListBox x:Name="_listBox" Height="160" Margin="5">            <ListBox.ItemTemplate>                <DataTemplate>                    <StackPanel Orientation="Horizontal">                        <!--Converter使用靜態資源-->                        <Image Source="{Binding Path=Category, Converter={StaticResource ResourceKey=cts}}" Width="20" Height="20"></Image>                        <TextBlock Text="{Binding Path=Name}" Width="60" Height="20" Margin="80, 0"></TextBlock>                    </StackPanel>                </DataTemplate>            </ListBox.ItemTemplate>        </ListBox>    </StackPanel></Window>


1.3 MultiBinding(多路Binding)

    有時候UI需要顯示的資料來源不止一個資料來源決定,這個時候就需要用到MultiBinding,即多路綁定。MultiBinding與Binding一樣均以BindingBase為基類,也就是說,凡是能用Binding的場合都能使用MultiBinding。MutiBinding具有一個Bindings的屬性,其類型是Connection<BindingBase>,通過這個屬性,MultiBinding把一組Binding對象彙總起來,處在這個Binding結合中的對象可以擁有自己的資料校正和轉換機制。它們彙集起來的資料將共同決定傳往MultiBinding目標的資料。如:


    考慮這樣一個需求,有一個用於新使用者註冊的UI(2個TextBox和一個Button),還有如下一些限定:
TextBox用於顯示輸入的郵箱,要求資料必須一致。
當TextBox的內容全部符合要求的時候,Button可用。

XAML:

<Window x:Class="WpfApplication6.wnd65"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        Title="wnd65" Height="200" Width="300">    <StackPanel>        <TextBox x:Name="_txtBox1" Margin="5"></TextBox>        <TextBox x:Name="_txtBox2" Margin="5"></TextBox>        <Button Content="OK" x:Name="_btn" Margin="5"></Button>    </StackPanel></Window>

C#:

    public class LogMulCvt:IMultiValueConverter    {        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)        {            // 元素強制轉換為指定的string類型            if(!values.Cast<string>().Any((text) => string.IsNullOrEmpty(text)) &&                values[0].ToString() == values[1].ToString())            {                return (true);            }            return (false);        }        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)        {            throw new NotImplementedException();        }    }    /// <summary>    /// wnd65.xaml 的互動邏輯    /// </summary>    public partial class wnd65 : Window    {        public wnd65()        {            InitializeComponent();            Binding binding1 = new Binding("Text") { Source = _txtBox1 };            Binding binding2 = new Binding("Text") { Source = _txtBox2 };            MultiBinding mulBinding = new MultiBinding();            mulBinding.Bindings.Add(binding1);            mulBinding.Bindings.Add(binding2);            mulBinding.Converter = new LogMulCvt();            _btn.SetBinding(Button.IsEnabledProperty, mulBinding);        }    }


注意:

MultiBinding對子項目的順序非常敏感,因為這個資料決定了彙集到Convert裡資料的順序。
MultiBinding的Converter實現的是IMultiValueConverter。

    WPF的核心理念是變傳統的UI驅動資料變成資料驅動UI,支撐這個理念的基礎就是本章講的Data Binding和與之相關的資料校正和資料轉換。在使用Binding的時候,最重要的就是設定它的源和路徑。  


參考《深入淺出WPF》

WPF Data Binding之資料的轉換和校正【四】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.