Get value from DataContext to MarkupExtension

I am using the MV-VM pattern

In my virtual machine, I have code like

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

I have a markup extension from which I would like to use the specified 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 + "Β»"; } 

I created an attached property Foo.Document and attached it to my page (the DataContext of the page is set by an instance of my ViewModel class

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

(so as not to enter it as a parameter every time I use the markup extension)

Now, in my markup extension, when I try to read a property attached to a document, I always get a null document. When debugging the binding, he sees that the problem with synchronization is that the attached property gets the correct value after starting the markup extension.

Is it possible to make this work somehow?

+4
source share
3 answers

The ProvideValue method is called twice, once when the XAML is evaluated by the parser and once when the values ​​are loaded. In this first call, the targetObject is just a kind of dummy object called SharedDP, not the object to which the markupextension extension applies. You need to skip this first call and use only the second call. This code works in our application.

  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; } 
+6
source

Perhaps you can associate the event with the Loaded or Initialized event on the page with your markup extensions. Or, perhaps you can put the markup extension in a XAML file after Foo.Document is specified.

Thank you Robelia WPF / XAML Team my blog

+1
source

Not the best way to do this. But this guy shows how to get a DataContext using reflection:

[WPF] Using InputBindings with MVVM Template

0
source

Source: https://habr.com/ru/post/1285657/


All Articles