我正在使用M-V-VM模式
在我的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>
(为了不必在每次使用标记扩展时都将其作为参数输入)
现在,在我的标记扩展中,当我尝试读取Document附加属性时,我总是得到一个空文档。通过调试绑定,它看起来像一个计时问题,附加属性在运行标记扩展后获得正确的值。
有可能以某种方式让这个工作吗?
答案 0 :(得分: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;
}
答案 1 :(得分:1)
您可以通过markupextensions将事件连接到Page上的Loaded或Initialized事件。 或者也许你可以在提到Foo.Document之后将你的标记扩展名放在XAML文件中。
谢谢,Rob Relyea WPF / XAML团队 my blog
答案 2 :(得分:0)
不是最好的方法。但是,这个人展示了如何使用反射获得DataContext
: