如何將RelativeSource
與WPF綁定一塊兒使用以及不一樣的用例有哪些? html
我建立了一個庫來簡化WPF的綁定語法,包括更容易使用RelativeSource。 這裏有些例子。 以前: canvas
{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}} {Binding Path=PathToProperty, RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}} {Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}} {Binding Path=Text, ElementName=MyTextBox}
後: windows
{BindTo PathToProperty} {BindTo Ancestor.typeOfAncestor.PathToProperty} {BindTo Template.PathToProperty} {BindTo #MyTextBox.Text}
如下是如何簡化方法綁定的示例。 以前: ide
// C# code private ICommand _saveCommand; public ICommand SaveCommand { get { if (_saveCommand == null) { _saveCommand = new RelayCommand(x => this.SaveObject()); } return _saveCommand; } } private void SaveObject() { // do something } // XAML {Binding Path=SaveCommand}
後: 優化
// C# code private void SaveObject() { // do something } // XAML {BindTo SaveObject()}
你能夠在這裏找到這個圖書館: http : //www.simplygoodcode.com/2012/08/simpler-wpf-binding.html ui
請注意我在「BEFORE」示例中使用的方法綁定已經使用RelayCommand
優化了代碼,最後我檢查的不是WPF的本機部分。 沒有它,'BEFORE'的例子會更長。 this
一些有用的零碎: spa
如下是如何在代碼中執行此操做: code
Binding b = new Binding(); b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1); b.Path = new PropertyPath("MyElementThatNeedsBinding"); MyLabel.SetBinding(ContentProperty, b);
我很大程度上是在代碼Behind中從Binding Relative Source複製了它。 orm
此外,就例子而言,MSDN頁面很是好: RelativeSource Class
想象一下這個案例,咱們想要一個矩形,它的高度老是等於它的寬度,一個正方形讓咱們說。 咱們可使用元素名稱來完成此操做
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>
但在上面這種狀況下,咱們有義務指出綁定對象的名稱,即矩形。 咱們可使用RelativeSource以不一樣的方式達到相同的目的
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>
對於這種狀況,咱們沒有義務說起綁定對象的名稱,而且每當高度改變時,寬度將始終等於高度。
若是要將寬度參數設置爲高度的一半,則能夠經過向Binding標記擴展添加轉換器來完成此操做。 咱們如今想象另外一個案例:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>
上面的狀況用於將給定元素的給定屬性綁定到其直接父元素之一,由於此元素包含一個名爲Parent的屬性。 這致使咱們進入另外一個相對源模式,即FindAncestor模式。
Bechir Bejaoui在他的文章中公開了WPF中RelativeSources的用例:
RelativeSource是一個標記擴展,當咱們嘗試將對象的屬性綁定到對象自己的另外一個屬性時,在咱們嘗試將對象的屬性綁定到其相對父項的另外一個屬性時,在特定綁定狀況下使用在自定義控件開發的狀況下將依賴項屬性值綁定到一塊XAML時,最後在使用一系列綁定數據的差別的狀況下。 全部這些狀況都表示爲相對源模式。 我將逐一揭露全部這些案件。
- 模式自我:
想象一下這個案例,咱們想要一個矩形,它的高度老是等於它的寬度,一個正方形讓咱們說。 咱們可使用元素名稱來完成此操做
<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>但在上面這種狀況下,咱們有義務指出綁定對象的名稱,即矩形。 咱們可使用RelativeSource以不一樣的方式達到相同的目的
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>對於這種狀況,咱們沒有義務說起綁定對象的名稱,而且每當高度改變時,寬度將始終等於高度。
若是要將寬度參數設置爲高度的一半,則能夠經過向Binding標記擴展添加轉換器來完成此操做。 咱們如今想象另外一個案例:
<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>上面的狀況用於將給定元素的給定屬性綁定到其直接父元素之一,由於此元素包含一個名爲Parent的屬性。 這致使咱們進入另外一個相對源模式,即FindAncestor模式。
- 模式FindAncestor
在這種狀況下,給定元素的屬性將與其父元素之一Corse綁定。 與上述狀況的主要區別在於,由您決定層次結構中的祖先類型和祖先等級來綁定屬性。 順便說一下,嘗試使用這塊XAML
<Canvas Name="Parent0"> <Border Name="Parent1" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent2"> <Border Name="Parent3" Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}" Height="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualHeight}"> <Canvas Name="Parent4"> <TextBlock FontSize="16" Margin="5" Text="Display the name of the ancestor"/> <TextBlock FontSize="16" Margin="50" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Border}, AncestorLevel=2},Path=Name}" Width="200"/> </Canvas> </Border> </Canvas> </Border> </Canvas>上面的狀況是兩個TextBlock元素,它們嵌入在一系列邊框中,而canvas元素表明它們的分層父元素。 第二個TextBlock將在相對源級別顯示給定父級的名稱。
所以,嘗試將AncestorLevel = 2更改成AncestorLevel = 1並查看會發生什麼。 而後嘗試將祖先的類型從AncestorType = Border更改成AncestorType = Canvas,看看發生了什麼。
顯示的文本將根據Ancestor類型和級別更改。 那麼若是祖先級別不適合祖先類型會發生什麼? 這是一個很好的問題,我知道你將要問它。 響應是沒有異常將被拋出,而且nothings將在TextBlock級別顯示。
- TemplatedParent
此模式容許將給定的ControlTemplate屬性綁定到應用ControlTemplate的控件的屬性。 爲了更好地理解這個問題,下面是一個例子
<Window.Resources> <ControlTemplate x:Key="template"> <Canvas> <Canvas.RenderTransform> <RotateTransform Angle="20"/> </Canvas.RenderTransform> <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> <Canvas Name="Parent0"> <Button Margin="50" Template="{StaticResource template}" Height="0" Canvas.Left="0" Canvas.Top="0" Width="0"> <TextBlock FontSize="22">Click me</TextBlock> </Button> </Canvas>若是我想將給定控件的屬性應用於其控件模板,那麼我可使用TemplatedParent模式。 這個標記擴展也有相似的一個,它是TemplateBinding,它是第一個的簡寫,但TemplateBinding在編譯時以TemplatedParent的對比度進行評估,TemplatedParent在第一個運行時以後進行評估。 正如您在下圖中所述,背景和內容從按鈕內部應用到控件模板。
值得注意的是,對於那些對Silverlight這個想法感到磕磕絆絆的人:
Silverlight僅提供這些命令的簡化子集