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

Dav*_*itt 564 .net data-binding wpf xaml relativesource

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

Abe*_*cht 755

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

{Binding Path=PathToProperty, RelativeSource={RelativeSource Self}}
Run Code Online (Sandbox Code Playgroud)

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

{Binding Path=PathToProperty,
    RelativeSource={RelativeSource AncestorType={x:Type typeOfAncestor}}}
Run Code Online (Sandbox Code Playgroud)

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

{Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}
Run Code Online (Sandbox Code Playgroud)

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

{TemplateBinding Path=PathToProperty}
Run Code Online (Sandbox Code Playgroud)

  • 对于这个"{Binding Path = PathToProperty,RelativeSource = {RelativeSource AncestorType = {x:Type typeOfAncestor}}}",看起来它需要在"AncestorType"之前有"Mode = FindAncestor" (12认同)
  • 只是想在此注意,如果要绑定到RelativeSource的DataContext中的属性,则必须明确指定它:`{Binding Path = DataContext.SomeProperty,RelativeSource = ...`.当我尝试绑定到DataTemplate中的父级DataContext时,这对我来说有些出乎意料. (4认同)
  • 我同意@EdwardM。当我在`AncestorType`之前省略`FindAncestor`时,出现以下错误:“ RelativeSource不在FindAncestor模式下”。(在VS2013中,社区版) (2认同)
  • @kmote,自 .net 3.0 以来,这对我来说一直有效,并且我再次验证了它在 kaxaml 中以这种方式工作......再说一遍,您使用什么技术?WPF/Silverlight/UWP 的 XAML 处理器不同,因此在不同的技术上可能会得到不同的结果。您还提到了 VS Community,所以也许这是一个 IDE 警告,但在运行时有效? (2认同)

Dre*_*kes 128

Binding RelativeSource={
    RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

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


Jef*_*ght 121

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

在此输入图像描述

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

las*_*iya 41

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

<Rectangle Fill="Red" Name="rectangle" 
                    Height="100" Stroke="Black" 
                    Canvas.Top="100" Canvas.Left="100"
                    Width="{Binding ElementName=rectangle,
                    Path=Height}"/>
Run Code Online (Sandbox Code Playgroud)

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

<Rectangle Fill="Red" Height="100" 
                   Stroke="Black" 
                   Width="{Binding RelativeSource={RelativeSource Self},
                   Path=Height}"/>
Run Code Online (Sandbox Code Playgroud)

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

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

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
                   Path=Parent.ActualWidth}"/>
Run Code Online (Sandbox Code Playgroud)

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

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

Cor*_*ian 35

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

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

  1. 模式自我:

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

<Rectangle Fill="Red" Name="rectangle" 
                Height="100" Stroke="Black" 
                Canvas.Top="100" Canvas.Left="100"
                Width="{Binding ElementName=rectangle,
                Path=Height}"/>
Run Code Online (Sandbox Code Playgroud)

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

<Rectangle Fill="Red" Height="100" 
               Stroke="Black" 
               Width="{Binding RelativeSource={RelativeSource Self},
               Path=Height}"/>
Run Code Online (Sandbox Code Playgroud)

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

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

 <TextBlock Width="{Binding RelativeSource={RelativeSource Self},
               Path=Parent.ActualWidth}"/>
Run Code Online (Sandbox Code Playgroud)

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

  1. 模式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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

  1. 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>
Run Code Online (Sandbox Code Playgroud)

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


小智 30

我不断更新我对 Binding 的研究。

\n

原创在这里

\n

数据上下文

\n

DataContext 是 FrameworkElement 中包含的 DependencyProperty。
\nPresentationFramework.dll

\n
namespace System.Windows\n{\n    public class FrameworkElement : UIElement\n    {\n        public static readonly DependencyProperty DataContextProperty;\n        public object DataContext { get; set; }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

并且,WPF 中的所有 UI 控件都继承该类FrameworkElement

\n
\n

此时,在学习 Binding 或 DataContext 时,您不必更深入地研究 FrameworkElement。
\n不过,这里只是简单提一下这样一个事实:可以包含所有 UI 控件的最接近的对象是 FrameworkElement。
\n

\n
\n

DataContext 始终是 Binding 的参考点。

\n

绑定可以直接从最近的 DataContext 开始调用 DataContext 类型格式的值。

\n
<TextBlock Text="{Binding}" DataContext="James"/>\n
Run Code Online (Sandbox Code Playgroud)\n

绑定到的值Text="{Binding}"直接从最近的 DataContext 传递TextBlock
\n因此,Binding结果值为Text\'James\'。
\n

\n
    \n
  • 类型整数
    \n直接从 Xaml 向 DataContext 分配值时,首先需要为值类型(例如 Integer 和 Boolean)定义资源。\n因为所有字符串都被识别为 String。

