从DataContext获取值到MarkupExtension

mos*_*ech 5 c# wpf datacontext xaml mvvm

我正在使用MV-VM模式

在我的VM中,我有类似的代码

public class ViewModel {
    public XmlDocument Document { ... }
    ....
}
Run Code Online (Sandbox Code Playgroud)

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

  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 + "»";
    }
Run Code Online (Sandbox Code Playgroud)

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

<Page ... lc:Foo.Document="{Binding Document}">
  ...
</Page>
Run Code Online (Sandbox Code Playgroud)

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

现在,在我的标记扩展中,当我尝试读取Document附加属性时,我总是得到一个空文档.通过调试绑定,它看起来像一个计时问题,因为附加属性在运行标记扩展后获得适当的值.

有可能以某种方式让这个工作?

Rob*_*Rob 7

ProvideValue方法被调用两次,一次是在解析器评估XAML时,一次是在加载值时.在第一次调用时,targetObject只是一种名为SharedDP的虚拟对象,而不是markupextension应用于的对象.你需要跳过第一个电话,只处理第二个电话.这是代码适用于我们的应用程序.

   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; 


    }
Run Code Online (Sandbox Code Playgroud)

  • 这对我来说根本不会发生......只召唤一次 (2认同)

小智 1

也许您可以将事件从标记扩展连接到页面上的“已加载”或“已初始化”事件。或者,您可以在提及 Foo.Document 之后将标记扩展放入 XAML 文件中。

谢谢 Rob Relyea WPF/XAML 团队 我的博客