Обновить привязку при изменении вложенного объекта - PullRequest
3 голосов
/ 12 сентября 2011

У меня есть несколько XAML следующим образом (простая метка и кнопка):

<Window x:Class="WpfApplication2.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Test="clr-namespace:WpfApplication2">
<StackPanel DataContext="{Binding Path=TestPerson}">
    <Label Content="{Binding Path=Name}"></Label>
    <Button Content="Button" Click="button1_Click" />
</StackPanel>
</Window>

в приведенном ниже коде у меня есть:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    private Person _person = new Person();
    public Person TestPerson { get { return _person; } }

    public MainWindow()
    {           
        DataContext = this;
        InitializeComponent();
    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        _person.Name = "Bill";
        //_person = new Person() { Name = "Bill" };
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs("TestPerson"));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

и класс Person:

public class Person
{
    string _name = "Bob";

    public string Name
    {
        get { return _name; }
        set { _name = value; }
    }
}

Фактически, запуск события Propertychanged не приводит к изменению содержимого метки на Bill.

Я обнаружил, что могу преодолеть это либо:

  • Назначение нового объекта _person (как в закомментированной строке)
  • Удаление DataContext из StackPanel и привязка метки к Path = TestPerson.Name

Я не понимаю, почему я должен назначить NEW объект _person для обновления Label или использовать полный путь в привязке.

Есть ли способ обновить Label без указав полный путь (полагаясь на DataContext), и без назначения нового объекта _person?

Ответы [ 2 ]

4 голосов
/ 12 сентября 2011

Вы повышаете PropertyChanged для Person экземпляра TestPerson.Однако TestPerson не изменилось, изменилось свойство Name TestPerson, и это свойство, к которому привязан Label.

Редактировать: Чтобы ответить, почему ваши первые две версии работают

Назначение нового объекта _person (как в закомментированной строке)

Здесь вы фактически изменяете значение TestPerson и поскольку DataContext наследуется детьми, Label также получает новый DataContext, поэтому обновляется Binding.

Удаление DataContext из StackPanelи пусть Label привязывается к Path = TestPerson.Name

Это то, чего я никогда не видел.Одна и та же привязка подписывается на PropertyChanged для TestPerson и Name в Person, поэтому повышение PropertyChanged для любого из этих свойств будет работать.

Если вы хотите преодолеть это без реализации INotifyPropertyChanged для Person вы можете изменить значение UpdateSourceTrigger на Explicit

<Label Name="label"
       Content="{Binding Path=Name, UpdateSourceTrigger=Explicit}"/>

и обновить Binding вручную каждый раз, когда Name изменит

private void button1_Click(object sender, RoutedEventArgs e)
{
    _person.Name = "Bill";
    BindingExpression be = label.GetBindingExpression(Label.ContentProperty);
    be.UpdateTarget();
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs("TestPerson"));
    }
}

В противном случае, простовнедрите INotifyPropertyChanged для Person, и это будет работать

public class Person : INotifyPropertyChanged
{ 
    string _name = "Bob"; 

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

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
} 
0 голосов
/ 12 сентября 2011

Вам нужно немного изменить свой XAML ...

В своем коде вместо того, чтобы устанавливать DataContext как this, установите его в XAML через Binding ...

     <StackPanel DataContext="{Binding RelativeSource={RelativeSource
                                            AncestorType= {x:Type Window},
                                                Mode=FindAncestor}, 
                                       Path=TestPerson}">
          <Label Content="{Binding Path=Name}"></Label>
          <Button Content="Button" Click="button1_Click" />
     </StackPanel>

Удалите

     DataContext = this;

из своего кода позади.

Дайте мне знать, если это поможет.

...