【问题标题】:How do I evaluate a RelativeSource object in code to provide a valid Source equivalent如何评估代码中的 RelativeSource 对象以提供有效的 Source 等效项
【发布时间】:2015-02-18 12:42:35
【问题描述】:

我遇到了一种情况,我需要使用here 描述的技术来解析绑定引用RelativeSource 的绑定。我正在使用自定义标记扩展来允许我将实际的绑定对象分配给DependencyProperty,但不幸的是,当我尝试在DummyDO 中对Value 应用绑定时,它会尝试找到我的路径(例如Background) 在等效标识的 RelativeSourceDummyDO 上,但不存在。

我希望我可以通过存储传递给 ProvideValueserviceProvider 属性并使用

来解决这个问题
return this.TargetBinding.ProvideValue((IProvideValueTarget)this.ServiceProvider);

在稍后的标记扩展中,但这会导致一个非常奇怪的空引用异常,其中没有可访问的内容是空的(我的猜测是某些引用已经以某种方式无效)。

另一种方法是在我的ProvideValue 方法期间存储属性的实际来源,然后创建一个ProvideCurrentValue 的新方法,以便稍后根据DummyDO 方法重新评估绑定。我只是不知道该怎么做!任何帮助将不胜感激。

代码如下:

XAML

<StackPanel>
    <Button 
     h:ResponsiveBrush.CentreTrackBrush="True" 
     h:ResponsiveBrush.Binding="{e:PassBinding TargetBinding={Binding Background,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type StackPanel}}}}" 
     >
        <Button.Content>Try Me</Button.Content>
    </Button>
</StackPanel>

(h:ResponsiveBrush 与我们所追求的无关——这是我试图附加的行为,关键部分是在某些时候它需要解析它通过 PassBindingExtension 传递的 Binding 对象)

标记扩展

public class PassBindingExtension : MarkupExtension
{
    public PassBindingExtension() { }
    public PassBindingExtension(Binding targetBinding) 
    {
        this.TargetBinding = targetBinding;
    }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var valueGetter = serviceProvider as IProvideValueTarget;
        if (valueGetter != null) 
        { 
            // Get the object. NB that this will evaluate to a 
            // BUTTON given the XAML above NOT a StackPanel as I was hoping
            this.TargetObject = valueGetter.TargetObject; 
            this.TargetProperty = valueGetter.TargetProperty;

            /* 
               Ideally around here I need to evaluate the object to which 
               this. TargetBinding refers around here so I can get the correct
               value later.
            */
        }

        /* 
           Addendum: If I try the following at this point, my application vanishes into
           oblivion

           var oOriginalValue = this.TargetBinding.ProvideValue(serviceProvider);

           Not sure if that's intended or not, but since I don't need to get the 
           original value, I just need the info to work out where the future value 
           should come from, I'm not too fussed.
        */

        return this;
    }

    public object ProvideValueLate() 
    {
        object oOut = null;

        /* Somehow, here, I need to reliably obtain 
           the value of TargetProperty on the 
           RelativeSource that would be evaluated with 
           respect to TargetObject 
        */

        return oOut;
    }

    [ConstructorArgument("targetBinding")]
    public Binding TargetBinding { get; set; }

    public object TargetObject { get; set; }

    public object TargetProperty { get; set; }

    // Obsolete - doesn't work
    public IServiceProvider ServiceProvider { get; set; }

    // Was hoping this would let me sidestep the issue, but lamentably it doesn't
    public object ProvideValueLate_Old()
    {     return this.TargetBinding.ProvideValue((IProvideValueTarget)this.ServiceProvider); }
}

【问题讨论】:

  • 显示您的相关代码...没有代码,您的文字意义不大。
  • 我已经添加了标记扩展的代码,以及我如何在 XAML 中使用它。基本思想是让我能够将 h:ResponsiveBrush 应用于任意画笔属性,而不是例如只是背景或边框。
  • 我还应该指出,在编写问题时,其目的是构建一个依赖 Source 而不是 RelativeSource 的新绑定,因此将在 DummyDO 中成功绑定(来自链接的帖子) .这可能仍然不是一个糟糕的处理方式,但是为了便于阅读,我还没有半成品代码来构建一个新的绑定。

标签: c# wpf binding


【解决方案1】:

是的,无法准确解决这个问题,但确实设法使用了一种解决方法,基于以下几点:

  • {Binding RelativeSource={RelativeSource Self}} 通过标准依赖属性评估相关对象,其中 Self 可以是任何 RelativeSource。
  • 因此,在附加的行为上创建两个属性,一个用于我们想要属性的对象,另一个用于属性路径。称它们为 SourceObject 和 SourcePath。
  • 使用以下方法获取现有值。这是在 h:ResponsiveBrush 的事件处理程序中 - 我没有设法使用标记扩展来完成这项工作(这是我想要的,但不能拥有一切......):

    string sourcePath = ((DependencyObject)sender).GetValue(SourcePathProperty);
    DependencyObject sourceObject = ((DependencyObject)sender).GetValue(SourceObjectProperty);
    Binding b = new Binding(sourcePath) {Source = sourceObject};
    RadialGradientBrush sourceBrush = DependencyInterpreter.EvalBinding(b) as RadialGradientBrush;
    

得到我需要的东西,但我暂时不会接受这个答案,因为它没有回答问题 - 只是为处于类似情况的其他人提供了一种解决方法。如果有人知道为什么标记扩展方法不起作用,我仍然会非常感兴趣。

【讨论】:

    猜你喜欢
    • 2020-09-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-07
    • 2021-08-30
    相关资源
    最近更新 更多