【翻译】WPF中的数据绑定表达式
有很多文章讨论绑定的概念,并讲解如何使用StaticResources和DynamicResources绑定属性。这些概念使用WPF提供的数据绑定表达式。在本文中,让我们研究WPF提供的不同类型的数据绑定表达式。
介绍
数据绑定是一种强大的技术,它允许数据在UI元素和业务模型之间流动。当业务模型中的数据发生变化时,它会自动将更改反映到UI元素上。
Models | Description |
---|---|
OneWay | Source → Destination |
TwoWay | Source ←→ Destination |
OneWayToSource | Source ← Destination |
OneTime | Source → Destination (only once) |
这可以通过WPF提供的不同类型的数据绑定表达式来实现。
数据绑定表达式的类型如下所示。
- DataContext绑定
- RelativeSource绑定
- ItemSource绑定
1、DataContext绑定
DataContext是一个依赖属性,它是绑定的默认源。Datacontext沿着逻辑树继承。因此,如果您设置一个DataContext来控制逻辑树中的所有子元素,它也将引用同一个DataContext,除非并且直到显式指定了另一个源。
让我们举个例子来更详细地理解它。
1.1 创建一个类Book,如下所示。
public class Book
{
public string Name
{
get;
set;
}
public string Author
{
get;
set;
}
}
1.2 添加一个XAML文件DataContextBinding.XAML
并放置四个TextBlock,如下所示。
<Grid VerticalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="40" />
<RowDefinition Height="40" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock Text="Book Name:" FontWeight="Bold" />
<TextBlock Grid.Column="1" />
<TextBlock Text="Author:" FontWeight="Bold" Grid.Row="1" />
<TextBlock Grid.Row="1" Grid.Column="1" />
</Grid>
现在,让我们看看如何使用这个DataContext属性来显示数据。
它有两种用法,如下所示。
- 1.使用{Binding}表达式
用于直接绑定DataContext。
创建类Book的实例,初始化其属性,并将类的Name属性分配给Window的DataContext属性。
public partial class DataContextBinding: Window
{
public DataContextBinding()
{
InitializeComponent();
//Create the instance
Book book = new Book();
//initialize the properties
book.Name = "Computer Networking";
//Assign the Property as DataContext
this.DataContext = book.Name;
}
}
由于DataContext是沿着逻辑树和数据book继承的,因此Name被绑定到Control Window。Window的所有子元素也将引用同一个对象(book.Name)。
要显示数据,请将DataContext与Textblock绑定,如下所示。
<TextBlock Text="Book Name:" FontWeight="Bold"/>
<TextBlock Text="{Binding}" Grid.Column="1" />
输出
- 使用{Binding Property}表达式
绑定Datacontext的属性。
创建类Book的实例,初始化其属性并将类的实例(Book)分配给Window的DataContext属性。
Book book = new Book();
//initialize the properties
book.Name = "Computer Networking";
book.Author = "James F. Kurose";
//Assign the instance as DataContext
this.DataContext = book;
现在,让我们看看输出。
由于绑定表达式{Binding}用于绑定Book类型的DataContext对象,因此调用ToString()方法,并将数据显示为字符串。为了以正确的格式显示数据,我们必须将数据对象的属性与TextBlock绑定,如下所示:
<TextBlock Text="Book Name:" FontWeight="Bold"/>
<TextBlock Text="{Binding Name}" Grid.Column="1" />
<TextBlock Text="Author:" FontWeight="Bold" Grid.Row="1" />
<TextBlock Text="{Binding Author}" Grid.Row="1" Grid.Column="1"/>
绑定表达式{Binding Name}用于绑定DataContext绑定的Name属性。
输出
2、RelativeSource 绑定
RelativeSource是一个属性,它用相对关系设置绑定源以绑定目标。此扩展主要用于必须将元素的一个属性绑定到同一元素的另一个属性时。
RelativeSource有四种类型,如下所示。
- Self
- FindAncestor
- TemplatedParent
- PreviousData
让我们一个一个详细地探讨一下。
2.1 Self
Self用于绑定源和绑定目标相同的场景中。对象的一个属性与同一对象的另一个属性绑定。
例如,让我们取一个高度和宽度相同的椭圆。
在XAML文件中添加下面给出的代码。宽度属性与高度属性相对绑定。
<Grid>
<Ellipse Fill="Black" Height="100" Width="{Binding RelativeSource={RelativeSource Self},Path=Height}">
</Ellipse>
</Grid>
输出
如果改变椭圆的高度,宽度也会相对变化。
2.2 FindAncestor
顾名思义,当绑定源是绑定目标的祖先(父级)之一时使用此选项。使用FindAncestor扩展,可以找到任何级别的祖先。
让我们举个例子来更清楚地理解它。
步骤
创建XAML,它表示下面给出的元素的逻辑树。
<Grid Name="Parent_3">
<StackPanel Name="Parent_2">
<Border Name="Parent_1">
<StackPanel x:Name="Parent_0" Orientation="Vertical">
<Button></Button>
</StackPanel>
</Border>
</StackPanel>
</Grid>
现在,让我们使用FindAncestor扩展将祖先的Name属性绑定到子元素button的Content属性。
<Grid Name="Parent_3">
<StackPanel Name="Parent_2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="100">
<Border Name="Parent_1">
<StackPanel x:Name="Parent_0" Orientation="Vertical">
<Button Height="50" Content="{Binding RelativeSource={RelativeSource FindAncestor,
AncestorType={x:Type StackPanel},
AncestorLevel=2},Path=Name}"></Button>
</StackPanel>
</Border>
</StackPanel>
</Grid>
输出
AncestorType为“StackPanel”与AcestorLevel为“2”组合,将button的content属性与StackPanel的Name属性(Parent_2)绑定在一起。
2.3 TemplatedParent
TemplatedParent是一个属性,它使您能够创建一个包含少量未知值的控件模板。这些值取决于应用ControlTemplate的控件的属性。
让我们举个例子来更详细地理解它
步骤
- 为按钮创建一个ControlTemplate,如下所示。
<Window.Resources>
<ControlTemplate x:Key="template">
<Canvas>
<Ellipse Height="110" Width="155"
Fill="Black"/>
<Ellipse Height="100" Width="150"
Fill="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Background}">
</Ellipse>
<ContentPresenter Margin="35"
Content="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Content}"/>
</Canvas>
</ControlTemplate>
</Window.Resources>
在上面给出的代码中,椭圆的Fill属性和ContentPresenter的Content属性依赖于将应用此模板的控件的属性值。
- 添加一个按钮并对其应用模板。
<Button Margin="50" Background="Beige" Template="{StaticResource template}" Height="0" Content="Click me" FontSize="22">
</Button>
在应用模板时,按钮的Background(Beige)与椭圆的Fill属性相对绑定,Content(Click me)与ContentPresenter的Content属性相对绑定。依赖值生效并给出以下输出。
输出
2.4 PreviousData
这是相对使用最少的方式。当数据被分析时,这就出现了,我们需要表示值相对于以前数据的变化。
让我们举个例子来更详细地理解它。
步骤
- 创建一个类Data并实现INotifyPropertyChanged接口,如下所示
public class Data: INotifyPropertyChanged
{
public int DataValue
{
get;
set;
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string PropertyName)
{
if (null != PropertyChanged)
{
PropertyChanged(this,
new PropertyChangedEventArgs(PropertyName));
}
}
}
- 创建一个Data类型的列表并将其指定为DataContext。
public RelativeSourcePreviousData()
{
InitializeComponent();
List < Data > data = new List < Data > ();
data.Add(new Data()
{
DataValue = 60
});
data.Add(new Data()
{
DataValue = 100
});
data.Add(new Data()
{
DataValue = 120
});
this.DataContext = data;
}
- 在XAML文件中添加ItemsControl。
<ItemsControl ItemsSource="{Binding}"></ItemsControl>
- 为其创建ItemsPanel模板,如下。
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
- 现在,为了正确地表示数据,创建DataTemplate,如下所示。
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Grid Margin="30,20,0,0">
<Rectangle Width="80" Height="{Binding DataValue}" Fill="Blue" />
<TextBlock Foreground="White" Margin="35,0,0,0" Text="{Binding DataValue}"></TextBlock>
</Grid>
<TextBlock Margin="30,20,0,0" Text="Previous Data:"></TextBlock>
<TextBlock VerticalAlignment="Center" Margin="5,20,0,0" Text="{Binding
RelativeSource={RelativeSource PreviousData}, Path=DataValue}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
输出
蓝色框的高度是列表中项目的值,旧数据显示在右侧。该项的第一个值为“60”。因此,第一项没有旧值。
3、ItemSource绑定
在处理集合时使用。使用这个绑定表达式,您可以非常容易地读取SelectedItem的属性。斜杠是一种特殊运算符,用于处理集合中的当前项。
下面给出了三种表达式。
- {Binding / }
- {Binding Collection / }
- {Binding Collection / Property}
3.1 {Binding / }
此表达式用于绑定DataContext中的当前项。
让我们采取一个示例:
在下面给出的示例中,DataContext是字符串类型的国家/地区的集合,并且与Listbox绑定在一起。
步骤
- 创建一个Countries类并添加一个GetCountriesName()方法,该方法返回string数据类型的国家的集合,如下所示。
public class Countries
{
public static List <string> GetCountriesName()
{
List <string> countries = new List <string> ();
foreach(CultureInfo culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
RegionInfo country = new RegionInfo(culture.LCID);
if (!countries.Contains(country.EnglishName))
countries.Add(country.EnglishName);
}
countries.Sort();
return countries;
}
}
- 添加一个XAMl文件,一个ListBox和TextBlock,如下所示。
<DockPanel Name="Collection">
<ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
</ListBox>
<TextBlock DockPanel.Dock="Top" />
</DockPanel>
- 创建类Countries的实例并将Countries集合指定为DataContext。
public CurrentItemCollection()
{
InitializeComponent();
Countries countries = new Countries();
this.DataContext = countries.GetCountriesName()
}
- 绑定TextBlock的Text属性以将其绑定到集合的当前选定项,如下所示。
<TextBlock DockPanel.Dock="Top" Text="{Binding /}" />
输出
一旦列表项被选中,它将在右侧显示所选国家/地区。
3.2 {Binding Collection /}
此表达式用于绑定DataContext中集合属性的当前项。
例如,
DataContext是Countries类
Collection属性是CounriesList,它与ListBox绑定。
步骤
- 使用上面创建的类似的国家类,只是略有不同。创建返回类型为RegionInfo的方法。
public static List <RegionInfo> GetCountries()
{
List <RegionInfo> countries = new List <RegionInfo> ();
foreach(CultureInfo culture in CultureInfo.GetCultures(CultureTypes.SpecificCultures))
{
RegionInfo country = new RegionInfo(culture.LCID);
if (countries.Where(p => p.Name == country.Name).Count() == 0)
countries.Add(country);
}
return countries.OrderBy(p => p.EnglishName).ToList();
}
- 添加RegionInfo类型的CountriesList属性。
private List <RegionInfo> countries = null;
public List <RegionInfo> CountriesList
{
get
{
if (countries == null)
countries = GetCountries();
return countries;
}
}
下面是CountriesList集合中的值的截图。
- 将类Countries指定为DataContext,并将Listbox与DataContext的CountriesList属性绑定。
<Window.Resources>
<vm:Countries x:Key="Countries"></vm:Countries>
</Window.Resources>
<Grid>
<DockPanel Name="Collection" DataContext="{StaticResource Countries}">
<ListBox ItemsSource="{Binding CountriesList}" IsSynchronizedWithCurrentItem="True">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding EnglishName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
</Grid>
- 要计算CountriesList属性的当前项,请绑定TextBlock的Text属性,如下所示。
<TextBlock DockPanel.Dock="Top" Text="{Binding CountriesList/}" HorizontalAlignment="Center" FontSize="16" VerticalAlignment="Center" />
输出
右侧显示DataContext(CountriesList)中集合的当前项(CountriesList)。
3.3 {Binding Collection / Property}
此表达式用于绑定DataContext中集合的当前项的属性。
例如,如果必须计算CountriesList集合的当前项的特定属性。
在这个例子中,我想显示属性“EnglishName”的值。
为此,绑定TextBlock的Text属性,如下所示。
<TextBlock DockPanel.Dock="Top" Text="{Binding CountriesList/EnglishName}" />
输出
现在,当列表中的项被选中时,它显示属性“EnglishName”的值。
结论
我已经详细介绍了所有的数据绑定表达式。我希望这有助于您理解绑定的概念和WPF提供的表达式。
时间如流水,只能流去不流回。
- 作者:Swati Gupta
- 原文标题:DataBinding Expressions In WPF
- 原文链接:https://www.c-sharpcorner.com/article/data-binding-expression-in-wpf/
- 翻译、编辑:沙漠之尽头的狼
- 公众号:Dotnet9
- 日期:2021-05-04
【翻译】WPF中的数据绑定表达式的更多相关文章
- WPF中的数据绑定(初级)
关于WPF中的数据绑定,初步探讨 数据绑定属于WPF中比较核心的范畴,以下是对WPF中数据绑定的一个初步探讨.个人感觉还是带有问题性质的叙述比较高效,也比较容易懂 第一,什么是数据绑定? 假定有这么一 ...
- WPF入门教程系列十五——WPF中的数据绑定(一)
使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数 ...
- WPF中的数据绑定!!!
引用自:https://msdn.microsoft.com/zh-cn/magazine/cc163299.aspx 数据点: WPF 中的数据绑定 数据点 WPF 中的数据绑定 John Pap ...
- WPF中的数据绑定
WPF中的数据绑定 基础概念 System.Windows.Data.Binding,他会把两个对象(UI对象与UI对象之间,UI对象与.NET数据对象之间)按照指定的方式粘合在一起,并在他们之间建立 ...
- Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定)
原文:Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定) ------------------------------ ...
- 【值转换器】 WPF中Image数据绑定Icon对象
原文:[值转换器] WPF中Image数据绑定Icon对象 这是原来的代码: <Image Source="{Binding MenuIcon}" ...
- WPF入门教程系列十八——WPF中的数据绑定(四)
六.排序 如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider.CollectionViewSource 则会 ...
- WPF入门教程系列十六——WPF中的数据绑定(二)
三.绑定模式 通过上一文章中的示例,学习了简单的绑定方式.在这里的示例,要学习一下绑定的模式,和模式的使用效果. 首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项,去改变TextBl ...
- WPF入门教程系列十七——WPF中的数据绑定(三)
四. XML数据绑定 这次我们来学习新的绑定知识,XML数据绑定.XmlDataProvider 用来绑定 XML 数据,该XML数据可以是嵌入.Xmal文件的 XmlDataProvider 标记中 ...
随机推荐
- Python爬虫学习三------requests+BeautifulSoup爬取简单网页
第一次第一次用MarkDown来写博客,先试试效果吧! 昨天2018俄罗斯世界杯拉开了大幕,作为一个伪球迷,当然也得为世界杯做出一点贡献啦. 于是今天就编写了一个爬虫程序将腾讯新闻下世界杯专题的相关新 ...
- TiDB在更新版本的时候初始化Prometheus的配置文件失败
一.背景是更换版本了之后,按照正常扩容节点也会报错. 我们安装的TiDB版本是v4.0.0,因为环境还在试用阶段,所以会经常增删节点.原因是我们违背官方说明,强行用机械盘上了,跑不过单机的mysql, ...
- Java 运行时数据区和内存模型
运行时数据区是指对 JVM 运行过程中涉及到的内存根据功能.目的进行的划分,而内存模型可以理解为对内存进行存取操作的过程定义.总是有人望文生义的将前者描述为 "Java 内存模型" ...
- C#异步编程由浅入深(二)Async/Await的作用.
考虑到直接讲实现一个类Task库思维有点跳跃,所以本节主要讲解Async/Await的本质作用(解决了什么问题),以及Async/Await的工作原理.实现一个类Task的库则放在后面讲.首先回顾 ...
- Img2Latex 临时方法
Img2Latex 临时方法 博客园Markdown编辑器中公式需采用Latex编写,然鹅现在并不想学习Latex 毕竟工科生,写论文也免不了的各种公式 (终极解决方案当然是学会Latex) 1.工具 ...
- java面试-死锁产生、定位分析和修复
死锁发生:两个或多个线程之间,互相持有对方需要的锁,而永久处于阻塞状态 一.手写死锁代码: public class DeadLockSample extends Thread { private S ...
- [C++]一篇文章搞懂C++中五花八门的各种初始化
总结 初始化的概念:创建变量时赋予它一个值(不同于赋值的概念) 类的构造函数控制其对象的初始化过程,无论何时只要类的对象被创建就会执行构造函数 如果对象未被用户指定初始值,那么这些变量会被执行默认初始 ...
- [Python]import使用的疑难杂症与包管理
概念:模块与包 模块module:一般是以.py为后缀的文件,也包括.pyo..pyc..pyd..so和.dll后缀的文件,模块内定义了函数.类以及变量 包package:包是含有若干个模块的文件夹 ...
- 一般实现分布式锁都有哪些方式?使用redis如何设计分布式锁?使用zk来设计分布式锁可以吗?这两种分布式锁的实现方式哪种效率比较高?
#(1)redis分布式锁 官方叫做RedLock算法,是redis官方支持的分布式锁算法. 这个分布式锁有3个重要的考量点,互斥(只能有一个客户端获取锁),不能死锁,容错(大部分redis节点创建了 ...
- java面试系列<4>——IO
面试系列--javaIO 一.概述 java的IO主要分为以下几类: 磁盘操作:File 字节操作:InputStream 和 OutputStream 字符操作:Reader 和 Writer 对象 ...