wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName

时间:2022-10-09 22:02:36

先做个声明:这里绑定都在前台实现,至于后台怎么写,那比前台简单多了,但更常用的是xaml中绑定。我们分析下最简单的字符串绑定来弄清楚原理,其他的类推就是。

数据绑定主要是要弄清楚两个东西,一个是源Source,一个是路径Path。

什么能够作为源Source呢:

CLR类型的单个对象

CLR类型的集合对象

DataTable和DataView

XML数据

依赖对象

FrameworkElement的DataContext

控件及ElementName

假如现在有一个最简单的需求:有一个窗口MainWindow,它里面有一个文本框(TextBox),Name为textBox,文本框的内容(Text)要绑定一个字符串。

好了,现在我们要考虑一个上面需求没提到的问题,该字符串是哪的字符串?

1.另外一个类Student(含公开属性Name)的实例化对象对应的Name

在哪实例化这个类Student呢?

  • 在MainWindow.xaml.cs里,对不起,即使实例化了,xaml里无法直接访问cs里的实例化的对象。
  • 在xaml里实例化,有个不错的选择就是通过声明资源(Resource)
 <Grid>
<Grid.Resources>
<local:Student x:Key="stu" StuName="张三"/>
</Grid.Resources>
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding Source={StaticResource stu},Path=StuName}"/>
</Grid>

这种方法测试是可行的。

  • 那如果通过数据上下文DataContext的方式呢,怎么写

DataContext只要存在于要绑定的控件的本身或者其逻辑树父级以上就可以,我们还是定义在Grid上吧

 <Grid Name="grid">
<Grid.DataContext>
<local:Student StuName="李四"/>
</Grid.DataContext>
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding Path=StuName}"/>
</Grid>

这种方法测试也是可行的。

2.如果该字符串存在于当前页面,是当前页面的一个公开属性呢

 public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private string str; public string Str
{
get
{
return str;
} set
{
str = value;
}
}
}
  • 我们先尝试用资源实例化
 <Window.Resources>
<local:MainWindow x:Key="str" Str="王五" />
</Window.Resources>
<Grid Name="grid">
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding Source={StaticResource str}, Path=Str}" />
</Grid>

启动的时候报错了:

wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName

原因是资源不允许嵌套,就是说页面定义的资源不能是本身的实例。

  • 再试试DataContext
 <Grid Name="grid">
<Grid.DataContext>
<local:MainWindow Str="王五" />
</Grid.DataContext>
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding Path=Str}" />
</Grid>

wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName

跟上面报了相同的错,看来数据上下文也不能指定为自己的实例。

  • 那就没招了吗?有的,直接将整个窗口(它也是FrameworkElement)作为Source,通过指定ElementName的方式
 <Window x:Class="Binding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Binding"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="525"
Height="350"
mc:Ignorable="d"
Name="this">
<Grid Name="grid">
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding ElementName=this, Path=Str}" />
</Grid>
</Window>

我们需要在cs里对Str赋值,否则绑定的是Str的默认值,这块我们这样理解,ElementName指定自己,那么就是实例化了一个MainWindow,它里面的属性都是取的默认值。

我们在构造里写 Str=“ZHAOLIU”,发现运行的文本框仍然为空,这是因为我们赋值是在界面初始化语句InitializeComponent();之后,

我们的属性又不具备更改通知功能,所以改变了值也不会起作用。下面我们就改造为可更改通知的。只需要继承接口INotifyPropertyChanged并实现他的约束就可以了。

 using System;
using System.Collections.Generic;
using System.ComponentModel;
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.Navigation;
using System.Windows.Shapes; namespace Binding
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
Str = "ZHAOLIU";
}
private string str; public event PropertyChangedEventHandler PropertyChanged; public string Str
{
get
{
return str;
} set
{
str = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Str"));
}
}
}
}
}

wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName

经过测试是可以的。

3.如果字符串存在于另一个窗口,是其一个公开属性呢

我们再新建个窗口Window1

 public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private string str; public string Str
{
get
{
return str;
} set
{
str = value;
}
}
}

然后我们在MainWindow里实例化Window1试试

 <Window.Resources>
<local:Window1 x:Key="str" Str="王五" />
</Window.Resources>
<Grid Name="grid">
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding Source={StaticResource str}, Path=Str}" />
</Grid>

wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName

这是可以的。至此我们知道,资源中实例化一个对象,控件去绑定该对象的公开属性,只要一条,该对象不能是自己本身就ok。

使用DataContext也是可以的

 <Window.DataContext>
<local:Window1 Str="麻子"/>
</Window.DataContext>
<Grid Name="grid">
<TextBox Name="textBox"
Width="150"
Height="23"
BorderBrush="Black"
Text="{Binding Path=Str}" />
</Grid>

wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName

ElementName呢,MainWindow拿不到Window1里的控件,就算你给Window1给了个名字,在MainWindow也不能以字符串直接拿到,不知道你们有没有见过将控件的值绑定到另一个页面的一个控件上的。

总结下:

wpf XAML xaml 进行 数据绑定,Resource DataContext ElementName