有很多文章討論綁定的概念,並講解如何使用 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.使用表達式
用於直接綁定 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" />
輸出

- 使用表達式
綁定 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;
現在,讓我們看看輸出。

由於綁定表達式用於綁定 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" />
綁定表達式用於綁定 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/
- 編輯:沙漠之盡頭的狼