Настройка пользовательского MarkupExtension из кода
как вы устанавливаете пользовательский MarkupExtension из кода?
вы можете легко установить, если из Xaml. То же самое касается Binding и DynamicResource.
<TextBox FontSize="{Binding MyFontSize}"
         Style="{DynamicResource MyStyle}"
         Text="{markup:CustomMarkup}"/>
установка тех же значений через код позади требует немного другого подхода
- 
обязательные: использовать текстовое поле.SetBinding или BindingOperations.SetBinding
Binding binding = new Binding("MyFontSize"); BindingOperations.SetBinding(textBox, TextBox.FontSizeProperty, binding); - 
DynamicResource: использовать SetResourceReference
textBox.SetResourceReference(TextBox.StyleProperty, "MyStyle"); - 
CustomMarkup: Как установить пользовательский
MarkupExtensionиз кода? Должен ли я позвонитьProvideValueи это тот случай, как я могу получитьIServiceProvider?*CustomMarkupExtension customExtension = new CustomMarkupExtension(); textBox.Text = customExtension.ProvideValue(??); 
я нашел удивительно мало на эту тему, так что, это можно сделать?
Г. Б.: ответил на вопрос. Просто добавляю некоторые детали, почему я хотел это сделать. Я попытался создать обходной путь для следующей проблемы.
проблема в том, что вы не можете наследовать от Binding и заменить ProvideValue так как он запечатан. Вам придется сделать что-то вроде этого: базовый класс для пользовательских расширений разметки привязки WPF. Но тогда проблема в том, что когда вы возвращаете Binding до Setter вы получаете исключение, но за пределами Style он работает нормально.
я читал в нескольких местах, что вы должны вернуть MarkupExtension сама если TargetObject это Setter чтобы позволить ему reeavaluate после того, как он применяется к фактическому FrameworkElement и это имеет смысл.
- расширение разметки в Data Trigger
 - огромное ограничение MarkupExtension
 - базовый класс для пользовательских расширений разметки привязки WPF (в комментариях)
 
однако это работает только тогда, когда TargetProperty типа object, иначе исключение-обратно. Если вы посмотрите на исходный код BindingBase вы можете видеть, что он делает именно это, но кажется, что структура имеет какой-то секретный ингредиент, который заставляет его работать.
6 ответов
Я думаю, что нет эквивалента кода, службы доступны только через XAML. От MSDN:
MarkupExtension имеет только один виртуальный метод, ProvideValue. Входной параметр serviceProvider-это способ передачи служб реализациям при вызове расширения разметки процессором XAML.
Как насчет этого в качестве альтернативы, он генерируется в коде, но не обязательно так элегантно, как XAML:
        var markup = new CustomMarkup();
        markup.ProvideValue(new Target(textBox, TextBox.TextProperty));
реализация для Target просто:
public struct Target : IServiceProvider, IProvideValueTarget
{
    private readonly DependencyObject _targetObject;
    private readonly DependencyProperty _targetProperty;
    public Target(DependencyObject targetObject, DependencyProperty targetProperty)
    {
        _targetObject = targetObject;
        _targetProperty = targetProperty;
    }
    public object GetService(Type serviceType)
    {
        if (serviceType == typeof(IProvideValueTarget))
            return this;
        return null;
    }
    object IProvideValueTarget.TargetObject { get { return _targetObject; } }
    object IProvideValueTarget.TargetProperty { get { return _targetProperty; } }
}
единственное, что остается, - это возможность получить ссылку на "CustomMarkup" из объектной модели XAML. С вышеизложенным вам нужно повиснуть на ссылке на него.
если расширение разметки довольно простое и создает привязку и возвращает результат из ProvideValue (), вы можете добавить простой вспомогательный метод:
public class CommandExtension : MarkupExtension
{
    public CommandExtension(string name)
    {
        this.Name = name;
    }
    public string Name { get; set; }
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return GetBinding(this.Name).ProvideValue(serviceProvider);
    }
    static Binding GetBinding(string name)
    {
        return new Binding("Commands[" + name + "]") { Mode = BindingMode.OneWay };
    }
    public static void SetBinding(DependencyObject target, DependencyProperty dp, string commandName)
    {
        BindingOperations.SetBinding(target, dp, GetBinding(commandName));
    }
}
а затем в коде вы можете просто вызвать CommandExtension.SetBinding () вместо BindingOperations.SetBinding().
очевидно, что если вы делаете что-то более сложное, чем это, то это решение может быть неуместным.
Это Silverlight ТВ-шоу может пролить свет на эту проблему. Я помню, что они показывали некоторые примеры кода, которые могут быть полезны.
как указал Х. Б., a MarkupExtension предназначен только для использования в XAML.
что составляет Binding уникальным является то, что на самом деле происходит от MarkupExtension что позволяет использовать синтаксис расширения {Binding ...} или полная разметка <Binding>...</Binding> и использовать его в коде.
однако вы всегда можете попробовать создать промежуточный объект (что-то сродни BindingOperations), который знает, как использовать пользовательские расширения разметки и применить его к цели DependencyObject.
чтобы сделать это, я считаю, что вам нужно будет использовать XamlSetMarkupExtensionAttribute (для .NET 4) или IReceiveMarkupExtension интерфейс (для .NET 3.икс.) Я не совсем уверен, как использовать атрибут и/или интерфейса, но он может указать вам в правильном направлении.
Как установить таможни MarkupExtension из кода?
если вы можете изменить его, то просто извлеките логику в отдельный SomeMethod который можно вызвать самостоятельно и / или из ProvideValue.
вместо
textBox.Text = customExtension.ProvideValue(??);
вы просто называете это
customExtension.SomeMethod(textBox, TextBox.TextProperty);
часто мы создаем на заказ расширения собственность (используется так в xaml):
<TextBox Text="{local:SomeExtension ...}" />
это можно написать вот так:
public class SomeExtension : MarkupExtension
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        var provider =     serviceProvider.GetService(typeof(IProvideValueTarget)) as IProvideValueTarget;
        var target = provider.TargetObject as DependencyObject;
        var property = provider.TargetProperty as DependencyProperty;
        // defer execution if target is data template
        if (target == null)
           return this;
        return SomeMethod(target, property);
    }
    public object SomeMethod(DependencyObject target, DependencyProperty property)
    {
        ... // do something
    }
}
поскольку я понял, что иногда необходимо использовать расширения разметки из кода, я всегда пытаюсь написать их таким образом.