    \n1. 在 Xaml 中使用系统mscrolib\n
    \n

    标准不支持简单类型变量类型。
    \n你可以用任何单词来定义它,但大多数情况下都使用sys单词。

    \n
    \n
    xmlns:sys="clr-namespace:System;assembly=mscorlib"\n
    Run Code Online (Sandbox Code Playgroud)\n2. 在 xaml 中创建YEAR资源密钥\n
    \n

    以 StaticResource 的形式声明要创建的类型的值。

    \n
    \n
    <Window.Resources>\n    <sys:Int32 x:Key="YEAR">2020</sys:Int32>\n</Window.Resources>\n...\n<TextBlock Text="{Binding}" DataContext="{StaticResource YEAR"/>\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 所有类型的值
    \n很少有值类型直接绑定到 DataContext 的情况。
    \n因为我们要绑定一个对象。

    \n
    <Window.Resources>\n    <sys:Boolean x:Key="IsEnabled">true</sys:Boolean>\n    <sys:double x:Key="Price">7.77</sys:double>\n</Window.Resources>\n...\n<StackPanel>\n    <TextBlock Text="{Binding}" DataContext="{StaticResource IsEnabled}"/>\n    <TextBlock Text="{Binding}" DataContext="{StaticResource Price}"/>\n</StackPanel>\n
    Run Code Online (Sandbox Code Playgroud)\n
  • \n
  • 另一种类型
    \n不仅是字符串,还可以是各种类型。因为 DataContext 是对象类型。\n

    \n
  • \n
\n

最后...

\n

在WPF中使用Binding时,大多数开发人员并没有充分意识到DataContext的存在、功能和重要性。
\n这可能意味着 Binding 正在幸运地连接。

\n
\n

特别是如果您负责或参与大型WPF项目,您应该更清楚地了解应用程序的DataContext层次结构。另外,引入WPF各种流行的MVVM Framework系统而没有这个DataContext概念,将会对自由实现功能产生更大的限制。\n

\n
\n
\n

捆绑

\n
    \n
  • 数据上下文绑定
  • \n
  • 元素绑定
  • \n
  • 多重绑定
  • \n
  • 自属性绑定
  • \n
  • 寻找祖先绑定
  • \n
  • 模板化父绑定
  • \n
  • 静态属性绑定
    \n
  • \n
\n

数据上下文绑定

\n

string property

\n
<TextBox Text="{Binding Keywords}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

元素绑定

\n
<CheckBox x:Name="usingEmail"/>\n<TextBlock Text="{Binding ElementName=usingEmail, Path=IsChecked}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

多重绑定

\n
<TextBlock Margin="5,2" Text="This disappears as the control gets focus...">\n  <TextBlock.Visibility>\n      <MultiBinding Converter="{StaticResource TextInputToVisibilityConverter}">\n          <Binding ElementName="txtUserEntry2" Path="Text.IsEmpty" />\n          <Binding ElementName="txtUserEntry2" Path="IsFocused" />\n      </MultiBinding>\n  </TextBlock.Visibility>\n</TextBlock>\n
Run Code Online (Sandbox Code Playgroud)\n
\n \n### 自属性绑定\n
<TextBlock x:Name="txt" Text="{Binding ElementName=txt, Path=Tag}"/>\n
Run Code Online (Sandbox Code Playgroud)\n

如果你必须绑定自己的属性,你可以使用Self Property Binding, 而不是使用Element Binding
\n你不再需要声明x:Name绑定你自己的财产。

\n
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n \n### 查找祖先绑定\n根据最接近它的父控件导入。\n
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=Title}"/>\n
Run Code Online (Sandbox Code Playgroud)\n

除了找到的控件的属性之外,还可以使用 DataContext 对象中的属性(如果存在)。

\n
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.Email}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

