Получить значение из DataContext в MarkupExtension - PullRequest
5 голосов
/ 03 июня 2009

Я использую шаблон 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>

(чтобы не вводить его в качестве параметра каждый раз, когда я использую расширение разметки)

Теперь, в моем расширении разметки, когда я пытаюсь прочитать вложенное свойство Document, я всегда получаю нулевой документ. При отладке привязки это выглядит как проблема синхронизации в том, что присоединенное свойство получает правильное значение после запуска расширения разметки.

Можно ли как-нибудь заставить это работать?

Ответы [ 3 ]

7 голосов
/ 17 июля 2010

Метод 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 голос
/ 03 июня 2009

Вы можете связать событие с событием Loaded или Initialized на странице, возможно, из ваших расширений. Или, возможно, вы можете поместить расширение разметки в файл XAML после упоминания Foo.Document.

Спасибо, Роб Рельея Команда WPF / XAML мой блог

0 голосов
/ 16 мая 2011

Не лучший способ сделать это. Но этот парень показывает, как получить DataContext, используя отражение:

[WPF] Использование InputBindings с шаблоном MVVM

...