在视觉树之外进行数据绑定。数据上下文桥接。

9
我正在尝试将动态行为绑定到WPF逻辑和视觉树之外的可视元素。我的问题是,RadChart绘图颜色在(quasi path)中给出: RadChart.SeriesMapping.LineSeriesDefinition.Appearance.Stroke 我最初想将其绑定到XAML中图表数据上下文的属性。天真地,我只写了一个常规的{Binding PlotBrush}
编译器返回“找不到主要的FrameWorkelement”错误。阅读后,我认为这意味着无法解析层次结构中的数据上下文。因为它的祖先(XAML讲话)有其他类型而且与内容控件的内容不同。
至少,这是我目前的理解。请纠正我。
所以,我找到了“DataContext Bridge” http://www.codeproject.com/KB/WPF/AttachingVirtualBranches.aspx 简单来说,它表示您将运行时分配数据上下文的框架元素的数据上下文属性(而不是任何继承它的属性)与“资源内的FrameWorkElement实例”的数据上下文绑定。然后,使用相同的资源对象实例来绑定到您希望“附加”到DataContext继承动态的“分支”的DataContext属性。但文章的作者有幸能够实现观察属性的ValidationRule消费者。SolidColorBrush是密封的,我想即使使用装饰器实现完整的Brush也需要相当多的工作。
在我的情况下,这并不能帮助我做到我想要的,但我“非常接近”。因此,我想知道是否有一些XAML技巧可以帮助我。
<Window.Resources>
    <local:FrameWorkElement x:Key="DataContextBridge"/>
</Window.Resources>

然而,目前还不清楚我该如何利用它。没有任何对象其数据上下文应该被设置。AppearanceSettings 不是一个 FrameworkElement。

<telerik:SeriesAppearanceSettings>
   <telerik:SeriesAppearanceSettings.Stroke>
       Ok, how do I use the fact that I can access the datacontext here?                                         
   </telerik:SeriesAppearanceSettings.Stroke>
</telerik:SeriesAppearanceSettings>

所以,下一步是我是否可以直接获取刷子对象。我进行了一些实验,随意尝试了这种事情:
.cs:
public class ObservableBrush : FrameworkElement
{
    public Brush Brush
    {
        get { return (Brush) GetValue(BrushProperty); }
        set { SetValue(BrushProperty, value); }
    }

    public static readonly DependencyProperty BrushProperty =
        DependencyProperty.Register("Brush", typeof (Brush), typeof (ObservableBrush), new UIPropertyMetadata(new SolidColorBrush(Colors.Black)));
}

XAML的顶部:
<Window.Resources>
    <local:ObservableBrush x:Key="StrokeBrush"/>
</Window.Resources>

内联XAML:

<telerik:SeriesAppearanceSettings.Stroke>
     <Binding Path="Brush">
     <Binding.Source>
          <Binding Source="{StaticResource ResourceKey=StrokeBrush}" Path="DataContext"/>
     </Binding.Source>                                            
     </Binding>                                     
</telerik:SeriesAppearanceSettings.Stroke>

"Binding"不是一个框架元素,"Source"也不是一个依赖属性,因此运行时会报错。我知道Brush属性永远不会返回除了在依赖属性注册中给定的默认值以外的任何值。
我已经连续第二天在解决这个问题。我认为我的下一步尝试将是: * 将ObservableBrush变成实际的Brush。然后通过编程方式设置它(有效地使用标准动态资源绑定)。我不喜欢这样做。我想让数据绑定工作。 * 桥接一个BRUSH而不是DATACONTEXT。
XAML部分正常工作:
<telerik:SeriesAppearanceSettings.Stroke>
     <Binding Source="{StaticResource ResourceKey=StrokeBrush}" Path="Brush"/>
</telerik:SeriesAppearanceSettings.Stroke>

但是,我该如何将Brush绑定到DataContext属性上呢?在ObservableBrush中有没有可以使用的重写方法,使得Brush可以动态地跟随数据上下文中的Brush?

