2

ここでは、単純なブレンド ビヘイビアーを示します。DependencyPropertyでの初期化中に何かをしたいシングルがありますOnAttached。しかし、動作が初期化される前にアタッチされているように見えるため、できません!

使用法:

<Button>
    <e:Interaction.Behaviors>
        <local:TestBehavior Test1="{Binding ValueOnViewModel}"/>
    </e:Interaction.Behaviors>
<Button>

意味:

class TestBehavior : Behavior<FrameworkObject>
{
    public static readonly DependencyProperty Test1Property
        = DependencyProperty.Register("Test1", typeof(int), typeof(TestBehavior),
        new PropertyMetadata(OnTest1Property_Changed));

    private static void OnTest1Property_Changed(DependencyObject sender,
        DependencyPropertyChangedEventArgs args)
    {
        // This gets called _after_ OnAttached!
    }

    public int Test1
    {
        get { return (int)GetValue(Test1Property); }
        set { SetValue(Test1Property, value); }
    }

    protected override void OnAttached()
    {
        base.OnAttached();

        // No matter what Test1Property is bound to in XAML 'a' will be default
        // value because as this point the Behavior is attached, but not
        // initialized!
        int a = Test1;
    }
}

これは本当に奇妙に思えます。この単純なケースでは、OnAttached ではなく OnTest1Property_Changed で初期化を実行することで問題を回避できます (ただし、インスタンス コンテキストではなく静的コンテキストにあるという多少の不都合はあります)。

しかし、複数のプロパティを持つかなり自明ではないビヘイビアがある場合はどうなるでしょうか? 動作の一部の使用法では、すべての DP が明示的に設定される場合がありますが、明示的に設定されていない DP のデフォルト値を使用して一部の DP のみが設定される場合もあります。動作が定義するすべての DP の変更イベントを処理できますが、クライアントが XAML で明示的に設定した DP を知る方法がないため、初期化が完了する前に変更通知が発生する必要があることを知る方法がありません。 .

では、ビヘイビアーの初期化がいつ完了したかを知るにはどうすればよいのでしょうか? これは明らかな弱点のように思えるので、明らかな何かを見落としているとしか思えません。

[アップデート]

Sorskoot の提案を使用して、代わりにビヘイビアーのベースとして使用できるこの単純な基本クラスをノックアップしました。

public class BehaviorBase<T> : Behavior<T> where T : FrameworkElement
{
    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += AssociatedObject_Loaded;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.Loaded -= AssociatedObject_Loaded;
    }

    protected virtual void OnLoaded()
    {

    }

    private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
    {
        OnLoaded();
    }
}
4

1 に答える 1

2

Loadedメソッド内でイベントにアタッチし、OnAttachedそこで初期化することをお勧めします。

 protected override void OnAttached()
 {
      base.OnAttached();

      base.AssociatedObject.Loaded += onloaded;
 }

 private void onloaded(object sender, RoutedEventArgs e)
 {
      int a = Test1;
      // Test1 should contain a value here. 
 }
于 2013-05-07T20:23:16.797 に答える