当前位置:  开发笔记 > 编程语言 > 正文

如何将WPF绑定与RelativeSource一起使用?

如何解决《如何将WPF绑定与RelativeSource一起使用?》经验,为你挑选了14个好方法。

如何使用RelativeSourceWPF绑定以及不同的用例?



1> Abe Heidebre..:

如果要绑定到对象上的另一个属性:

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}

如果您想获得祖先的财产:

{Binding Path=PathToProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}

如果要在模板化父级上获取属性(因此可以在ControlTemplate中执行双向绑定)

{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}

或者,更短(这仅适用于OneWay绑定):

{TemplateBinding Path=PathToProperty}


对于这个"{Binding Path = PathToProperty,RelativeSource = {RelativeSource AncestorType = {x:Type typeOfAncestor}}}",看起来它需要在"AncestorType"之前有"Mode = FindAncestor"
只是想在此注意,如果要绑定到RelativeSource的DataContext中的属性,则必须明确指定它:`{Binding Path = DataContext.SomeProperty,RelativeSource = ...`.当我尝试绑定到DataTemplate中的父级DataContext时,这对我来说有些出乎意料.
我同意@EdwardM。当我在`AncestorType`之前省略`FindAncestor`时,出现以下错误:“ RelativeSource不在FindAncestor模式下”。(在VS2013中,社区版)

2> Drew Noakes..:
Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...

默认属性RelativeSourceMode属性.这里给出了一整套有效值(来自MSDN):

PreviousData允许您在显示的数据项列表中绑定以前的数据项(而不是包含数据项的控件).

TemplatedParent指应用模板(其中存在数据绑定元素)的元素.这与设置TemplateBindingExtension类似,仅在Binding位于模板中时才适用.

Self指向要设置绑定的元素,并允许您将该元素的一个属性绑定到同一元素上的另一个属性.

FindAncestor指数据绑定元素的父链中的祖先.您可以使用它来绑定到特定类型或其子类的祖先.如果要指定AncestorType和/或AncestorLevel,则使用此模式.



3> Jeffrey Knig..:

这是MVVM架构上下文中更直观的解释:

在此输入图像描述


我错过了什么?你怎么能考虑一个简单明了的图形?1:左边的框与右边的框没有关系(为什么ViewModel里面有.cs文件?)2:这些DataContext箭头指向什么?3:为什么Message属性不在ViewModel1中?最重要的是5:如果TextBlock已经拥有相同的DataContext,为什么需要一个RelativeSource Binding来获取Window的DataContext?我显然在这里遗漏了一些东西,所以要么我很笨,要么这个图形并不像大家想的那么简单明了!请赐教
@MatthewCargille我非常清楚这是什么意思,这不是我的观点.但是让自己处于不熟悉XAML和MVVM的人的位置,你会发现这不是_simple和clear_.
@MarkusHütter该图显示了一个嵌套视图和相应的ViewModel组.View1的DataContext是ViewModel1,但它想绑定到BaseViewModel的属性.因为BaseViewModel是BaseView的DataContext(它是一个Window),所以它可以通过查找第一个父容器(即Window)并获取其DataContext来实现.

4> lasitha edir..:

想象一下这个案例,我们想要一个矩形,它的高度总是等于它的宽度,一个正方形让我们说.我们可以使用元素名称来完成此操作


但在上面这种情况下,我们有义务指出绑定对象的名称,即矩形.我们可以使用RelativeSource以不同的方式达到相同的目的


对于这种情况,我们没有义务提及绑定对象的名称,并且每当高度改变时,宽度将始终等于高度.

如果要将宽度参数设置为高度的一半,则可以通过向Binding标记扩展添加转换器来完成此操作.我们现在想象另一个案例:

 

上面的情况用于将给定元素的给定属性绑定到其直接父元素之一,因为此元素包含一个名为Parent的属性.这导致我们进入另一个相对源模式,即FindAncestor模式.


