1

次のようなカスタム コントロールを作成すると:

public class MyControl : ContentControl
{
   public static readonly DependencyProperty ItemsProperty =               
         DependencyProperty.Register(
                "Items", 
                typeof(ObservableCollection<object>), 
                typeof(MyControl), 
                new PropertyMetadata(null));

   public MyControl()
   {   
       // Setup a default value to empty collection
       // so users of MyControl can call MyControl.Items.Add()
       Items = new ObservableCollection<object>();
   }

   public ObservableCollection<object> Items
   { 
      get { return (ObservableCollection<object>)GetValue(ItemsProperty); } 
      set { SetValue(ItemsProperty, value); } 
   } 
}

次に、ユーザーが Xaml で次のようにバインドできるようにします。

<DataTemplate>
    <MyControl Items="{Binding ItemsOnViewModel}"/>
</DataTemplate>

その後、バインディングは機能しません!これはDependency Property Precedenceによるもので、CLR Set 値を Template バインディングの上に置きます!

それで、これが機能しない理由は理解できますが、解決策があるのだろうか。My Control の MVVM パワーユーザーが DataTemplate を介して同じプロパティにバインドできるようにしながら、プログラムで項目を追加したいだけの MyControl の怠惰な消費者のために、ItemsProperty のデフォルト値を新しい ObservableCollection に提供することは可能ですか?

これは Silverlight & WPF 用です。スタイルの DynamicResource セッターは解決策のように見えましたが、Silverlight では機能しません :(

アップデート:

SetCurrentValue(ItemsProperty, new ObservableCollection<object>());WPFで、まさに私が望んでいることを確認できます。デフォルト値を書き込みますが、テンプレート バインディングによってオーバーライドできます。誰でもSilverlightに相当するものを提案できますか? 言うは易く行うは難し!:s

別の更新:

どうやら、値強制を使用して.NET3.5でSetCurrentValueをシミュレートでき、これらの手法を使用してSilverlightで値強制をシミュレートできます。おそらく、ここには (長ったらしい) 回避策があります。

値の強制を使用した .NET3.5 の SetCurrentValue の回避策
Silverlight の値の強制の回避策

4

2 に答える 2

0

依存関係プロパティのデフォルトプロパティを指定することはできません。

  public static readonly DependencyProperty ItemsProperty = DependencyProperty.Register(
        "Items",
        typeof(ObservableCollection<object>),
        typeof(CaseDetailControl),
        new PropertyMetadata(new ObservableCollection<object>()));

または私はあなたが求めているものが欠けていますか?

編集:

ああ...その場合、ゲッターでnullをチェックするのはどうですか?:

    public ObservableCollection<object> Items
    {
        get
        {
            if ((ObservableCollection<object>)GetValue(ItemsProperty) == null)
            {
                this.SetValue(ItemsProperty, new ObservableCollection<object>());
            }

            return (ObservableCollection<object>)GetValue(ItemsProperty);
        }

        set
        {
            this.SetValue(ItemsProperty, value);
        }
    }
于 2012-11-01T17:37:32.563 に答える
0

ObservableCollection プロパティが正しく動作しない場合、そのプロパティへの割り当てを破棄しようとします。どういうわけか、参照が正しく変換されず、バインディングが失われることがわかりました。その結果、ObservableCollection プロパティを実際に設定することは避けています (代わりに、既存のプロパティをクリアして要素を追加することを好みます)。セッターでゲッターを複数回呼び出すため、これは DependencyProperty で非常にずさんになります。代わりに INotifyPropertyChanged を使用することを検討してください。とにかく、これは次のようになります。

編集:SteveLの回答から露骨にゲッターを盗みました。GetValue への呼び出しが 1 回だけになるように少し作り直しました。良い回避策。

public ObservableCollection<object> Items
{ 
    get
    {
        ObservableCollection<object> coll = (ObservableCollection<object>)GetValue(ItemsProperty);
        if (coll == null)
        {
            coll = new ObservableCollection<object>();
            this.SetValue(ItemsProperty, coll);
        }

        return coll;
    }
    set 
    {
        ObservableCollection<object> coll = Items;
        coll.Clear();
        foreach(var item in value)
            coll.Add(item);
    }
} 

これは、正しく設定するためのデフォルトに依存することに注意してください。つまり、静的な ItemsProperty のデフォルトを正しいタイプの新しい ObservableCollection (つまり、new PropertyMetadata(new ObservableCollection())) に変更することを意味します。また、コンストラクターでそのセッターを削除する必要があります。そうでない場合は、確実に INotifyPropertyChanged の使用に移行することをお勧めします...

于 2012-11-01T17:28:28.053 に答える