有很多文章讨论绑定的概念,并讲解如何使用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" />

输出

  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有四种类型,如下所示。

  1. Self
  2. FindAncestor
  3. TemplatedParent
  4. 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的控件的属性。

让我们举个例子来更详细地理解它

步骤

  1. 为按钮创建一个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属性依赖于将应用此模板的控件的属性值。

  1. 添加一个按钮并对其应用模板。
<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

这是相对使用最少的方式。当数据被分析时,这就出现了,我们需要表示值相对于以前数据的变化。

让我们举个例子来更详细地理解它。

步骤

  1. 创建一个类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));
}
}
}
  1. 创建一个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;
}
  1. 在XAML文件中添加ItemsControl。
<ItemsControl ItemsSource="{Binding}"></ItemsControl>
  1. 为其创建ItemsPanel模板,如下。
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
  1. 现在,为了正确地表示数据,创建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的属性。斜杠是一种特殊运算符,用于处理集合中的当前项。

下面给出了三种表达式。

  1. {Binding / }
  2. {Binding Collection / }
  3. {Binding Collection / Property}

3.1 {Binding / }

此表达式用于绑定DataContext中的当前项。

让我们采取一个示例:

在下面给出的示例中,DataContext是字符串类型的国家/地区的集合,并且与Listbox绑定在一起。

步骤

  1. 创建一个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;
}
}
  1. 添加一个XAMl文件,一个ListBox和TextBlock,如下所示。
<DockPanel Name="Collection">
<ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
</ListBox>
<TextBlock DockPanel.Dock="Top" />
</DockPanel>
  1. 创建类Countries的实例并将Countries集合指定为DataContext。
public CurrentItemCollection()
{
InitializeComponent();
Countries countries = new Countries();
this.DataContext = countries.GetCountriesName()
}
  1. 绑定TextBlock的Text属性以将其绑定到集合的当前选定项,如下所示。
<TextBlock DockPanel.Dock="Top" Text="{Binding /}" />

输出

一旦列表项被选中,它将在右侧显示所选国家/地区。

3.2 {Binding Collection /}

此表达式用于绑定DataContext中集合属性的当前项。

例如,

DataContext是Countries类

Collection属性是CounriesList,它与ListBox绑定。

步骤

  1. 使用上面创建的类似的国家类,只是略有不同。创建返回类型为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();
}
  1. 添加RegionInfo类型的CountriesList属性。
private List <RegionInfo> countries = null;
public List <RegionInfo> CountriesList
{
get
{
if (countries == null)
countries = GetCountries();
return countries;
}
}

下面是CountriesList集合中的值的截图。

  1. 将类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>
  1. 要计算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提供的表达式。


时间如流水,只能流去不流回。

【翻译】WPF中的数据绑定表达式的更多相关文章

  1. WPF中的数据绑定(初级)

    关于WPF中的数据绑定,初步探讨 数据绑定属于WPF中比较核心的范畴,以下是对WPF中数据绑定的一个初步探讨.个人感觉还是带有问题性质的叙述比较高效,也比较容易懂 第一,什么是数据绑定? 假定有这么一 ...

  2. WPF入门教程系列十五——WPF中的数据绑定(一)

    使用Windows Presentation Foundation (WPF) 可以很方便的设计出强大的用户界面,同时 WPF提供了数据绑定功能.WPF的数据绑定跟Winform与ASP.NET中的数 ...

  3. WPF中的数据绑定!!!

    引用自:https://msdn.microsoft.com/zh-cn/magazine/cc163299.aspx  数据点: WPF 中的数据绑定 数据点 WPF 中的数据绑定 John Pap ...

  4. WPF中的数据绑定

    WPF中的数据绑定 基础概念 System.Windows.Data.Binding,他会把两个对象(UI对象与UI对象之间,UI对象与.NET数据对象之间)按照指定的方式粘合在一起,并在他们之间建立 ...

  5. Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定)

    原文:Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定) ------------------------------ ...

  6. 【值转换器】 WPF中Image数据绑定Icon对象

    原文:[值转换器] WPF中Image数据绑定Icon对象        这是原来的代码:        <Image Source="{Binding MenuIcon}" ...

  7. WPF入门教程系列十八——WPF中的数据绑定(四)

    六.排序 如果想以特定的方式对数据进行排序,可以绑定到 CollectionViewSource,而不是直接绑定到 ObjectDataProvider.CollectionViewSource 则会 ...

  8. WPF入门教程系列十六——WPF中的数据绑定(二)

    三.绑定模式 通过上一文章中的示例,学习了简单的绑定方式.在这里的示例,要学习一下绑定的模式,和模式的使用效果. 首先,我们来做一个简单示例,这个示例是根据ListBox中的选中项,去改变TextBl ...

  9. WPF入门教程系列十七——WPF中的数据绑定(三)

    四. XML数据绑定 这次我们来学习新的绑定知识,XML数据绑定.XmlDataProvider 用来绑定 XML 数据,该XML数据可以是嵌入.Xmal文件的 XmlDataProvider 标记中 ...

随机推荐

  1. dev winform导出功能

    SaveFileDialog fileDialog = new SaveFileDialog(); fileDialog.Title = "导出Excel"; fileDialog ...

  2. 【原创】如何用Android Studio断点安卓自带Service或Bind类型的Service

    很久以来,我一直想找一种方法来断点调试安卓系统自身的Service,或者bind类型的Service,比如我想看WifiManager里面的getWifiApConfiguration函数是如何实现的 ...

  3. HttpClient示例

    <%@page import="com.sun.xml.ws.client.BindingProviderProperties"%> <%@page conten ...

  4. EF CodeFirst-----简单demo示例

    关于EF CodeFirst的文章院子里有很多的学习资料,但大多数都是一些讲Model通过特性或是Fluent API与数据库之间形成映射的关系,看了相关的文章之后,Model如何映射到数据还是有些迷 ...

  5. Java程序修改文件名

    package script; import java.io.File; import java.io.IOException; public class Realname { public stat ...

  6. &quot;file:///&quot; file 协议

    [问题] 在WLW中拖入本地图片文件,然后调试过程中,选中对应图片,看到获得的对应的html源码中,图片地址是这样的: href="file:///C:/Users/CLi/AppData/ ...

  7. 截获控制台程序关闭事件(SetConsoleCtrlHandler)

    最近控制台程序中需要捕获控制台关闭事件,在用户关闭的时候进行某些操作,找了一大圈发现了一个方法,通过调用WIN32 API SetConsoleCtrlHandler方法来实现,具体代码如下: usi ...

  8. NeoOcean - Unity3D Ocean Waves Simulation

    GMail: bearworks8@gmail.com QQMail:196221347@qq.com QQ Group:391782326 Dropbox Demo:  https://www.dr ...

  9. WSAEventSelect

    WSAEventSelect 是 WinSock 提供的一种异步事件通知I/O模型,与 WSAAsyncSelect模型有些类似.       该模型同样是接收 FD_XXX 之类的网络事件,但是是通 ...

  10. Codeforces Round #452 F. Letters Removing

    Description Petya has a string of length n consisting of small and large English letters and digits. ...