复制和粘贴时最好引用您的来源.
@Jeremy指的是Bechir Bejaoui从2010年5月11日开始的[本教程](http://www.c-sharpcorner.com/UploadFile/yougerthen/relativesources-in-wpf/)。

5> Cornel Maria..:

Bechir Bejaoui在他的文章中公开了WPF中RelativeSources的用例:

RelativeSource是一个标记扩展,当我们尝试将对象的属性绑定到对象本身的另一个属性时,在我们尝试将对象的属性绑定到其相对父项的另一个属性时,在特定的绑定情况下使用在自定义控件开发的情况下将依赖项属性值绑定到一块XAML时,最后在使用一系列绑定数据的差异的情况下.所有这些情况都表示为相对源模式.我将逐一揭露所有这些案件.

    模式自我:

想象一下这个案例,我们想要一个矩形,它的高度总是等于它的宽度,一个正方形让我们说.我们可以使用元素名称来完成此操作


但在上面这种情况下,我们有义务指出绑定对象的名称,即矩形.我们可以使用RelativeSource以不同的方式达到相同的目的


对于这种情况,我们没有义务提及绑定对象的名称,并且每当高度改变时,宽度将始终等于高度.

如果要将宽度参数设置为高度的一半,则可以通过向Binding标记扩展添加转换器来完成此操作.我们现在想象另一个案例:

 

上面的情况用于将给定元素的给定属性绑定到其直接父元素之一,因为此元素包含一个名为Parent的属性.这导致我们进入另一个相对源模式,即FindAncestor模式.

    模式FindAncestor

在这种情况下,给定元素的属性将与其父元素之一Corse绑定.与上述情况的主要区别在于,由您决定层次结构中的祖先类型和祖先等级来绑定属性.顺便说一下,尝试使用这块XAML


    
        
            
               
               
               
                
            
        
     
   

上面的情况是两个TextBlock元素,它们嵌入在一系列边框中,而canvas元素代表它们的分层父元素.第二个TextBlock将在相对源级别显示给定父级的名称.

因此,尝试将AncestorLevel = 2更改为AncestorLevel = 1并查看会发生什么.然后尝试将祖先的类型从AncestorType = Border更改为AncestorType = Canvas,看看发生了什么.

显示的文本将根据Ancestor类型和级别更改.那么如果祖先级别不适合祖先类型会发生什么?这是一个很好的问题,我知道你将要问它.响应是没有异常将被抛出,并且nothings将在TextBlock级别显示.

    TemplatedParent

此模式允许将给定的ControlTemplate属性绑定到应用ControlTemplate的控件的属性.为了更好地理解这个问题,下面是一个例子



        
            
                
                
            

              
            
        
    

    
    
 

如果我想将给定控件的属性应用于其控件模板,那么我可以使用TemplatedParent模式.这个标记扩展也有类似的一个,它是TemplateBinding,它是第一个的简写,但TemplateBinding在编译时以TemplatedParent的对比度进行评估,TemplatedParent在第一个运行时之后进行评估.正如您在下图中所述,背景和内容从按钮内部应用到控件模板.



6> Kylo Ren..:

在WPF RelativeSource绑定中公开三个properties设置:

1.模式:enum可能有四个值:

一个.PreviousData(value=0):它将前一个值赋给property绑定的值

湾 TemplatedParent(value=1): 这在定义templates任何控件时使用,并且想要绑定到的值/ Propertycontrol.

例如,定义ControlTemplate:

  
        
 

C.Self(value=2):当我们想要从一个self或一个property自我绑定.

例如:设置打开时发送检查状态为checkboxasCommandParameterCommandCheckBox


d.FindAncestor(value=3):当想要从父进程绑定controlVisual Tree.

例如:绑定checkboxrecords,如果grid,如果header checkbox被选中


2.AncestorType: 当模式FindAncestor然后定义什么类型的祖先

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}

3.AncestorLevel: 当模式是FindAncestor什么级别的祖先(如果有两个相同类型的父级visual tree)

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}

以上是所有用例RelativeSource binding.

这是一个参考链接.



7> Bob King..:

不要忘记TemplatedParent:


要么

{Binding RelativeSource={RelativeSource TemplatedParent}}



8> 小智..:

值得注意的是,对于那些对Silverlight这个想法感到磕磕绊绊的人:

Silverlight仅提供这些命令的简化子集



9> Luis Perez..:

我创建了一个库来简化WPF的绑定语法,包括更容易使用RelativeSource.这里有些例子.之前:

{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}

后:

{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}

以下是如何简化方法绑定的示例.之前:

// 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

请注意我用于方法绑定的'BEFORE'示例中的代码已经通过使用RelayCommand哪个代码进行了优化,我检查的最后一个代码不是WPF的本机部分.没有它,'BEFORE'的例子会更长.


这种手持练习表明了XAML的弱点;*方式*太复杂了.

