赞
踩
一些总结
修改对象 = binding 数据源
数据绑定
绑定源
1、CLR对象(实体):可以绑定到CLR类的公开的属性、子属性、索引器上
2、ADO.Net对象(数据库):例如DataTable、DataView等
3、XML文件:使用xPath进行解析
4、DependencyObject(依赖对象):绑定到其依赖项属性上,即控件绑定控件
绑定目标
对于绑定目标,必须是WPF中的DependencyObject,将数据绑定到其依赖项属性上。
(依赖属性里自带数据更新功能)
绑定属性
创建新的窗口的时候,记得在app.xaml里面的StartupUrl里修改位置
这段代码结果为,在上面的TextBlock输入后,自动会显示在下面的TextBlock里
<StackPanel Margin="10">
<TextBox Name="txtBingSource"/>
<WrapPanel>
<TextBlock Text="Value:" FontWeight="Bold"/>
<!--
{binding ElementName=xxx,Path=Text} ElementName 指的是绑定对象 Path 指的是绑定属性
绑定属性必须是依赖属性,Text属性如何确定是依赖属性呢?
-->
<TextBox Text="{Binding ElementName=txtBingSource,Path=Text}"/>
</WrapPanel>
</StackPanel>
DataContext属性
1、创建一个新的窗体(这个title、width、height是界面的大小)
2、在窗体的cs文件里加上DataContext就可以更便捷的使用了
<StackPanel>
<WrapPanel>
<TextBlock Text="窗口的标题为:"/>
<TextBox Text="{Binding Path=Title}" Width="150"/>
</WrapPanel>
<WrapPanel Margin="0 10 0 0 ">
<TextBlock Text="窗口的宽度为:"/>
<!-- 直接Binding Width 是一种简便方式-->
<TextBox Text="{Binding Width}" Width="50"/>
<TextBlock Text="窗口的高度为:"/>
<TextBox Text="{Binding Height}" Width="50"/>
</WrapPanel>
</StackPanel>
public partial class DataContextSample : Window
{
public DataContextSample()
{
InitializeComponent();
// 设置窗口的数据上下文对象
this.DataContext = this;
}
}
后台代码数据绑定
1、创建一个新的窗口
2、在后台内绑定数据
<StackPanel Margin="10">
<TextBox Name="txtBindingSource"/>
<WrapPanel>
<TextBlock Text="Value:" FontWeight="Bold"/>
<TextBlock Name="lbValue"/>
</WrapPanel>
</StackPanel>
public BindingBackend() { InitializeComponent(); // 绑定前端控件显示数据 BindingData(); } private void BindingData() { // 创建绑定对象 var binding = new Binding("Text"); // 设置绑定源 binding.Source = txtBindingSource; // 设置绑定目标 lbValue.SetBinding(TextBlock.TextProperty,binding); }
UpdateSourcetrigger属性
个人理解是及时更新
Explicit–必须手动更新数据源
LostFocus–失去焦点后就修改数值
PropertyChanged–时刻在变化
<StackPanel Margin="10">
<WrapPanel>
<TextBlock Text="窗口标题:"/>
<TextBox Name="txtWindowTitle" Text="{Binding Title,UpdateSourceTrigger=Explicit}" Width="150"/>
<Button Name="BtnUpdateSource" Content="更新源" Click="BtnUpdateSource_Click"/>
</WrapPanel>
<WrapPanel Margin="0 10 0 0">
<TextBlock Text="窗口尺寸:"/>
<TextBox Text="{Binding Width,UpdateSourceTrigger=LostFocus}" Width="50"/>
<TextBlock Text="x"/>
<TextBox Text="{Binding Height,UpdateSourceTrigger=PropertyChanged}" Width="50"/>
</WrapPanel>
</StackPanel>
public UpdateSourceTriggerSamples()
{
InitializeComponent();
this.DataContext = this;
}
private void BtnUpdateSource_Click(object sender, RoutedEventArgs e)
{
// 通过文本框对象获取绑定表达式对象
var binding = txtWindowTitle.GetBindingExpression(TextBox.TextProperty);
// 手动更行绑定对象
binding.UpdateSource();
}
数据更新
<StackPanel Margin="20">
<TextBox Width="150" Text="{Binding Name}"/>
<Button Margin="0 10 0 0" Content="更新源" Name="BtnUpdateSource" Click="BtnUpdateSource_Click" Width="150"/>
</StackPanel>
public partial class DataUpdateDemo : Window { User user = new User(); public DataUpdateDemo() { InitializeComponent(); // 创建user对象 user.Name = "Gerry"; // 指定窗口DataContext窗口 this.DataContext= user; } private void BtnUpdateSource_Click(object sender, RoutedEventArgs e) { this.user.Name = "Update userInfo"; // 后台的user数据已经发生改变了,但是ui界面的没有变化 } } /// <summary> /// 创建user类 让源头(发生改变的源头)继承接口 /// </summary> public class User : INotifyPropertyChanged { private string? _name; public string? Name { get { return _name; } set { _name = value; OnPropertyChanged(nameof(Name)); // 当值每次发生变化的时候 } } public event PropertyChangedEventHandler? PropertyChanged; /// <summary> /// 当指定的某个属性发生变化的时候对界面UI的线程推送更新消息 /// </summary> /// <param name="propertyName"></param> public void OnPropertyChanged(string propertyName) { if(PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } }
ObservableCollection完成列表更新
<DockPanel Margin="20">
<StackPanel DockPanel.Dock="Right" Margin="10 0 0 0">
<Button Name="BtnAdd" Content="新增用户" Click="BtnAdd_Click"/>
<Button Name="BtnUpdate" Content="修改用户" Click="BtnUpdate_Click" Margin="0 5 0 5"/>
<Button Name="BtnDelete" Content="删除用户" Click="BtnDelete_Click"/>
</StackPanel>
<ListBox Name="lbUsers" DisplayMemberPath="Name"/>
</DockPanel>
public partial class DataUpdateDemo2 : Window { //private List<UserInfo> users = new List<UserInfo>(); private ObservableCollection<UserInfo> users = new ObservableCollection<UserInfo>(); public DataUpdateDemo2() { InitializeComponent(); //初始化集合中的元素 一个新的方法 InitializeUsers(); // 绑定用户集合到列表框 lbUsers.ItemsSource = users; } private void InitializeUsers() { users.Add(new UserInfo { Name = ".Net Core" }); users.Add(new UserInfo { Name = ".Net Framework" }); } private void BtnAdd_Click(object sender, RoutedEventArgs e) { users.Add(new UserInfo { Name = "Python" }); } private void BtnUpdate_Click(object sender, RoutedEventArgs e) { if(lbUsers.SelectedItems != null) { (lbUsers.SelectedItem as UserInfo)!.Name = "Golang"; } } private void BtnDelete_Click(object sender, RoutedEventArgs e) { if(lbUsers.SelectedItem != null) { users.Remove(lbUsers.SelectedItem as UserInfo); } } } public class UserInfo : INotifyPropertyChanged { private string? _name; public string? Name { get { return _name; } set { _name = value; OnPropertyChanged(nameof(Name)); } } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged(string propertyName) { if(PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } }
类型转换器(自定义转换器)
加入输入yes,就和输入true一样
//使用方法,先放在资源里面,再在下面调用
<Window.Resources>
<local:BooleanConverter x:Key="booleanConverter"/>
</Window.Resources>
<StackPanel Margin="20">
<TextBox Name="txtValue"/>
<WrapPanel Margin="0 20">
<TextBlock Text="输入的值为:"/>
<TextBlock Text="{Binding ElementName=txtValue,Path=Text,Converter={StaticResource booleanConverter}}"/>
</WrapPanel>
<CheckBox Content="YES" IsChecked="{Binding ElementName=txtValue,Path=Text,Converter={StaticResource booleanConverter}}"/>
</StackPanel>
public partial class BindingConverter : Window { public BindingConverter() { InitializeComponent(); } /// <summary> /// 编写boolean类型的自定义转换器 /// </summary> public class BooleanConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { //获取绑定的值 var val = value.ToString()!.ToLower(); switch(val) { case "yes": return true; case "no": return false; } return false; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }
IDataErrorInfo绑定数据校验
<!--引用这个选择器 下面就可以直接使用了--> <Window.Resources> <local:StudentInfo x:Key="StudentValidator"/> <Style TargetType="TextBox"> <Setter Property="Background" Value="White"/> <Setter Property="Foreground" Value="Black"/> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="Background" Value="#ddd"/> <Setter Property="Foreground" Value="Red"/> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}"/> </Trigger> </Style.Triggers> </Style> </Window.Resources> <StackPanel Margin="30"> <!--在里面指定了校验器规则--> <!--另一种引用校验的方法 下面可以注释--> <StackPanel.DataContext> <Binding Source="{StaticResource StudentValidator}"/> </StackPanel.DataContext> <WrapPanel> <TextBlock Text="学生姓名:" Margin="0 0 10 0"/> <!--写法1:一个筛选规则--> <TextBox Name="txtStuName" Text="{Binding StuName,ValidatesOnDataErrors=True}" Width="120"/> </WrapPanel> <WrapPanel Margin="0 10 0 10"> <TextBlock Text="考试分数:" Margin="0 0 10 0"/> <TextBox Name="txtScore" Width="120"> <!--多个筛选规则--> <TextBox.Text> <Binding Path="StuScore" UpdateSourceTrigger="PropertyChanged"> <Binding.ValidationRules> <DataErrorValidationRule/> </Binding.ValidationRules> </Binding> </TextBox.Text> </TextBox> </WrapPanel> </StackPanel>
创建一个StudentInfo类
public class StudentInfo:IDataErrorInfo { public StudentInfo() { StuName = "Tester"; StuScore = 78; } public string this[string columnName] { get { string result = null; switch(columnName) { case "StuName": // 设置学生姓名校验规则 var len = StuName!.Length; if (len <= 4 || len >= 10) result = "姓名长度必须在4~10位字符"; break; case "StuScore": if (StuScore < 0 || StuScore > 150) result = "分数的取值必须是0~150之间的数字"; break; } return result; } } public string? StuName { get; set; } public double StuScore { get; set; } public string Error => throw new NotImplementedException(); }
public partial class DataVaildateDemo : Window
{
public DataVaildateDemo()
{
InitializeComponent();
this.DataContext = new StudentInfo();
}
}
StringFormat数据格式化
类似C#直接写format
绑定数据调试
数据绑定的四种模式介绍
WPF的绑定模式是枚举的 枚举值共有5个
1、OneWay(源变就更新目标属性)
2、TwoWay(源变就更新目标并且目标变得更新源)
3、OneTime(值根据源来设置目标,以后都不会变)
4、OneWayToSource(与OneWay相反)
5、Default(可以单向或双向,是靠被值定的源或目标是否有get或set来指定的)
所以绑定的话是需要选上面5个中的一个模式的,根据你的需求来选择,不选的话就会默认自动选择第5个。
OneTime
<StackPanel>
<TextBox Text="{Binding Name,Mode=OneTime}"/>
<Button Content="修改Name的值" Click="Button_Click"/>
<Button Content="获取Name的值" Click="Button_Click_1"/>
</StackPanel>
public partial class OneTimeBinding : Window { PersonData source = new PersonData(); public OneTimeBinding() { InitializeComponent(); this.DataContext = source; } private void Button_Click(object sender, RoutedEventArgs e) { //修改源数据 source.Name = "Update Name Value"; } private void Button_Click_1(object sender, RoutedEventArgs e) { MessageBox.Show($"Name Value: {source.Name}"); } }
创建了一个PersonData的实体类
public class PersonData : INotifyPropertyChanged { public PersonData() { Name = "Gerry"; } public event PropertyChangedEventHandler? PropertyChanged; private void OnPropertyChanged(string propertyName) { if(PropertyChanged != null) { PropertyChanged(this,new PropertyChangedEventArgs(propertyName)); } } private string? _name; public string? Name { get { return _name; } set { _name = value; OnPropertyChanged(nameof(Name)); } } }
OneWay
直接修改上面的代码,将OneTime修改成OneWay
TwoWay
OneWayToSource
练习:接收TextBox里面的数据
<StackPanel>
<WrapPanel Margin="10">
<TextBlock Text="请输入标题: "/>
<TextBox Name="txtWindowTitle" Width="150"/>
<Button Content="复制到下一行" Name="NextTitle" Click="NextTitle_Click"/>
</WrapPanel>
<WrapPanel Margin="10">
<TextBlock Text="这是复制的这行: "/>
<TextBox Name="copyWindowTitle" Text="{Binding Txt}" Width="150"/>
</WrapPanel>
</StackPanel>
public partial class TestFront : Window { Information information= new Information(); public TestFront() { InitializeComponent(); this.DataContext = information; } private void NextTitle_Click(object sender, RoutedEventArgs e) { information.Txt = txtWindowTitle.Text; } } public class Information : INotifyPropertyChanged { public event PropertyChangedEventHandler? PropertyChanged; public void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } private string? _txt; public string? Txt { get { return _txt; } set { _txt = value; OnPropertyChanged(nameof(Txt)); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。