模板化父绑定

\n

这是一种可以在 内部使用的方法ControlTemplate,并且您可以导入作为 的所有者的控件ControlTemplate

\n
<Style TargetType="Button">\n  <Setter Property="Template">\n      <Setter.Value>\n          <ControlTemplate TargetType="Button">\n              <TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/>\n          </ControlTemplate>\n      </Setter.Value>\n  </Setter>\n
Run Code Online (Sandbox Code Playgroud)\n

您可以访问所有Property 和DataContext。

\n
<TextBlock Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Content}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

静态属性绑定

\n

您可以直接访问绑定属性值。

\n1. 声明static属性。\n
namespace Exam\n{\n  public class ExamClass\n  {\n      public static string ExamText { get; set; }\n  }\n} \n
Run Code Online (Sandbox Code Playgroud)\n2. 在 XAML 中使用静态类。\n
<Window ... xmlns:exam="clr-namespace:Exam">\n
Run Code Online (Sandbox Code Playgroud)\n3. 绑定属性。\n
<TextBlock Text="{Binding exam:ExamClass.ExamText}"/>\n
Run Code Online (Sandbox Code Playgroud)\n

或者,您可以像使用 一样设置资源键Converter

\n
<Window.Resource>\n  <cvt:VisibilityToBooleanConverter x:Key="VisibilityToBooleanConverter"/>\n  <exam:ExamClass x:Key="ExamClass">\n</Window.Resource>\n...\n\n<TextBlock Text="{Binding Source={StaticResource ExamClass}, Path=ExamText}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

正常情况下我从来没有使用过静态属性。这是因为偏离其自身 DataContext 的数据可能会破坏整个 WPF 应用程序的流程并严重损害可读性。然而,这种方法在开发阶段被积极使用,以实现快速测试和功能,以及在DataContext(或ViewModel)中。
\n

\n
\n
\n

不良装订与良好装订

\n

\xe2\x9c\x94\xef\xb8\x8f 如果要绑定的属性包含在 Datacontext 中,
\xc2\xa0 \xc2\xa0 \xc2\xa0 则不必使用 ElementBinding。

\n

\xc2\xa0 \xc2\xa0 \xc2\xa0通过连接的控件使用 ElementBinding 不是功能问题,
\n\xc2\xa0 \xc2\xa0 \xc2\xa0 但它破坏了 Binding 的基本模式。

\n 错误绑定\n
<TextBox x:Name="text" Text="{Binding UserName}"/>\n...\n<TextBlock Text="{Binding ElementName=text, Path=Text}"/>\n
Run Code Online (Sandbox Code Playgroud)\n 良好的绑定\n
<TextBox Text="{Binding UserName}"/>\n...\n<TextBlock Text="{Binding UserName}"/>\n
Run Code Online (Sandbox Code Playgroud)\n
\n

\xe2\x9c\x94\xef\xb8\x8f 使用属于较高层控件的属性时不要使用 ElementBinding。

\n 错误绑定\n
<Window x:Name="win">\n  <TextBlock Text="{Binding ElementName=win, Path=DataContext.UserName}"/>\n  ...\n
Run Code Online (Sandbox Code Playgroud)\n 良好的绑定\n
<Window>\n  <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext.UserName}"/>\n  ...\n
Run Code Online (Sandbox Code Playgroud)\n 太棒了!\n
<Window>\n  <TextBlock DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}, Path=DataContext}" \n             Text="{Binding UserName}"/>\n  ...\n
Run Code Online (Sandbox Code Playgroud)\n
\n

\xe2\x9c\x94\xef\xb8\x8f 使用自己的属性时不要使用 ElementBinding。

\n 错误绑定\n
<TextBlock x:Name="txt" Text="{Binding ElementName=txt, Path=Foreground}"/>\n
Run Code Online (Sandbox Code Playgroud)\n 良好的绑定\n
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Foreground}"/>\n
Run Code Online (Sandbox Code Playgroud)\n

  • 这个论坛上最被低估的答案。好工作! (4认同)

Kyl*_*Ren 27

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

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

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

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

例如,定义ControlTemplate:

  <ControlTemplate>
        <CheckBox IsChecked="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
 </ControlTemplate>
