8

MarkupExtensionコードからカスタムを設定するにはどうすればよいですか?

Xamlからなら簡単に設定できます。Bindingと についても同様DynamicResourceです。

<TextBox FontSize="{Binding MyFontSize}"
         Style="{DynamicResource MyStyle}"
         Text="{markup:CustomMarkup}"/>

コードビハインドで同じ値を設定するには、少し異なるアプローチが必要です

  1. バインディング: textBox.SetBinding または BindingOperations.SetBinding を使用します。

    Binding binding = new Binding("MyFontSize");
    BindingOperations.SetBinding(textBox, TextBox.FontSizeProperty, binding);
    
  2. DynamicResource: SetResourceReference を使用

    textBox.SetResourceReference(TextBox.StyleProperty, "MyStyle");
    
  3. CustomMarkup:MarkupExtensionコードからカスタムを設定するにはどうすればよいですか? ProvideValueその場合、どうすれば a を取得できますIServiceProviderか?*

    CustomMarkupExtension customExtension = new CustomMarkupExtension();
    textBox.Text = customExtension.ProvideValue(??);
    

この件に関して驚くほどほとんど見つけられなかったので、できますか?


HBは質問に答えました。なぜこれをやりたかったのか、ここにいくつかの詳細を追加するだけです。次の問題の回避策を作成しようとしました。

問題は、封印されているため、派生しBindingてオーバーライドできないことです。ProvideValue代わりに、次のようなことを行う必要があります: A base class for custom WPF binding markup extensions。しかし、問題は、 aBindingを a に返すSetterと例外が発生することですが、それ以外ではStyle正常に動作します。

が実際に適用された後に再評価できるようにする場合は、MarkupExtensionそれ自体を返す必要があることをいくつかの場所で読みましたが、これは理にかなっています。TargetObjectSetterFrameworkElement

ただし、それTargetPropertyは が typeobjectの場合にのみ機能し、それ以外の場合は例外が返されます。ソースコードをBindingBase見ると、まさにこれを行っていることがわかりますが、フレームワークにはそれを機能させる秘密の要素があるようです。

4

6 に答える 6

6

同等のコードはないと思います。サービスは XAML 経由でのみ利用できます。MSDNから:

MarkupExtension には、ProvideValue という仮想メソッドが 1 つだけあります。入力 serviceProvider パラメーターは、マークアップ拡張機能が XAML プロセッサによって呼び出されたときに、サービスが実装に伝達される方法です。

于 2011-09-20T19:21:40.833 に答える
5

コードで生成されますが、必ずしも 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; } }
}

残っている唯一の機能は、XAML オブジェクト モデルから「CustomMarkup」への参照を戻す機能です。上記では、それへの参照に固執する必要があります。

于 2012-02-09T04:20:36.877 に答える
3

マークアップ拡張機能がかなり単純で、バインディングを作成し、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));
    }
}

そして、コードでは、BindingOperations.SetBinding()の代わりにCommandExtension.SetBinding()を呼び出すことができます。

明らかに、これよりも複雑なことをしている場合、この解決策は適切でない可能性があります。

于 2012-11-15T22:59:25.907 に答える
2

この Silverlight TV ショーは、この問題に光を当てるかもしれません。役に立つかもしれないいくつかのコード サンプルを示していたのを思い出します。

于 2011-09-20T19:24:57.177 に答える
1

HB が指摘したように、aMarkupExtensionは XAML 内での使用のみを目的としています。

ユニークなのは、拡張構文または完全なマークアップを使用してコードで使用できるようにするものBindingから実際に派生することです。MarkupExtension{Binding ...}<Binding>...</Binding>

BindingOperationsただし、カスタム マークアップ拡張機能の使用方法とそれを target に適用する方法を知っている中間オブジェクト ( に似たもの) の作成をいつでも試すことができますDependencyObject

XamlSetMarkupExtensionAttributeこれを行うには、 (.NET 4 の場合) またはIReceiveMarkupExtensionインターフェイス (.NET 3.x の場合)を使用する必要があると思います。属性やインターフェイスをどのように利用するかは完全にはわかりませんが、正しい方向に向けられるかもしれません。

于 2011-09-20T21:31:13.363 に答える
0

コードからカスタム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
    }
}

コードからマークアップ拡張機能を使用する必要がある場合があることに気付いたので、常にそのような方法で記述しようとしています。

于 2017-06-23T11:36:44.120 に答える