一、WPF數(shù)據(jù)綁定的概要
數(shù)據(jù)綁定:是應(yīng)用程序 UI 與業(yè)務(wù)邏輯之間建立連接的過(guò)程。 如果綁定正確設(shè)置并且數(shù)據(jù)提供正確通知,則當(dāng)數(shù)據(jù)的值發(fā)生更改時(shí),綁定到數(shù)據(jù)的視覺(jué)元素會(huì)自動(dòng)反映更改。 數(shù)據(jù)綁定可能還意味著如果視覺(jué)元素中數(shù)據(jù)的外部表現(xiàn)形式發(fā)生更改,則基礎(chǔ)數(shù)據(jù)可以自動(dòng)更新以反映更改。
例如:如果用戶(hù)編輯 TextBox 元素中的值,則基礎(chǔ)數(shù)據(jù)值會(huì)自動(dòng)更新以反映該更改。
1. 數(shù)據(jù)綁定涉及到兩個(gè)方面:
一個(gè)是綁定源,一個(gè)是綁定目標(biāo)。綁定源即控件綁定所使用的源數(shù)據(jù),綁定目標(biāo)即數(shù)據(jù)顯示的控件。
2. 對(duì)于綁定源,在WPF可以是以下四種:
•CLR對(duì)象:可以綁定到CLR類(lèi)的公開(kāi)的屬性、子屬性、索引器上。
•ADO.Net對(duì)象:例如DataTable、DataView等 。
•XML文件:使用XPath進(jìn)行解析 。
•DependencyObject:綁定到其依賴(lài)項(xiàng)屬性上,即控件綁定控件 。
對(duì)于綁定目標(biāo),必須是WPF中的DependencyObject,將數(shù)據(jù)綁定到其依賴(lài)項(xiàng)屬性上。
二、 綁定的模式
1. 根據(jù)數(shù)據(jù)流的方向,WPF中的數(shù)據(jù)綁定分為以下四種:
OneWay 綁定:對(duì)源屬性的更改會(huì)自動(dòng)更新目標(biāo)屬性,但是對(duì)目標(biāo)屬性的更改不會(huì)傳播回源屬性。此綁定類(lèi)型適用于綁定的控件為隱式只讀控件的情況。
TwoWay 綁定:對(duì)源屬性的更改會(huì)自動(dòng)更新目標(biāo)屬性,而對(duì)目標(biāo)屬性的更改也會(huì)自動(dòng)更新源屬性。此綁定類(lèi)型適用于可編輯窗體或其他完全交互式 UI 方案 。
OneWayToSource 與 OneWay 相反;它在目標(biāo)屬性更改時(shí)更新源屬性。
OneTime綁定:該綁定會(huì)導(dǎo)致源屬性初始化目標(biāo)屬性,但不傳播后續(xù)更改。
注釋?zhuān)喝绻麩o(wú)需監(jiān)視目標(biāo)屬性的更改,則使用 OneWay 綁定模式可避免 TwoWay 綁定模式的系統(tǒng)開(kāi)銷(xiāo)。
大多數(shù)屬性都默認(rèn)為 OneWay 綁定,但是一些依賴(lài)項(xiàng)屬性,通常為用戶(hù)可編輯的控件的屬性,如 TextBox 的 Text 屬性和 CheckBox 的 IsChecked 屬性,默認(rèn)為 TwoWay 綁定。
如果要知道依賴(lài)項(xiàng)屬性綁定在默認(rèn)情況下是單向還是雙向的編程方法可使用 GetMetadata 獲取屬性的屬性元數(shù)據(jù),然后檢查 BindsTwoWayByDefault 屬性的布爾值。
示例代碼:
復(fù)制代碼 代碼如下:
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é)論:
對(duì)于OneWay綁定:在界面中顯示的數(shù)據(jù)可以隨數(shù)據(jù)源的值的變化而變化,但更改界面的數(shù)據(jù)不會(huì)影響到數(shù)據(jù)源。
對(duì)于TwoWay綁定:界面中顯示的數(shù)據(jù)及數(shù)據(jù)源的數(shù)據(jù)可以雙向顯示及更新。
對(duì)于OneWayToSource綁定:初始時(shí)界面的數(shù)據(jù)為空;更改界面的數(shù)據(jù)可以影響數(shù)據(jù)源的值,但是更改數(shù)據(jù)源的值不會(huì)體現(xiàn)在界面上。
對(duì)于OneTime綁定:在界面中顯示的為數(shù)據(jù)源的初始值,更改數(shù)據(jù)源的值的時(shí)候,不會(huì)更改界面的數(shù)據(jù)顯示;更改界面的數(shù)據(jù)也不會(huì)影響到數(shù)據(jù)源的數(shù)據(jù)。
三、綁定目標(biāo)值影響綁定源值條件
問(wèn)題:綁定源的值是在您編輯文本的同時(shí)進(jìn)行更新,還是在您結(jié)束編輯文本并將鼠標(biāo)指針從文本框移走后才進(jìn)行更新呢?或者在您需要更新的情況下在手動(dòng)的更新呢?
1. UpdateSourceTrigger 屬性是確定觸發(fā)源更新的原因。
下圖中右箭頭的點(diǎn)演示 UpdateSourceTrigger 屬性的角色:
TwoWay及OneWayToSource是由綁定目標(biāo)到綁定源方向,若實(shí)現(xiàn)綁定目標(biāo)的值更改影響綁定源的值方式,只需要設(shè)置相應(yīng)控件綁定時(shí)的UpdateSourceTrigger的值,其值有三種:
PropertyChanged:當(dāng)綁定目標(biāo)屬性更改時(shí),立即更新綁定源。
LostFocus:當(dāng)綁定目標(biāo)元素失去焦點(diǎn)時(shí),更新綁定源。
Explicit:僅在調(diào)用 UpdateSource 方法時(shí)更新綁定源。
注釋?zhuān)憾鄶?shù)依賴(lài)項(xiàng)屬性的UpdateSourceTrigger 值的默認(rèn)值為 PropertyChanged,而 Text 屬性的默認(rèn)值為 LostFocus。
2. 示例
復(fù)制代碼 代碼如下:
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>
復(fù)制代碼 代碼如下:
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訪問(wèn) XML 數(shù)據(jù)的方式有以下三種:
可以使用 XmlDataProvider 類(lèi)嵌入內(nèi)聯(lián) XML 數(shù)據(jù)。
可以將 Source 屬性設(shè)置為 XML 數(shù)據(jù)文件的 Uri。
可以將 Document 屬性設(shè)置為 XmlDocument。
注釋?zhuān)寒?dāng) XmlDocument.NodeChanged 事件發(fā)生時(shí),XmlDataProvider 執(zhí)行所有綁定的完全刷新。 特定節(jié)點(diǎn)不進(jìn)行優(yōu)化。
默認(rèn)情況下,XmlDataProvider.IsAsynchronous 屬性設(shè)置為 true,表示默認(rèn)情況下 XmlDataProvider 檢索數(shù)據(jù)并異步生成 XML 節(jié)點(diǎn)的集合。
以下將介紹使用上面所述的三種方式顯示xml數(shù)據(jù):
示例
復(fù)制代碼 代碼如下:
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="動(dòng)態(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>
復(fù)制代碼 代碼如下:
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>
通過(guò)以上示例我想大家應(yīng)該很容易理解與應(yīng)用。
2. ObjectDataProvider:
ObjectDataProvider 使您能夠在 XAML 中創(chuàng)建可用作綁定源的對(duì)象,并為您提供以下屬性,以對(duì)對(duì)象執(zhí)行查詢(xún)并綁定到結(jié)果。
使用 ConstructorParameters 屬性將參數(shù)傳遞給對(duì)象的構(gòu)造函數(shù)。
使用 MethodName 屬性調(diào)用一個(gè)方法。
使用 MethodParameters 屬性將參數(shù)傳遞給該方法。 然后,可以綁定到該方法的結(jié)果。
使用ObjectType 指定將提供數(shù)據(jù)綁定源的對(duì)象。
使用 ObjectInstance 屬性來(lái)指定現(xiàn)有的對(duì)象實(shí)例作為源
注釋?zhuān)哼€可以使用 IsAsynchronous 屬性指定是在輔助線程還是在活動(dòng)上下文中執(zhí)行對(duì)象創(chuàng)建。也就是是否異步檢索數(shù)據(jù)。
示例:
復(fù)制代碼 代碼如下:
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 ListProvince> ProvinceList
{get;set;}
#endregion
#region GetAllCity
public static ListCountry> GetAllCity()
{
return new ListCountry>{
new Country
{
Name = "中國(guó)",
ProvinceList = new ListProvince>
{
new Province{ Name="福建省",
CityList=new ListCity>{new City{Name="福州市"},new City{Name="廈門(mén)市"},new City{Name="漳州市"},new City{Name="泉州市"}}
},
new Province{Name="江蘇省",
CityList=new ListCity>{
new City{Name="蘇州市"},new City{Name="南京市"},new City{Name="揚(yáng)州市"},new City{Name="無(wú)錫市"}}
},
new Province{Name="江西省",
CityList=new ListCity>{new City{Name="南昌市"},new City{Name="九江市"}}}}
}
};
}
#endregion
}
#endregion
#region Province
public class Province
{
#region Name
public string Name
{get;set;}
#endregion
#region CityList
public ListCity> CityList
{get;set;}
#endregion
}
#endregion
#region City
public class City
{
#region Name
public string Name
{get;set;}
#endregion
}
#endregion
}
五、類(lèi)型轉(zhuǎn)換與數(shù)據(jù)校驗(yàn)
1. IValueConverter接口
提供一種將自定義邏輯應(yīng)用于綁定的方式。
在Binding時(shí),數(shù)據(jù)源對(duì)象到目標(biāo)對(duì)象之間(或者目標(biāo)對(duì)象到數(shù)據(jù)源對(duì)象)可能需要某種轉(zhuǎn)換。這時(shí)只需實(shí)現(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)換后的值類(lèi)型,parameter是Binding 類(lèi)的 ConverterParameter傳遞過(guò)來(lái)的參數(shù)。
Convert方法:數(shù)據(jù)綁定引擎在將值從綁定源傳播給綁定目標(biāo)時(shí),調(diào)用此方法。
ConvertBack方法:數(shù)據(jù)綁定引擎在將值從綁定目標(biāo)傳播給綁定源時(shí),調(diào)用此方法。
ValueConversion屬性作用是告訴自定義轉(zhuǎn)換器類(lèi)可以轉(zhuǎn)換的源數(shù)據(jù)和目標(biāo)數(shù)據(jù)的 類(lèi)型(ValueConversion屬性將在稍后的示例中看到)。
2. ValidationRule類(lèi)
提供一種為檢查用戶(hù)輸入的有效性而創(chuàng)建自定義規(guī)則的方法。
ValidationRule : 所有自定義驗(yàn)證規(guī)則的基類(lèi)。提供了讓用戶(hù)定義驗(yàn)證規(guī)則的入口。
ExceptionValidation :表示一個(gè)規(guī)則,該規(guī)則檢查在綁定源屬性更新過(guò)程中引發(fā)的異常。它是一個(gè)內(nèi)置的規(guī)則,它檢查在綁定源屬性更新過(guò)程中引發(fā)的異常。
ValidationResult : 數(shù)據(jù)驗(yàn)證結(jié)果的表現(xiàn)方式。ValidationRule對(duì)象的Validate方法執(zhí)行完畢后通過(guò)ValidationResult來(lái)表示驗(yàn)證的結(jié)果。這里包含了錯(cuò)誤信息—ErrorContent,數(shù)據(jù)是否有效—IsValid。ValidResult 為 ValidationResult 的有效實(shí)例。
ValidationError :表示一個(gè)驗(yàn)證錯(cuò)誤,該錯(cuò)誤在 ValidationRule 報(bào)告驗(yàn)證錯(cuò)誤時(shí)由綁定引擎創(chuàng)建。
復(fù)制代碼 代碼如下:
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>
復(fù)制代碼 代碼如下:
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
六、 綁定集合對(duì)象
1. ICollectionView接口
允許集合具有當(dāng)前記錄管理、自定義排序、篩選和分組這些功能。比如排序,分組,篩選,導(dǎo)航以及其它自定義視圖,并且這不會(huì)影響到你的后臺(tái)數(shù)據(jù)的實(shí)際存儲(chǔ)。
2. ObservableCollection T> 類(lèi)
表示一個(gè)動(dòng)態(tài)數(shù)據(jù)集合,在添加項(xiàng)、移除項(xiàng)或刷新整個(gè)列表時(shí),此集合將提供通知。
3. WPF MVVM概要
MVVM(Model-View-ViewModel)是由MVC,MVP演變而來(lái)。MVVM分離了邏輯與界面,解放業(yè)務(wù)邏輯。
您可能感興趣的文章:- WPF自定義控件和樣式之自定義按鈕(Button)
- wpf將表中數(shù)據(jù)顯示到datagrid示例
- 在WinForm和WPF中使用GMap.Net地圖插件簡(jiǎn)單教程
- 仿vs實(shí)現(xiàn)WPF好看的進(jìn)度條
- WPF彈出自定義窗口的方法
- WPF實(shí)現(xiàn)漸變淡入淡出的登陸窗口效果
- WPF如何自定義TabControl控件樣式示例詳解
- C# WPF ListView控件的實(shí)例詳解
- WPF應(yīng)用啟動(dòng)慢的問(wèn)題解決