Run Code Online (Sandbox Code Playgroud)

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

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

<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />
Run Code Online (Sandbox Code Playgroud)

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

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

<CheckBox IsChecked="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}, Path=DataContext.IsHeaderChecked, Mode=TwoWay}" />
Run Code Online (Sandbox Code Playgroud)

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

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid}}
Run Code Online (Sandbox Code Playgroud)

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

RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type iDP:XamDataGrid, AncestorLevel=1}}
Run Code Online (Sandbox Code Playgroud)

以上是所有用例RelativeSource binding.

这是一个参考链接.

  • 太棒了.. 这对我有用: &lt;DataGridCheckBoxColumn Header="Paid" Width="35" Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.SelectedBuyer.IsPaid , Mode=OneWay}" /&gt; 我试图绑定到父窗口的 selectedbuyer.IsPaid 属性 (2认同)

Bob*_*ing 18

不要忘记TemplatedParent:

<Binding RelativeSource="{RelativeSource TemplatedParent}"/>
Run Code Online (Sandbox Code Playgroud)

要么

{Binding RelativeSource={RelativeSource TemplatedParent}}
Run Code Online (Sandbox Code Playgroud)


小智 13

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

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


Lui*_*rez 13

我创建了一个库来简化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}
Run Code Online (Sandbox Code Playgroud)

后:

{BindTo PathToProperty}
{BindTo Ancestor.typeOfAncestor.PathToProperty}
{BindTo Template.PathToProperty}
{BindTo #MyTextBox.Text}
Run Code Online (Sandbox Code Playgroud)

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

// 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}
Run Code Online (Sandbox Code Playgroud)

后:

// C# code
private void SaveObject() {
 // do something
}

// XAML
{BindTo SaveObject()}
Run Code Online (Sandbox Code Playgroud)

你可以在这里找到这个图书馆:http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

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

  • 这种手持练习表明了XAML的弱点;*方式*太复杂了. (2认同)

Nat*_*per 13

一些有用的零碎:

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

Binding b = new Binding();
b.RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, this.GetType(), 1);
b.Path = new PropertyPath("MyElementThatNeedsBinding");
MyLabel.SetBinding(ContentProperty, b);
Run Code Online (Sandbox Code Playgroud)

我很大程度上是在代码Behind中Binding Relative Source复制了它.

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

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

Juv*_*uve 10

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


小智 9

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

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

Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"
Run Code Online (Sandbox Code Playgroud)

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


Edd*_*Edd 8

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

<Style.Triggers>
    <DataTrigger Binding="{Binding Items.Count, RelativeSource={RelativeSource Self}}" Value="0">
        <Setter Property="Background">
            <Setter.Value>
                <VisualBrush Stretch="None">
                    <VisualBrush.Visual>
                        <TextBlock Text="We did't find any matching records for your search..." FontSize="16" FontWeight="SemiBold" Foreground="LightCoral"/>
                    </VisualBrush.Visual>
                </VisualBrush>
            </Setter.Value>
        </Setter>
    </DataTrigger>
</Style.Triggers>
Run Code Online (Sandbox Code Playgroud)


Con*_*ngo 5

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

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

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

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

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

附录A:博客文章的镜像

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

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

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding ShowPrice,
                Converter={StaticResource visibilityConverter}}"/>
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding DataContext.ShowPrice,
                Converter={StaticResource visibilityConverter},
                RelativeSource={RelativeSource FindAncestor, AncestorType=DataGrid}}"/>
Run Code Online (Sandbox Code Playgroud)

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

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding IsChecked,
                Converter={StaticResource visibilityConverter},
                ElementName=chkShowPrice}"/>
Run Code Online (Sandbox Code Playgroud)

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

在这一点上,似乎唯一可行的方法是更改​​后台代码中的列可见性,在使用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));
}
Run Code Online (Sandbox Code Playgroud)

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

<DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Data="{Binding}" />
</DataGrid.Resources>
Run Code Online (Sandbox Code Playgroud)

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

<DataGridTextColumn Header="Price" Binding="{Binding Price}" IsReadOnly="False"
                Visibility="{Binding Data.ShowPrice,
                Converter={StaticResource visibilityConverter},
                Source={StaticResource proxy}}"/>
Run Code Online (Sandbox Code Playgroud)

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

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