一、WPF數(shù)據(jù)綁定的概要
數(shù)據(jù)綁定:是應(yīng)用程序 UI 與業(yè)務(wù)邏輯之間建立連接的過程。 如果綁定正確設(shè)置并且數(shù)據(jù)提供正確通知,則當數(shù)據(jù)的值發(fā)生更改時,綁定到數(shù)據(jù)的視覺元素會自動反映更改。 數(shù)據(jù)綁定可能還意味著如果視覺元素中數(shù)據(jù)的外部表現(xiàn)形式發(fā)生更改,則基礎(chǔ)數(shù)據(jù)可以自動更新以反映更改。
例如:如果用戶編輯 TextBox 元素中的值,則基礎(chǔ)數(shù)據(jù)值會自動更新以反映該更改。
1. 數(shù)據(jù)綁定涉及到兩個方面:
一個是綁定源,一個是綁定目標。綁定源即控件綁定所使用的源數(shù)據(jù),綁定目標即數(shù)據(jù)顯示的控件。
2. 對于綁定源,在WPF可以是以下四種:
•CLR對象:可以綁定到CLR類的公開的屬性、子屬性、索引器上。
•ADO.Net對象:例如DataTable、DataView等 。
•XML文件:使用XPath進行解析 。
•DependencyObject:綁定到其依賴項屬性上,即控件綁定控件 。
對于綁定目標,必須是WPF中的DependencyObject,將數(shù)據(jù)綁定到其依賴項屬性上。
二、 綁定的模式
1. 根據(jù)數(shù)據(jù)流的方向,WPF中的數(shù)據(jù)綁定分為以下四種:
OneWay 綁定:對源屬性的更改會自動更新目標屬性,但是對目標屬性的更改不會傳播回源屬性。此綁定類型適用于綁定的控件為隱式只讀控件的情況。
TwoWay 綁定:對源屬性的更改會自動更新目標屬性,而對目標屬性的更改也會自動更新源屬性。此綁定類型適用于可編輯窗體或其他完全交互式 UI 方案 。
OneWayToSource 與 OneWay 相反;它在目標屬性更改時更新源屬性。
OneTime綁定:該綁定會導(dǎo)致源屬性初始化目標屬性,但不傳播后續(xù)更改。
注釋:如果無需監(jiān)視目標屬性的更改,則使用 OneWay 綁定模式可避免 TwoWay 綁定模式的系統(tǒng)開銷。
大多數(shù)屬性都默認為 OneWay 綁定,但是一些依賴項屬性,通常為用戶可編輯的控件的屬性,如 TextBox 的 Text 屬性和 CheckBox 的 IsChecked 屬性,默認為 TwoWay 綁定。
如果要知道依賴項屬性綁定在默認情況下是單向還是雙向的編程方法可使用 GetMetadata 獲取屬性的屬性元數(shù)據(jù),然后檢查 BindsTwoWayByDefault 屬性的布爾值。
示例代碼:
代碼如下:
<Page x:Class="WpfDemo.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Page1" HorizontalAlignment="Center">
<Grid Name="GridTable" Height="360" Background="Silver">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="130"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="20"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Label Width="130" Height="25" Grid.Row="0" Grid.Column="0" Name="label1">TwoWay</Label>
<TextBox Width="150" Height="25" Grid.Row="0" Grid.Column="1" Name="textBox4" Text="{Binding ElementName=scrollBar1,Path=Value,Mode=TwoWay}" />
<Label Width="130" Height="25" Grid.Row="1" Grid.Column="0" Name="label2">OneWay</Label>
<TextBox Width="150" Height="25" Grid.Row="1" Grid.Column="1" Name="textBox1" Text="{Binding ElementName=scrollBar1, Path=Value,Mode=OneWay}"/>
<Label Width="130" Height="25" Grid.Row="2" Grid.Column="0" Name="label3">OneWayToSource</Label>
<TextBox Width="150" Height="25" Grid.Row="2" Grid.Column="1" Name="textBox2" Text="{Binding ElementName=scrollBar1, Path=Value,Mode=OneWayToSource}" />
<Label Width="130" Height="25" Grid.Row="3" Grid.Column="0" Name="label4">OneTime</Label>
<TextBox Width="150" Height="25" Grid.Row="3" Grid.Column="1" Name="textBox3" Text="{Binding ElementName=scrollBar1, Path=Value,Mode=OneTime}"/>
<ScrollBar Value="30" Minimum="0" Grid.RowSpan="4" Grid.Row="0" Grid.Column="2" Maximum="100" Name="scrollBar1" Width="18" Height="{Binding ElementName=GridTable,Path=Height}" />
</Grid>
</Page>
根據(jù)程序執(zhí)行結(jié)果,我們可以得到以下結(jié)論:
對于OneWay綁定:在界面中顯示的數(shù)據(jù)可以隨數(shù)據(jù)源的值的變化而變化,但更改界面的數(shù)據(jù)不會影響到數(shù)據(jù)源。
對于TwoWay綁定:界面中顯示的數(shù)據(jù)及數(shù)據(jù)源的數(shù)據(jù)可以雙向顯示及更新。
對于OneWayToSource綁定:初始時界面的數(shù)據(jù)為空;更改界面的數(shù)據(jù)可以影響數(shù)據(jù)源的值,但是更改數(shù)據(jù)源的值不會體現(xiàn)在界面上。
對于OneTime綁定:在界面中顯示的為數(shù)據(jù)源的初始值,更改數(shù)據(jù)源的值的時候,不會更改界面的數(shù)據(jù)顯示;更改界面的數(shù)據(jù)也不會影響到數(shù)據(jù)源的數(shù)據(jù)。
三、綁定目標值影響綁定源值條件
問題:綁定源的值是在您編輯文本的同時進行更新,還是在您結(jié)束編輯文本并將鼠標指針從文本框移走后才進行更新呢?或者在您需要更新的情況下在手動的更新呢?
1. UpdateSourceTrigger 屬性是確定觸發(fā)源更新的原因。
下圖中右箭頭的點演示 UpdateSourceTrigger 屬性的角色:
TwoWay及OneWayToSource是由綁定目標到綁定源方向,若實現(xiàn)綁定目標的值更改影響綁定源的值方式,只需要設(shè)置相應(yīng)控件綁定時的UpdateSourceTrigger的值,其值有三種:
PropertyChanged:當綁定目標屬性更改時,立即更新綁定源。
LostFocus:當綁定目標元素失去焦點時,更新綁定源。
Explicit:僅在調(diào)用 UpdateSource 方法時更新綁定源。
注釋:多數(shù)依賴項屬性的UpdateSourceTrigger 值的默認值為 PropertyChanged,而 Text 屬性的默認值為 LostFocus。
2. 示例
代碼如下:
XAML:
<Page x:Class="WpfDemo.Changed"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Changed">
<Grid Name="GridTable" Height="250" Background="Silver" Width="350">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
<ColumnDefinition Width="100"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Width="90" Height="25" Grid.Column="0" Name="label1" Text="PropertyChanged:"></TextBlock>
<TextBlock Grid.Row="1" Width="90" Height="25" Grid.Column="0" Name="label2" Text="LostFocus:"></TextBlock>
<TextBlock Grid.Row="2" Width="90" Height="25" Grid.Column="0" Name="label3" Text="Explicit:"></TextBlock>
<TextBox Grid.Row="0" Width="150" Height="25" Text="{Binding Path=UserName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Grid.Column="1" Name="TextBox1" />
<TextBox Grid.Row="1" Width="150" Height="25" Text="{Binding Path=UserName,Mode=TwoWay,UpdateSourceTrigger=LostFocus}" Grid.Column="1" Name="TextBox2" />
<TextBox Grid.Row="2" Width="150" Height="25" Text="{Binding Path=UserName,Mode=TwoWay,UpdateSourceTrigger=Explicit}" Grid.Column="1" Name="txtExplicit" />
<TextBlock Grid.Row="3" Width="90" Height="25" Grid.Column="0" Name="lblResult" Text="結(jié)果:"></TextBlock>
<TextBlock Grid.Row="3" Width="90" Height="25" Grid.Column="1" Name="lblDisplay" Text="{Binding Path=UserName,Mode=OneWay}"></TextBlock>
<Button Name="btnChanged" Width="90" Height="25" Grid.Row="3" Grid.Column="2">Explicit</Button>
</Grid>
</Page>
代碼如下:
C#:
namespace WpfDemo
{
public partial class Changed : Page
{
#region properties
public UserModel CurrentUser
{
get;set;
}
#endregion
#region Constructor
public Changed()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Changed_Loaded);
this.btnChanged.Click += new RoutedEventHandler(btnChanged_Click);
}
#endregion
#region Changed_Loaded
void Changed_Loaded(object sender, RoutedEventArgs e)
{
this.CurrentUser = new UserModel() {UserName="swd"};
this.DataContext = this.CurrentUser;
}
#endregion
#region btnLogon_Click
void btnChanged_Click(object sender, RoutedEventArgs e)
{
this.txtExplicit.GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
#endregion
}
public class UserModel
{
public string UserName
{
get;set;}
}
}
程序執(zhí)行結(jié)果如上所述。
四、 數(shù)據(jù)提供程序
1. XmlDataProvider:
XmlDataProvider訪問 XML 數(shù)據(jù)的方式有以下三種:
可以使用 XmlDataProvider 類嵌入內(nèi)聯(lián) XML 數(shù)據(jù)。
可以將 Source 屬性設(shè)置為 XML 數(shù)據(jù)文件的 Uri。
可以將 Document 屬性設(shè)置為 XmlDocument。
注釋:當 XmlDocument.NodeChanged 事件發(fā)生時,XmlDataProvider 執(zhí)行所有綁定的完全刷新。 特定節(jié)點不進行優(yōu)化。
默認情況下,XmlDataProvider.IsAsynchronous 屬性設(shè)置為 true,表示默認情況下 XmlDataProvider 檢索數(shù)據(jù)并異步生成 XML 節(jié)點的集合。
以下將介紹使用上面所述的三種方式顯示xml數(shù)據(jù):
示例
代碼如下:
Xaml:
<Page x:Class="WpfDemo.xmlBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="xmlBinding" xmlns:local="clr-namespace:WpfDemo">
<Page.Resources>
<XmlDataProvider x:Key="XmlFile" Source="Students.xml" XPath="/Students"></XmlDataProvider>
<XmlDataProvider x:Key="InnerXmlStu" XPath="/Students">
<x:XData>
<Students xmlns="">
<Student><name>swd</name></Student>
<Student><name>awd</name></Student>
<Student><name>asd</name></Student>
</Students>
</x:XData>
</XmlDataProvider>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"></ColumnDefinition>
<ColumnDefinition Width="150"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Height="25" Width="100" Text="引用XML文件"></TextBlock>
<TextBlock Grid.Row="1" Grid.Column="0" Height="25" Width="100" Text="內(nèi)嵌XML"></TextBlock>
<TextBlock Grid.Row="2" Grid.Column="0" Height="25" Width="100" Text="動態(tài)XML"></TextBlock>
<ListBox Name="lisbXmlFile" Grid.Row="0" Grid.Column="1" Height="100" Width="150" ItemsSource="{Binding Source={StaticResource XmlFile},XPath=Student/name}">
</ListBox>
<ListBox Name="lisbInnerXml" Grid.Row="1" Grid.Column="1" Height="100" Width="150" ItemsSource="{Binding Source={StaticResource InnerXmlStu},XPath=Student/name}">
</ListBox>
<ListBox Name="lisbXmlDoc" Grid.Row="2" Grid.Column="1" Height="100" Width="150" ItemsSource="{Binding XPath=Student/name}">
</ListBox>
</Grid>
</Page>
代碼如下:
XML:
<?xml version="1.0" encoding="utf-8" ?>
<Students>
<Student>
<name>swd</name>
<score>110</score>
</Student>
<Student>
<name>asd</name>
<score>120</score>
</Student>
<Student>
<name>awd</name>
<score>130</score>
</Student>
</Students>
通過以上示例我想大家應(yīng)該很容易理解與應(yīng)用。
2. ObjectDataProvider:
ObjectDataProvider 使您能夠在 XAML 中創(chuàng)建可用作綁定源的對象,并為您提供以下屬性,以對對象執(zhí)行查詢并綁定到結(jié)果。
使用 ConstructorParameters 屬性將參數(shù)傳遞給對象的構(gòu)造函數(shù)。
使用 MethodName 屬性調(diào)用一個方法。
使用 MethodParameters 屬性將參數(shù)傳遞給該方法。 然后,可以綁定到該方法的結(jié)果。
使用ObjectType 指定將提供數(shù)據(jù)綁定源的對象。
使用 ObjectInstance 屬性來指定現(xiàn)有的對象實例作為源
注釋:還可以使用 IsAsynchronous 屬性指定是在輔助線程還是在活動上下文中執(zhí)行對象創(chuàng)建。也就是是否異步檢索數(shù)據(jù)。
示例:
代碼如下:
XAML:
C#:
namespace WpfDemo
{
#region CObjectDataProvider
public partial class CObjectDataProvider : Page
{
public CObjectDataProvider()
{InitializeComponent();}
}
#endregion
#region Country
public class Country
{
#region Name
public string Name
{get;set;}
#endregion
#region ProvinceList
public List<Province> ProvinceList
{get;set;}
#endregion
#region GetAllCity
public static List<Country> GetAllCity()
{
return new List<Country>{
new Country
{
Name = "中國",
ProvinceList = new List<Province>
{
new Province{ Name="福建省",
CityList=new List<City>{new City{Name="福州市"},new City{Name="廈門市"},new City{Name="漳州市"},new City{Name="泉州市"}}
},
new Province{Name="江蘇省",
CityList=new List<City>{
new City{Name="蘇州市"},new City{Name="南京市"},new City{Name="揚州市"},new City{Name="無錫市"}}
},
new Province{Name="江西省",
CityList=new List<City>{new City{Name="南昌市"},new City{Name="九江市"}}}}
}
};
}
#endregion
}
#endregion
#region Province
public class Province
{
#region Name
public string Name
{get;set;}
#endregion
#region CityList
public List<City> CityList
{get;set;}
#endregion
}
#endregion
#region City
public class City
{
#region Name
public string Name
{get;set;}
#endregion
}
#endregion
}
五、類型轉(zhuǎn)換與數(shù)據(jù)校驗
1. IValueConverter接口
提供一種將自定義邏輯應(yīng)用于綁定的方式。
在Binding時,數(shù)據(jù)源對象到目標對象之間(或者目標對象到數(shù)據(jù)源對象)可能需要某種轉(zhuǎn)換。這時只需實現(xiàn)IValueConverter接口自定義值轉(zhuǎn)換器即可。
接口原型定義:
public interface IValueConverter
{
object Convert(object value, Type targetType, object parameter, CultureInfo culture);
object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
參數(shù)value是要轉(zhuǎn)換的值,typeTarget是轉(zhuǎn)換后的值類型,parameter是Binding 類的 ConverterParameter傳遞過來的參數(shù)。
Convert方法:數(shù)據(jù)綁定引擎在將值從綁定源傳播給綁定目標時,調(diào)用此方法。
ConvertBack方法:數(shù)據(jù)綁定引擎在將值從綁定目標傳播給綁定源時,調(diào)用此方法。
ValueConversion屬性作用是告訴自定義轉(zhuǎn)換器類可以轉(zhuǎn)換的源數(shù)據(jù)和目標數(shù)據(jù)的 類型(ValueConversion屬性將在稍后的示例中看到)。
2. ValidationRule類
提供一種為檢查用戶輸入的有效性而創(chuàng)建自定義規(guī)則的方法。
ValidationRule : 所有自定義驗證規(guī)則的基類。提供了讓用戶定義驗證規(guī)則的入口。
ExceptionValidation :表示一個規(guī)則,該規(guī)則檢查在綁定源屬性更新過程中引發(fā)的異常。它是一個內(nèi)置的規(guī)則,它檢查在綁定源屬性更新過程中引發(fā)的異常。
ValidationResult : 數(shù)據(jù)驗證結(jié)果的表現(xiàn)方式。ValidationRule對象的Validate方法執(zhí)行完畢后通過ValidationResult來表示驗證的結(jié)果。這里包含了錯誤信息—ErrorContent,數(shù)據(jù)是否有效—IsValid。ValidResult 為 ValidationResult 的有效實例。
ValidationError :表示一個驗證錯誤,該錯誤在 ValidationRule 報告驗證錯誤時由綁定引擎創(chuàng)建。
代碼如下:
XAML:
<Page x:Class="WpfDemo.TypeConvertAndValidationRule"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="TypeConvertAndValidationRule"
xmlns:src="clr-namespace:WpfDemo">
<Grid Height="250" Width="360" Background="Silver">
<Grid.RowDefinitions>
<RowDefinition>
</RowDefinition>
<RowDefinition>
</RowDefinition>
<RowDefinition>
</RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition>
</ColumnDefinition>
<ColumnDefinition>
</ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Height="25" Width="100" Text="生日" Grid.Row="0" Grid.Column="0"></TextBlock>
<TextBox Name="txtBirthday" Height="25" Width="150" Grid.Row="0" Grid.Column="1">
<TextBox.Text>
<Binding Path="Birthday" UpdateSourceTrigger="LostFocus" Mode="TwoWay">
<Binding.ValidationRules><src:ValidationDateTimeRule/></Binding.ValidationRules>
<Binding.Converter><src:MyConverterOfBirthFormat/></Binding.Converter>
</Binding>
</TextBox.Text>
<TextBox.ToolTip>
<Binding RelativeSource="{RelativeSource Self}" Path="(Validation.Errors) [0].ErrorContent"></Binding>
</TextBox.ToolTip> </TextBox>
<TextBlock Height="25" Width="150" Grid.Row="1" Text="{Binding Path=Birthday,Mode=OneWay}" Grid.Column="1"></TextBlock>
<TextBlock Height="25" Width="100" Text="電子郵件格式檢查" Grid.Row="2" Grid.Column="0"></TextBlock>
<TextBox Height="25" Width="150" Grid.Row="2" Grid.Column="1">
<TextBox.Text>
<Binding Path="EMail">
<Binding.ValidationRules><ExceptionValidationRule /></Binding.ValidationRules>
</Binding> </TextBox.Text>
<TextBox.ToolTip>
<Binding RelativeSource="{RelativeSource Self}" Path="(Validation.Errors)[0].ErrorContent"></Binding>
</TextBox.ToolTip> </TextBox>
</Grid>
</Page>
代碼如下:
C#:
namespace WpfDemo
{
#region TypeConvertAndValidationRule
public partial class TypeConvertAndValidationRule : Page
{
public TypeConvertAndValidationRule()
{
InitializeComponent();
this.DataContext = new UserInfo { Name = "swd", Birthday =System.Convert.ToDateTime("1987/10/21"), EMail = "swd@126.com" };
}
}
#endregion
#region UserInfo
public class UserInfo
{
#region Name
public string Name
{get;set;}
#endregion
#region Birthday
public DateTime Birthday
{get;set;}
#endregion
#region EMail
private string email;
public string EMail
{
get
{return email;}
set
{
this.email = value;
Regex r = new Regex(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$");
if (!r.IsMatch(value))
{
throw new ApplicationException("電子郵件格式有誤!");
}
}
}
#endregion
}
#endregion
六、 綁定集合對象
1. ICollectionView接口
允許集合具有當前記錄管理、自定義排序、篩選和分組這些功能。比如排序,分組,篩選,導(dǎo)航以及其它自定義視圖,并且這不會影響到你的后臺數(shù)據(jù)的實際存儲。
2. ObservableCollection <T> 類
表示一個動態(tài)數(shù)據(jù)集合,在添加項、移除項或刷新整個列表時,此集合將提供通知。
3. WPF MVVM概要
MVVM(Model-View-ViewModel)是由MVC,MVP演變而來。MVVM分離了邏輯與界面,解放業(yè)務(wù)邏輯。
聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com