Dav*_*itt 564 .net data-binding wpf xaml relativesource
如何使用RelativeSource
WPF绑定以及不同的用例?
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)
Dre*_*kes 128
Binding RelativeSource={
RelativeSource Mode=FindAncestor, AncestorType={x:Type ItemType}
}
...
Run Code Online (Sandbox Code Playgroud)
默认属性RelativeSource
是Mode
属性.这里给出了一整套有效值(来自MSDN):
PreviousData允许您在显示的数据项列表中绑定以前的数据项(而不是包含数据项的控件).
TemplatedParent指应用模板(其中存在数据绑定元素)的元素.这与设置TemplateBindingExtension类似,仅在Binding位于模板中时才适用.
Self指向要设置绑定的元素,并允许您将该元素的一个属性绑定到同一元素上的另一个属性.
FindAncestor指数据绑定元素的父链中的祖先.您可以使用它来绑定到特定类型或其子类的祖先.如果要指定AncestorType和/或AncestorLevel,则使用此模式.
Jef*_*ght 121
这是MVVM架构上下文中更直观的解释:
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模式.
Cor*_*ian 35
Bechir Bejaoui在他的文章中公开了WPF中RelativeSources的用例:
RelativeSource是一个标记扩展,当我们尝试将对象的属性绑定到对象本身的另一个属性时,在我们尝试将对象的属性绑定到其相对父项的另一个属性时,在特定的绑定情况下使用在自定义控件开发的情况下将依赖项属性值绑定到一块XAML时,最后在使用一系列绑定数据的差异的情况下.所有这些情况都表示为相对源模式.我将逐一揭露所有这些案件.
- 模式自我:
想象一下这个案例,我们想要一个矩形,它的高度总是等于它的宽度,一个正方形让我们说.我们可以使用元素名称来完成此操作
Run Code Online (Sandbox Code Playgroud)<Rectangle Fill="Red" Name="rectangle" Height="100" Stroke="Black" Canvas.Top="100" Canvas.Left="100" Width="{Binding ElementName=rectangle, Path=Height}"/>
但在上面这种情况下,我们有义务指出绑定对象的名称,即矩形.我们可以使用RelativeSource以不同的方式达到相同的目的
Run Code Online (Sandbox Code Playgroud)<Rectangle Fill="Red" Height="100" Stroke="Black" Width="{Binding RelativeSource={RelativeSource Self}, Path=Height}"/>
对于这种情况,我们没有义务提及绑定对象的名称,并且每当高度改变时,宽度将始终等于高度.
如果要将宽度参数设置为高度的一半,则可以通过向Binding标记扩展添加转换器来完成此操作.我们现在想象另一个案例:
Run Code Online (Sandbox Code Playgroud)<TextBlock Width="{Binding RelativeSource={RelativeSource Self}, Path=Parent.ActualWidth}"/>
上面的情况用于将给定元素的给定属性绑定到其直接父元素之一,因为此元素包含一个名为Parent的属性.这导致我们进入另一个相对源模式,即FindAncestor模式.
- 模式FindAncestor
在这种情况下,给定元素的属性将与其父元素之一Corse绑定.与上述情况的主要区别在于,由您决定层次结构中的祖先类型和祖先等级来绑定属性.顺便说一下,尝试使用这块XAML
Run Code Online (Sandbox Code Playgroud)<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的控件的属性.为了更好地理解这个问题,下面是一个例子
Run Code Online (Sandbox Code Playgroud)<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在第一个运行时之后进行评估.正如您在下图中所述,背景和内容从按钮内部应用到控件模板.
小智 30
我不断更新我对 Binding 的研究。
\n原创在这里
\nDataContext 是 FrameworkElement 中包含的 DependencyProperty。
\nPresentationFramework.dll
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
\n不过,这里只是简单提一下这样一个事实:可以包含所有 UI 控件的最接近的对象是 FrameworkElement。
\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直接从 Xaml 向 DataContext 分配值时,首先需要为值类型(例如 Integer 和 Boolean)定义资源。\n因为所有字符串都被识别为 String。
mscrolib
\n\n\n标准不支持简单类型变量类型。
\n
\n你可以用任何单词来定义它,但大多数情况下都使用sys
单词。
xmlns:sys="clr-namespace:System;assembly=mscorlib"\n
Run Code Online (Sandbox Code Playgroud)\n2. 在 xaml 中创建YEAR
资源密钥\n\n\n以 StaticResource 的形式声明要创建的类型的值。
\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很少有值类型直接绑定到 DataContext 的情况。
\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不仅是字符串,还可以是各种类型。因为 DataContext 是对象类型。\n
在WPF中使用Binding时,大多数开发人员并没有充分意识到DataContext的存在、功能和重要性。
\n这可能意味着 Binding 正在幸运地连接。
\n\n特别是如果您负责或参与大型WPF项目,您应该更清楚地了解应用程序的DataContext层次结构。另外,引入WPF各种流行的MVVM Framework系统而没有这个DataContext概念,将会对自由实现功能产生更大的限制。\n
\n
string property
<TextBox Text="{Binding Keywords}"/>\n
Run Code Online (Sandbox Code Playgroud)\n <CheckBox x:Name="usingEmail"/>\n<TextBlock Text="{Binding ElementName=usingEmail, Path=IsChecked}"/>\n
Run Code Online (Sandbox Code Playgroud)\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 <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
绑定你自己的财产。
<TextBlock Text="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"/>\n
Run Code Online (Sandbox Code Playgroud)\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 这是一种可以在 内部使用的方法ControlTemplate
,并且您可以导入作为 的所有者的控件ControlTemplate
。
<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 您可以直接访问绑定属性值。
\n1. 声明static
属性。\nnamespace 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
。
<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\n正常情况下我从来没有使用过静态属性。这是因为偏离其自身 DataContext 的数据可能会破坏整个 WPF 应用程序的流程并严重损害可读性。然而,这种方法在开发阶段被积极使用,以实现快速测试和功能,以及在DataContext(或ViewModel)中。
\n
\n
\xc2\xa0 \xc2\xa0 \xc2\xa0通过连接的控件使用 ElementBinding 不是功能问题,
\n\xc2\xa0 \xc2\xa0 \xc2\xa0 但它破坏了 Binding 的基本模式。
<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 <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 <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
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
自我绑定.例如:设置打开时发送检查状态为
checkbox
asCommandParameter
Command
CheckBox
<CheckBox ...... CommandParameter="{Binding RelativeSource={RelativeSource Self},Path=IsChecked}" />
Run Code Online (Sandbox Code Playgroud)
d.FindAncestor(
value=3
):当想要从父进程绑定control
时Visual Tree
.例如:绑定
checkbox
的records
,如果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
.
Bob*_*ing 18
不要忘记TemplatedParent:
<Binding RelativeSource="{RelativeSource TemplatedParent}"/>
Run Code Online (Sandbox Code Playgroud)
要么
{Binding RelativeSource={RelativeSource TemplatedParent}}
Run Code Online (Sandbox Code Playgroud)
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'的例子会更长.
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
小智 9
我没有阅读每个答案,但我只想在按钮的相对源命令绑定的情况下添加此信息.
当您使用相对源时Mode=FindAncestor
,绑定必须类似于:
Command="{Binding Path=DataContext.CommandProperty, RelativeSource={...}}"
Run Code Online (Sandbox Code Playgroud)
如果未在路径中添加DataContext,则在执行时无法检索该属性.
这是在空数据网格上使用这种模式的一个例子.
<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)
如果元素不属于视觉树,则RelativeSource将永远无法工作。
在这种情况下,您需要尝试由Thomas Levesque开创的另一种技术。
他在[WPF]下的博客中提供了解决方案,该方法在不继承DataContext时如何绑定数据。而且它绝对出色!
万一他的博客被关闭,这种情况极少发生,附录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属性正确显示或隐藏该列。
归档时间: |
|
查看次数: |
413486 次 |
最近记录: |