属性のデフォルト値により、属性の有効性が保証されます。
属性検証の有効性を使用して、入力属性と属性の必須コールバックを検証できます。つまり、属性が変更されたかどうかに関係なく、通知を行う必要があります。
属性変更通知では、属性が変更された場合にプログラムに一連の処理を通知することができます。
ここで WPF に問題はありません。依存関係プロパティが上記の問題をどのように解決するかを見てみましょう。
コンテンツの概要は、最初の最も単純な依存関係属性、依存関係属性値、基本操作属性、ラッパー属性メタデータ (PropertyMetadata) を定義します。
属性メタデータの基本動作
MSDN の原文は単刀直入ですが、一度理解すると、見たときの印象が変わります。
1. 最初の最も単純な依存関係属性を定義します。
MSDN 原文: Windows Presentation Foundation (WPF) は、共通言語ランタイム (CLR) プロパティの機能を拡張するために使用できるサービスのセットを提供します。これらのサービスは、総称して WPF プロパティ システムと呼ばれることがよくあります。 WPF プロパティ システムでサポートされるプロパティは、依存関係プロパティと呼ばれます。
次のように、Age 依存関係属性を定義しましょう。
パブリック クラス DPCustomPeople
{
public static readonly dependencyProperty AgeProperty =
dependencyProperty.Register("年齢", typeof(int), typeof(DPCustomPeople));
public void DisplayAgeProperty()
{
Console.WriteLine("DPName:" + DPCustomPeople.AgeProperty.Name);
Console.WriteLine("DPPropertyType:" + DPCustomPeople.AgeProperty.PropertyType);
Console.WriteLine("DPOWnerType:" + DPCustomPeople.AgeProperty.OwnerType);
}
}
次に、出力結果を呼び出します
クラスプログラム
{
static void Main(string[] args)
{
DPCustomPeople 人 = 新しい DPCustomPeople();
people.DisplayAgeProperty();
}
}
皆さんは、DependencyProperty クラスに馴染みがないかもしれません。DependencyProperty クラスは、依存関係プロパティのいくつかの基本的な特性を提供します。
依存関係プロパティを登録する方法は、複数のオーバーロードされたメソッドを提供するDependencyPropertyの静的なRegisterメソッドを呼び出すことですが、登録が完了すると静的プロパティとなるため、次の3つの手順が必要です。
登録名(名前)「年齢」を入力
登録プロパティの型 (PropertyType) typeof (int)
依存関係属性の所有者タイプ(OwnerType)を登録 typeof(DPCustomPeople)
注: 属性名、属性タイプ、属性所有者タイプは、一度登録すると変更できません。
以下が出力結果です
2. 依存属性値の基本操作(値の取得と代入)
Age 依存関係プロパティを定義した後、プロパティに対して値の取得と割り当ての操作を実行できるようになります。DependencyProperty 自体はこれらの操作を提供しませんが、DependencyObject によって処理されます。
dependencyObject は、依存関係プロパティ システムに参加するオブジェクトを表します。
そのため、定義したクラスはDependencyObjectを継承した上でDPCustomPeopleを書き換える必要があります。
パブリック クラス DPCustomPeople:System.Windows.DependencyObject
{
}
基本的な値の割り当て操作 GetValue メソッドと SetValue メソッド
public void DPPropertyBasicOperator()
{
Console.WriteLine("年齢:" + this.GetValue(DPCustomPeople.AgeProperty));
this.SetValue(DPCustomPeople.AgeProperty, 24);
Console.WriteLine("ChangedAge:" + this.GetValue(DPCustomPeople.AgeProperty));
}
出力結果
3. 属性ラッパーは GetValue メソッドと SetValue メソッドを使用して値を操作するため、これをラップして Age 属性を定義できます。
public int 年齢
{
get { return (int)GetValue(AgeProperty) }
set { SetValue(AgeProperty, value) }
}
注: 依存プロパティのパッケージ化の命名規則では、次のプロパティを削除します。
public void DPPropertyBasicOperatorUsingProperty()
{
Console.WriteLine("年齢:" + this.Age);
this.Age=24;
Console.WriteLine("ChangedAge:" + this.Age);
}
上記のコードはより簡潔に見えますか?
4. プロパティメタデータ (PropertyMetadata)
MSDN 原文: Windows Presentation Foundation (WPF) プロパティ システムには、リフレクションや通常の共通言語ランタイム (CLR) 機能を通じてプロパティについてレポートできる内容に限定されないメタデータ レポート システムが含まれています。
属性メタデータと言えば、最初に思い浮かぶのは .net の属性です。
パブリッククラスの人
{
[デフォルト値(200),カテゴリ("レイアウト")]
public int 幅 { セット;
}
属性は、Visual Studio の機能を使用して IDE で属性をサポートできるようにするか、リフレクションに依存して値を割り当てる必要があります。
しかし、これらのテクノロジーがなければ、 new は通常のチャネルを通じて新しいインスタンスを作成し、属性のいくつかの基本的な特性 (デフォルト値など) を保証するためにこれらの属性に依存することはできません。上記のメタデータとは異なります。
依存関係プロパティのメタデータ
依存関係プロパティが定義されているクラスによって一意に指定できます 依存関係プロパティが別のクラスに追加されたときに変更できます 定義した基本クラスから依存関係プロパティを継承するすべての派生クラスによって明示的にオーバーライドできます 上記の言語は単刀直入です。しかし、それは意図を説明しますが、最初に設計者の考えを理解できるとは限りません。まずはこのコンセプトの存在を知りましょう。
5. 属性メタデータの基本動作 属性メタデータの基本動作は、依存属性に対して 3 つの機能を提供します。これは、この記事で取り上げた問題でもあります。
デフォルトのプロパティ プロパティ通知プロパティの必須コールバック まず、完全な PropertyMetadata のコンストラクターを見てみましょう。デフォルトの PropertyMetadata が依存プロパティに設定されていない場合、PropertyMetadata オブジェクトは依存プロパティに対して内部で自動的に作成されます。
public PropertyMetadata(object defaultValue, PropertyChangedCallback propertyChangedCallback, CoerceValueCallback coerceValueCallback)
依存属性は、属性メタデータの概念を借用して、属性のデフォルト値、属性通知、強制コールバック、およびその他の動作を完了します。
1.属性のデフォルト値
public static readonly dependencyProperty NameProperty =
dependencyProperty.Register("名前", typeof(string), typeof(DPCustomPeople),
新しい PropertyMetadata(string.Empty));
これを見た人は、なぜ PropertyMetadata を使用してデフォルト値を Register メソッドに登録しないのかと疑問を持つでしょう。
public static readonly dependencyProperty NameProperty =
dependencyProperty.Register("名前", typeof(string), typeof(DPCustomPeople),
文字列.空);
もちろん、この疑問はずっと私の中にあり、解決できなければどうしようもないので、今回は放置しておきます。
注: PropertyMetadata のプロパティにデフォルト値を割り当てる場合、型の正確性は検出できません。
このような定義は、vs の dp コード セグメントのデフォルト値が 0 であるため、これは注目に値します。
public static readonly dependencyProperty NameProperty =
dependencyProperty.Register("名前", typeof(string), typeof(DPCustomPeople),
新しい UIPropertyMetadata(0));
2. 属性デフォルト値復元操作
プロパティに値が割り当てられた後、次のコードに示すように、DependencyObject の ClearValue メソッドを通じてデフォルト値を復元できます。
パブリック文字列名
{
get { return (string)GetValue(NameProperty) }
set { SetValue(名前プロパティ, 値) }
}
public static readonly dependencyProperty NameProperty =
dependencyProperty.Register("名前", typeof(string), typeof(DPCustomPeople),
新しい UIPropertyMetadata(string.Empty));
public void DPPropertyClearOperator()
{
Console.WriteLine("名前:" + this.Name);
this.Name="テリー";
Console.WriteLine("ChangedName:" + this.Name);
this.ClearValue(NameProperty);
Console.WriteLine("名前:" + this.Name);
}
出力結果
注: デフォルトの割り当てとデフォルト値を区別してください
通常、デフォルトの割り当てはコンストラクターで行われますが、特に派生クラスがプロパティをオーバーライドする場合、これはデフォルト値ではありません (依存関係プロパティが登場する前はそうでした)。
パブリッククラス生徒:DPCustomPeople
{
publicStudent()
{
this.Name = "空";
}
public void TestSubDefaultDpValue()
{
Console.WriteLine("前をクリア:"+this.Name);
this.ClearValue(Student.NameProperty);
Console.WriteLine("Clear After:" + this.Name);
}
}
出力結果
3.物件変更届出
この関数は最も一般的に使用され、プロパティ値が変更されると、PropertyChangedCallback コールバックがトリガーされます。
パブリックブールIsBoy
{
get { return (bool)GetValue(IsBoyProperty) }
set { SetValue(IsBoyProperty, 値) }
}
public static readonly dependencyProperty IsBoyProperty =
dependencyProperty.Register("IsBoy", typeof(bool), typeof(Student),
new UIPropertyMetadata(false,new PropertyChangedCallback(IsBoyPropertyChangedCallback)));
public static void IsBoyPropertyChangedCallback(DependencyObject d, dependencyPropertyChangedEventArgs e)
{
Student st = d as Student;
if (セントイズボーイ)
{
Console.WriteLine("ハロー、ボーイ");
}
それ以外
{
Console.WriteLine("Hello,Girl");
}
}
public void TestPropertyChangedCallback()
{
this.IsBoy = false;
this.IsBoy = true;
}
古い値と新しい値の出力結果は、DependencyPropertyChangedEventArgs を通じて表示できます。
注記:
(1). 上記の出力結果から、依存プロパティのデフォルト値がプロパティ変更通知をトリガーしないことがわかりましたか?
(2) 属性変更通知を手動でトリガーします。
デフォルト値でプロパティの変更をトリガーしたい場合 (実際には、それが本当に必要な場合もあります)、待って手動でトリガーする必要はありません。
private void RaiseIsBoyPropertyChangedCallback()
{
IsBoyPropertyChangedCallback(this,new dependencyPropertyChangedEventArgs
(Student.IsBoyProperty、Student.IsBoyProperty.DefaultMetadata.DefaultValue、null));
}
(3). 属性変更通知がある場合は、属性のデフォルト値の型が正しいか必ず確認してください。
値型にはデフォルト値があることはわかっていますが、参照型にはデフォルト値がありません (つまり、型にデフォルト値があるかどうかは、以下に示すように、default キーワードを使用して確認できます)。
上記で定義した依存関係プロパティのデフォルト値を null に書き換えます。PropertyChangedCallback がない場合は正常に実行できますが、プロパティ変更通知がある場合は問題が発生し、プログラムは型が異なることを示す例外をスローします。マッチ。
public static readonly dependencyProperty IsBoyProperty =
dependencyProperty.Register("IsBoy", typeof(bool), typeof(Student),
new UIPropertyMetadata(null,new PropertyChangedCallback(IsBoyPropertyChangedCallback)));
参照型をもう一度見てみましょう。デフォルト値が null の場合は、すべて問題ありません。
パブリック IList LovedGirl
{
get { return (IList)GetValue(LovedGirlProperty) }
set{SetValue(LovedGirlProperty, value);
}
public static readonly dependencyProperty LovedGirlProperty =
dependencyProperty.Register("LovedGirl", typeof(IList), typeof(Student),
new UIPropertyMetadata(null, new PropertyChangedCallback(LovedGirlChangedCallback)));
public static void LovedGirlChangedCallback(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
Student st = d as Student;
foreach (IList としての e.NewValue の var 項目)
{
Console.WriteLine(項目);
}
}
public void TestReferenceDpType()
{
List<string> list = new List<string>();
list.Add("女の子 1");
list.Add("女の子 2");
this.LovedGirl = リスト;
}
4. 強制属性コールバック
まず、デフォルト値では依然としてコールバック メソッドがトリガーされません。
強制コールバックメソッドとは、属性値が変化するかどうかに関係なく、コールバックメソッドに入るという意味です。
public int スコア
{
get { return (int)GetValue(ScoreProperty) }
set { SetValue(スコアプロパティ, 値) }
}
public static readonlyDependencyProperty ScoreProperty =
dependencyProperty.Register("スコア", typeof(int), typeof(Student),
new UIPropertyMetadata(0,null,new CoerceValueCallback(ScoreCoerceValueCallback)));
パブリック静的オブジェクト ScoreCoerceValueCallback(DependencyObject d, object baseValue)
{
Console.WriteLine(baseValue);
ベース値を返します。
}
public void TestCoerceValueCallback()
{
this.スコア = 0;
this.スコア = 0;
this.スコア = 0;
}