那么在树形结构中创建一个虚拟的可视元素,然后将两个绑定关联到它上面怎么样?

<!-- Within the visual tree scope -->
<SomeFrameWorkElementType>
     <SomeFrameWorkElemetType.SomeBrushProp>
         <Binding Source="{StaticResource ResourceKey=StrokeBrush}" Path="Brush" Mode="OneWayToSource"/>
         <Binding Stroke/>
     </SomeFrameWorkElemetType.SomeBrushProp>
<SomeFrameWorkElementType>

这样会“连接”这两个绑定吗?

还是有一些(非)官方的“辅助类”来实现此类功能?

或者我是在错误的道路上,最好通过动态资源绑定在代码后台解决这个问题?

如何继续进行的任何想法或观察?除了我坚持数据绑定而动态资源应该解决这个问题之外。


正如某人可能会注意到的那样,DynamicResource也需要对象树......因此,问题依旧存在。 - Tormod
1个回答

13

你在那里找到了Josh Smith写的一篇好文章,但它有点过时。同样的作者在一年后写了一篇更好的文章,涵盖了基本相同的问题,但有更好的答案:Artificial Inheritance Context

他在那里使用了DataContextSpy类,虽然我仍然不完全明白你试图实现什么,但我会尝试向您展示如何使用它:

<Grid><!-- this is some container where its DataContext has the PlotBrush Property-->
    <Grid.Resources>
        <spy:DataContextSpy x:Key="Spy"/>
    </Grid.Resources>
    <telerik:thisIsYourControl>
        <telerik:SeriesAppearanceSettings.Stroke>
             <Binding Source="{StaticResource Spy}" Path="DataContext.PlotBrush"/>
        </telerik:SeriesAppearanceSettings.Stroke>
    </telerik:thisIsYourControl>
<Grid>

希望这对你有所帮助并且能够正常工作。我之前没有使用过Telerik控件,所以我无法编写完整的示例代码,但仍然希望这可以涵盖你的需求。


谢谢您的评论。很好的阅读。DataContextSpy也很不错,但它没有解决我的问题。在他的文章中,他正在操作Image的url属性。Image类是FrameworkElement,因此它可以有一个DataContext。在我的情况下,既不是AppearanceSettings(绑定“Stroke”属性)也不是Brush(绑定“Color”属性)是FrameWorkElement。我的问题不在于使DataContext从资源中可访问。而是如何在资源内使用DataContext,在XAML中为非FrameworkElement类型的对象的属性分配Brush或Color。 - Tormod
1
@Tormod,你真的尝试过我的解决方案吗?在这个例子中,重要的不是绑定的是一个图像,而是这个图像位于<ListBoxItem.Tag>中,这会破坏元素树。因此,如果没有DataContextSpy,这个绑定就无法工作。在你的问题中,你说_XAML部分运行良好:_ - 以下XAML告诉我,在你的情况下,可以将绑定绑定到资源上的属性。这就是为什么我相信建议的解决方案可行。请试一试! - Markus Hütter
它奏效了。我有点困惑。非常感谢您的时间和坚持不懈。我意识到当提供 <Binding> xaml 元素作为内容时,我并不知道实际发生了什么。我没有预料到绑定实例会解析为 BrushType。我不久前参加了一门高级 WPF 课程。这就是我们应该在那里学习的类型,而不是花费数小时用 XAML 搞图形。您能否查看原帖中“Inline XAML:”下面的 XAML,并告诉我为什么它不起作用?“Source isn't dependency prop”。 - Tormod
1
@Tormod,要使用“Binding”,底层属性必须是DependencyProperty。telerik:SeriesAppearanceSettings.Stroke就是一个DependencyProperty。而Binding.Source则不是。这就是为什么会出现错误提示的原因。因此,无法将Binding的Source属性绑定到其他属性! - Markus Hütter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接