10> Nathan Coope..:

一些有用的零碎:

以下是如何在代码中执行此操作:

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复制了它.

此外,就例子而言,MSDN页面非常好:RelativeSource Class


我对WPF的模糊记忆是,在代码中进行绑定可能通常不是最好的事情.

11> Juve..:

我刚刚发布了另一个解决方案,用于访问Silverlight中适用于我的父元素的DataContext.它使用Binding ElementName.



12> 小智..:

我没有阅读每个答案,但我只想在按钮的相对源命令绑定的情况下添加此信息.

当您使用相对源时Mode=FindAncestor,绑定必须类似于:

Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"

如果未在路径中添加DataContext,则在执行时无法检索该属性.



13> 小智..:

这是在空数据网格上使用这种模式的一个例子.


    
        
            
                
                    
                        
                    
                
            
        
    



14> Contango..:

如果元素不属于视觉树,则RelativeSource将永远无法工作。

在这种情况下,您需要尝试由Thomas Levesque开创的另一种技术。

他在[WPF]下的博客中提供了解决方案,该方法在不继承DataContext时如何绑定数据。而且它绝对出色!

万一他的博客被关闭,这种情况极少发生,附录A包含了他的文章的镜像副本。

请不要在此处发表评论,请直接在他的博客文章中发表评论。

附录A:博客文章的镜像

WPF中的DataContext属性非常方便,因为它由您为其分配元素的所有子元素自动继承。因此,您无需在要绑定的每个元素上再次设置它。但是,在某些情况下,DataContext是不可访问的:它发生在不属于可视或逻辑树的元素中。然后在这些元素上绑定属性可能非常困难……

让我们用一个简单的示例进行说明:我们想在DataGrid中显示产品列表。在网格中,我们希望能够基于ViewModel公开的ShowPrice属性的值来显示或隐藏Price列。一种明显的方法是将列的可见性绑定到ShowPrice属性:


不幸的是,更改ShowPrice的值无效,并且该列始终可见...为什么?如果我们在Visual Studio中查看“输出”窗口,则会注意到以下行:

System.Windows.Data错误:2:找不到目标元素的管理FrameworkElement或FrameworkContentElement。BindingExpression:Path = ShowPrice; DataItem = null; 目标元素是“ DataGridTextColumn”(HashCode = 32685253);目标属性为“可见性”(类型为“可见性”)

该消息相当神秘,但是含义实际上非常简单:WPF不知道使用哪个FrameworkElement来获取DataContext,因为该列不属于DataGrid的可视树或逻辑树。

我们可以尝试调整绑定以获得所需的结果,例如,通过将RelativeSource设置为DataGrid本身:


或者,我们可以添加一个绑定到ShowPrice的CheckBox,然后尝试通过指定元素名称将列可见性绑定到IsChecked属性:


但是这些变通办法似乎都不起作用,我们总是得到相同的结果……

在这一点上,似乎唯一可行的方法是更改​​后台代码中的列可见性,在使用MVVM模式时,我们通常更希望避免这种情况……但是我不会这么快就放弃,至少不会放弃同时还有其他选择可供考虑

解决我们的问题的方法实际上非常简单,并且利用了Freezable类。此类的主要目的是定义具有可修改状态和只读状态的对象,但是在我们的案例中,有趣的功能是,即使Freezable对象不在视觉或逻辑树中,它们也可以继承DataContext。我不知道启用此行为的确切机制,但我们将利用它来使绑定工作正常进行……

这个想法是创建一个继承Freezable并声明一个Data依赖项属性的类(我称它为BindingProxy,原因很快就会变得很明显)。

public class BindingProxy : Freezable
{
    #region Overrides of Freezable

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }

    #endregion

    public object Data
    {
        get { return (object)GetValue(DataProperty); }
        set { SetValue(DataProperty, value); }
    }

    // Using a DependencyProperty as the backing store for Data.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty DataProperty =
        DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}

然后,我们可以在DataGrid的资源中声明此类的实例,并将Data属性绑定到当前的DataContext:


    

最后一步是指定此BindingProxy对象(可通过StaticResource轻松访问)作为绑定的源:


请注意,绑定路径的前缀为“ Data”,因为该路径现在是相对于BindingProxy对象的。

绑定现在可以正常工作,并且可以根据ShowPrice属性正确显示或隐藏该列。

推荐阅读
乐韵答题
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有