上一篇我們將 "XAML" 大概做了個瞭解 ,這篇將繼續學習WPF數據綁定的相關內容 數據源與控制項的Binding 作為數據傳送UI的通道,通過 介面的 事件通知 數據屬性發生改變 通過Binding關聯UI控制項元素 控制項之間的Binding 我們也可以通過後臺C 代碼實現 統計文本字元長度 Bin ...
上一篇我們將XAML大概做了個瞭解 ,這篇將繼續學習WPF數據綁定的相關內容
數據源與控制項的Binding
Binding
作為數據傳送UI的通道,通過INotityPropertyChanged
介面的PropertyChanged
事件通知Binding
數據屬性發生改變
public class Product : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
if (PropertyChanged != null)
{
this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Name"));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
通過Binding關聯UI控制項元素
this.txtOfProduct.SetBinding(TextBox.TextProperty, new Binding() { Path = new PropertyPath("Name"), Source = p });
控制項之間的Binding
<TextBox x:Name="TextBox1" Text="{Binding ElementName=slider1,Path=Value,Mode=OneWay}"></TextBox>
<Slider x:Name="slider1" Margin="5"></Slider>
我們也可以通過後臺C#代碼實現
TextBox1.SetBinding(TextBox.TextProperty, new Binding("Value") { ElementName = "slider1", Mode=BindingMode.OneWay });
統計文本字元長度
<TextBox x:Name="TextBox1" Margin="5" TextWrapping="Wrap" ></TextBox>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.Length}"></TextBlock>
Binding的Path
Path的索引器方式
<TextBox x:Name="TextBox1" Margin="5" TextWrapping="Wrap" ></TextBox>
<!--獲取Text的第三個字元-->
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text.[2]}"></TextBlock>
<TextBlock Margin="5" TextAlignment="Right" Text="{Binding ElementName=TextBox1, Path=Text[2]}"></TextBlock>
當使用一個集合或者DataView
作為Binding
源時,如果我們想把它的預設元素作為Path來使用
List<string> names = new List<string>() { "張三", "李四", "王五" };
//張三
this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("/") { Source = names });
//“張三”字元串的長度
this.TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Length") { Source = names,Mode=BindingMode.OneWay});
//獲取“張三”字元串中的第1個字元
this.TextBox3.SetBinding(TextBox.TextProperty, new Binding("/[0]") { Source = names, Mode = BindingMode.OneWay });
如果集合中嵌套集合,我們依然可以通過多級"/"語法把子集作為Path的元素
class City
{
public string Name { get; set; }
}
class Province
{
public List<City> Citys { get; set; }
public string Name { get; set; }
}
class Country
{
public List<Province> Provinces { get; set; }
public string Name { get; set; }
}
TextBox1.SetBinding(TextBox.TextProperty, new Binding("/Name") { Source = countries });
TextBox2.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Name") { Source = countries });
TextBox3.SetBinding(TextBox.TextProperty, new Binding("/Provinces/Citys/Name") { Source = countries });
省略Path
sys
需要引用xmlns:sys="clr-namespace:System;assembly=mscorlib"
<StackPanel.Resources>
<sys:String x:Key="text">
WPF入門手冊
</sys:String>
</StackPanel.Resources>
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding .,Source={StaticResource ResourceKey=text}}" ></TextBox>
TextBox2.SetBinding(TextBox.TextProperty, new Binding(".") { Source = "WPF技術入門" });
沒有Path和Source,Binding可以通過DataContext獲取數據
<StackPanel.DataContext>
<sys:String>
WPF入門手冊
</sys:String>
</StackPanel.DataContext>
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding Mode=OneWay}" ></TextBox>
選中ListBox元素顯示對應的屬性的一個例子
<TextBox x:Name="TextBox1" Margin="5" ></TextBox>
<ListBox x:Name="ListBox1"></ListBox>
List<City> cities = new List<City>() {
new City() { Id=1,Name="北京" },
new City() { Id=2,Name="昆明" },
new City() { Id=3,Name="上海" },
new City() { Id=4,Name="廈門" },
new City() { Id=5,Name="廣州" }
};
this.ListBox1.ItemsSource = cities;
this.ListBox1.DisplayMemberPath = "Name";
this.TextBox1.SetBinding(TextBox.TextProperty, new Binding("SelectedItem.Id") { Source = this.ListBox1 });
使用Binding的RelativeSource
當Binding
有明確的數據源的時,我們可以通過Soure
或ElementName
賦值辦法關聯Binding
,但有事我們不知道Soure
對象的名字是什麼,卻知道它與作為Binding
目標對象的UI元素佈局上的相對關係,通過RelativeSourceMode
枚舉設置關聯的對象關係
<Grid x:Name="g1">
<StackPanel x:Name="s1">
<DockPanel x:Name="d1">
<TextBox x:Name="TextBox1" Margin="5" ></TextBox>
</DockPanel>
</StackPanel>
</Grid>
後臺代碼處理
RelativeSource rs = new RelativeSource(RelativeSourceMode.FindAncestor)
{
AncestorLevel = 1,
AncestorType = typeof(StackPanel)
};
//將StackPanel的Name s1賦給了TextBox1的Text
TextBox1.SetBinding(TextBox.TextProperty, new Binding("Name") { RelativeSource = rs });
也可以通過XAML的方式賦值
<Grid x:Name="g1">
<StackPanel x:Name="s1">
<DockPanel x:Name="d1">
<TextBox x:Name="TextBox1" Margin="5" Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type DockPanel},AncestorLevel=1,Mode=FindAncestor}, Path=Name}" ></TextBox>
</DockPanel>
</StackPanel>
</Grid>
Binding數據驗證
Binding
的ValidationRules
屬性的類型為Collection<ValidationRule>
。通過實現Validate
方法返回給ValidationResult
對象,並設置IsVaild
屬性,ErrorContent
屬性可以接受一個字元串。
public class RangValidationRule : ValidationRule
{
//驗證數據
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
double d = 0;
if (double.TryParse(value.ToString(), out d))
{
if (d >= 1 && d <= 100)
{
return new ValidationResult(true, null);
}
}
return new ValidationResult(false, "數據錯誤");
}
}
<TextBox x:Name="TextBox1" Margin="5"></TextBox>
<Slider x:Name="slider1" Minimum="1" Maximum="100" Margin="5"></Slider>
Binding binding = new Binding("Value") {
Source=slider1,
UpdateSourceTrigger=UpdateSourceTrigger.PropertyChanged,
};
binding.ValidationRules.Add(new RangValidationRule());
this.TextBox1.SetBinding(TextBox.TextProperty, binding);
顯示錯誤提示
public MainWindow()
{
InitializeComponent();
Binding binding = new Binding("Value")
{
Source = slider1,
UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
NotifyOnValidationError = true//開啟錯誤通知
};
binding.ValidationRules.Add(new RangValidationRule());
this.TextBox1.SetBinding(TextBox.TextProperty, binding);
//註冊驗證錯誤事件
this.TextBox1.AddHandler(Validation.ErrorEvent, new RoutedEventHandler(ValidationErrorNotify));
}
private void ValidationErrorNotify(object sender, RoutedEventArgs e)
{
var errors = Validation.GetErrors(this.TextBox1);
if (errors.Count > 0)
{
TextBlock1.Text = errors[0].ErrorContent.ToString();
}
}
多路Binding
一般我們在做註冊用戶功能的時候,輸入密碼的時候都需要再確認輸入密碼,比較兩次輸入是否一致,現在我們可以通過多路Binding來簡單的實現這個功能
首先實現一個IMultiValueConverter
介面功能,如果兩次密碼一致,提交按鈕狀態為可用
public class SubmitMultiBindingConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
return (!values.Cast<string>().Any(a => string.IsNullOrEmpty(a))/*驗證所有元素非空*/ &&
values[0].ToString() == values[1].ToString())/*值1=值2*/;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
XAML代碼
<TextBox x:Name="Password" Margin="5"></TextBox>
<TextBox x:Name="Passworder" Margin="5"></TextBox>
<Button x:Name="Submit" Content="提交" Margin="10" Height="30" Width="100"></Button>
後臺Binding
Binding pwdBinding = new Binding("Text") { Source = Password };
Binding pwderBinding = new Binding("Text") { Source = Passworder };
MultiBinding multi = new MultiBinding() { Mode=BindingMode.OneWay};
multi.Bindings.Add(pwdBinding);
multi.Bindings.Add(pwderBinding);
multi.Converter = new SubmitMultiBindingConverter();
Submit.SetBinding(Button.IsEnabledProperty, multi);
以上就是Binding常用到的功能,下篇我將繼續學習依賴屬性和WPF路由事件的相關內容