4

私はこのようなエンティティを持っています:

public class Person
{
    public string Name { get; set; }

    public Person()
    {
        Name = "Godspeed";
    }
}

次に、XAMLに3つのテキストボックスとボタンがあります。

<Window x:Class="WpfApplication19.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication19"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Person />
    </Window.DataContext>
    <StackPanel>
        <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Text="{Binding Name,UpdateSourceTrigger=PropertyChanged}" />
        <Button Click="Button_Click">Click</Button>
    </StackPanel>
</Window>

奇妙なことに、エンティティ「Person」はINotifyPropertyChangedを実装していませんが、1つのテキストボックスが変更されると、ソース(Personオブジェクト)が変更されますが、プロパティ変更イベントは発生せず、残りの2つのテキストボックスが発生します。自動的に変更されました。

ボタンがクリックされると、次のようなコードでソースを直接更新します。

((Person)DataContext).Name = "Godspeed";

更新されません。つまり、PersonクラスがINotifyPropertyChangedを実装している場合、この動作は正常ですが、クラスはインターフェイスを実装していませんが、インターフェイスも更新していると思います。手がかりがあれば理由を教えてください。ありがとう。

4

3 に答える 3

4

理由はPropertyDescriptorです。次のスレッドを参照してください。同じ質問があります。データバインディングシステムは、プロパティが変更されたことをどのように認識しますか?

ここに2つの答えがあります

魔法はバインディングシステムのPropertyDescriptorの使用にあると思います(SetValueはおそらくValueChangedを発生させます-PropertyDescriptorは共有される可能性がありますが、イベントはオブジェクトごとに発生します)。


私はマイクロソフトにいませんが、確認できます。PropertyDescriptorを使用して値を更新すると、関連する変更通知が自動的に伝達されます。

編集これは、 DataContextオブジェクト
に名前を付けることで確認できますPerson

<Window.DataContext>
    <local:Person x:Name="person"/>
</Window.DataContext>

次のコードをMainWindowctorに追加します

public MainWindow()
{
    InitializeComponent();

    PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(person);
    PropertyDescriptor nameProperty = properties[0];
    nameProperty.AddValueChanged(person, OnPropertyChanged);
}
void OnPropertyChanged(object sender, EventArgs e)
{
    MessageBox.Show("Name Changed");
}

3つのTextBoxのいずれかの値を変更すると、イベントハンドラーOnPropertyChangedになります。

于 2011-08-12T08:44:06.993 に答える
1

さて、あなたが言ったように、あなたはただ実装する必要がありますINotifyPropertyChanged

このイベントは、コードからPropertyChangedプロパティを設定し、この変更をUIに反映する必要がある場合に使用されます(UIはイベントをキャッチし、UIのおかげで更新されます)。反対側(UIから変更)は何も必要ありません、これがあなたがこの振る舞いをする理由ですPropertyChangedUpdateSourceTriggerPropertyChanged

そのようにしてみてください:

    public class Person : INotifyPropertyChanged
    {
            #region INotifyPropertyChanged Members

            /// <summary>
            /// Property Changed Event
            /// </summary>
            public event PropertyChangedEventHandler PropertyChanged;

            /// <summary>
            /// Property Changed
            /// </summary>
            /// <param name="propertyName"></param>
            protected void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            #endregion

    private string name;

    public string Name
    {
      get { return name; }
      set 
      {
        name = value;
        OnPropertyChanged("Name");
      }
    }

}

このコードを使用して、名前を設定すると、PropertyChangedイベントが発生するため、それに応じてUIが更新されます:)

于 2011-08-12T08:23:41.467 に答える
1

updatesourcetrigger = propertychangedだけでなく、デフォルト(フォーカスが失われた)値でも機能します。@Meleakが言ったことに加えて、私はそれが良い振る舞いであることを指摘したいと思います。uiによって行われた変更は、すべてのバインディングターゲットに伝播されます。バインディングエンジンは、この変更をすべてのコントロールに一度に伝達したいと考えています。コードを介して変更を加え、INotifyPropertyChangedを実装しない場合、コードから行われた変更はまったく反映されません。繰り返しますが、同じバインディングソースを持つすべてのコントロールに対して。すべてのコントロールは、そのような実装と同期して機能します。

于 2011-08-12T08:48:45.930 に答える