【问题标题】:Get value from DataContext to MarkupExtension从 DataContext 获取值到 MarkupExtension
【发布时间】:2010-10-30 22:54:12
【问题描述】:

我正在使用 M-V-VM 模式

在我的虚拟机中,我有类似的代码

public class ViewModel {
    public XmlDocument Document { ... }
    ....
}

我有一个标记扩展,我想从中使用该文档

  public override object ProvideValue(IServiceProvider serviceProvider) {
        IProvideValueTarget valueProvider = serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        if (valueProvider != null) {
            DependencyObject target = valueProvider.TargetObject as DependencyObject;
            XmlDocument doc = Foo.GetDocument(target);
            if (doc != null) {
                var n = doc.SelectSingleNode("/.../text()");
                if (n != null) return n.Value;
            }
        }
        return "«" + ObjectProperty + "»";
    }

我创建了附加属性 Foo.Document,并将其附加到我的页面(页面的 DataContext 设置为我的 ViewModel 类的实例

<Page ... lc:Foo.Document="{Binding Document}">
  ...
</Page>

(为了不必每次使用标记扩展时都将其作为参数输入)

现在,在我的标记扩展中,当我尝试读取文档附加属性时,我总是得到一个空文档。通过调试绑定,在运行标记扩展后,附加属性会获得正确的值,这似乎是一个计时问题。

有没有可能让它以某种方式工作?

【问题讨论】:

    标签: c# wpf xaml mvvm datacontext


    【解决方案1】:

    ProvideValue 方法被调用两次,一次是在解析器评估 XAML 时,一次是在加载值时。在第一次调用中,targetObject 只是一种称为 SharedDP 的虚拟对象,而不是应用标记扩展的对象。您需要跳过第一个电话,只处理第二个电话。 这是在我们的应用中运行的代码。

       public override object ProvideValue(IServiceProvider serviceProvider){                                
                    var pvt = serviceProvider as IProvideValueTarget;
                    if (pvt == null)
                    {
                        return null;
                    }
    
    
                    var frameworkElement = pvt.TargetObject as FrameworkElement;
                    if (frameworkElement == null)
                    {
                        return this;
                    }
    //.... Code will run once the markup is correctly loaded
     var dataContext = frameworkElement.DataContext; 
    
    
        }
    

    【讨论】:

    • 这对我来说根本不会发生...只被调用一次
    • 伟大的工作;这解决了我的问题。请注意,其中一些准备性“虚拟”调用是您获得可能需要的其他类型的服务提供者上下文并为以后保存的唯一机会。我特别指的是相关的 WPF NameScope 和/或根元素(WPF 使用它自己的名称范围机制而不是 XAML 的 FrameworkElements 等),当你在里面时,这几乎是不可能获得一些后来的 ProvideValue 调用一个控制模板。
    【解决方案2】:

    也许你可以从你的标记扩展中将一个事件连接到页面上的 Loaded 或 Initialized 事件。 或者您可以在提到 Foo.Document 之后将您的标记扩展名放在 XAML 文件中。

    谢谢,Rob Relyea WPF/XAML 团队 my blog

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 1970-01-01
      • 2015-04-04
      • 1970-01-01
      相关资源
      最近更新 更多