WPF Привязка данных: изменение элементов в связанной коллекции не обновляет источник привязки? - PullRequest
0 голосов
/ 30 ноября 2010

У меня есть два класса:

public class Person
{
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
    public ObservableCollection<AccountDetail> Details
    {
        get { return details; }
        set { details = value; }
    }
    public ObservableCollection<AccountDetail> Phones
    {
        get
        {
            ObservableCollection<AccountDetail> phones;
            phones = new ObservableCollection<AccountDetail>();
            foreach (AccountDetail detail in Details)
            {
                if (detail.Type == DetailType.Phone)
                {
                    phones.Add(detail);
                }
            }
            return phones;
        }
        set
        {
            ObservableCollection<AccountDetail> phones;
            phones = value;
            foreach (AccountDetail detail in Details)
            {
                if (detail.Type == DetailType.Phone)
                {
                    Details.Remove(detail);
                }
            }
            foreach (AccountDetail detail in phones)
            {
                if (!string.IsNullOrEmpty(detail.Value))
                {
                    Details.Add(detail); 
                }
            }
        }
    }

    private string firstName;
    private string lastName;
    private ObservableCollection<AccountDetail> details;
}

и

public class AccountDetail
{
    public DetailType Type
    {
        get { return type; }
        set { type = value; }
    }
    public string Value
    {
        get { return this.value; }
        set { this.value = value; }
    }

    private DetailType type;
    private string value;
}

В моем файле XAML есть ListBox с именем PhonesListBox, который является данными, привязанными к списку телефонов (свойствообъекта Person):

<Window.Resources>

    <!-- Window controller -->
    <contollers:PersonWindowController 
        x:Key="WindowController" />

</Window.Resources>

...

<ListBox 
    Name="PhonesListBox" 
    Margin="0,25,0,0" 
    HorizontalAlignment="Stretch" 
    VerticalAlignment="Top" 
    ItemsSource="{Binding Path=SelectedPerson.Phones, 
                  Source={StaticResource ResourceKey=WindowController}}"
    HorizontalContentAlignment="Stretch" />

...

В коде класса есть обработчик для кнопки, которая добавляет новый элемент к этому PhonesListBox:

private void AddPhoneButton_Click(object sender, RoutedEventArgs e)
{
    ObservableCollection<AccountDetail> phones;

    phones = (ObservableCollection<AccountDetail>)PhonesListBox.ItemsSource;
    phones.Add(new AccountDetail(DetailType.Phone));
}

Проблема заключается в том, чтовновь добавленный элемент списка не добавляется в наблюдаемую коллекцию сведений о человеке, т. е. свойство Phones не обновляется (set никогда не вызывается).Зачем?Где я делаю ошибку?

Спасибо за помощь.

ОБНОВЛЕНИЕ: я изменил метод AddPhoneButton_Click на:

private void AddPhoneButton_Click(object sender, RoutedEventArgs e)
{
    PersonWindowController windowController;
    ObservableCollection<AccountDetail> details;

    windowController = (PersonWindowController)this.FindResource("WindowController");
    details = windowController.SelectedPerson.Details;
    details.Add(new AccountDetail(DetailType.Phone));
}

Это обновляет соответствующую коллекцию, которая details не Phones (так как телефоны просто вид или получатель подмножества деталей).Кроме того, я понял, что мне даже не нужен установщик телефонов.Проблема, с которой я сейчас сталкиваюсь, заключается в том, что мой пользовательский интерфейс не обновляется с изменениями, внесенными в коллекцию данных (и впоследствии в телефоны).Я не знаю, как и где позвонить, чтобы поменять недвижимость, так как не меняются ни детали, ни телефоны;члены их коллекции.Помогите.Пожалуйста.

Ответы [ 4 ]

2 голосов
/ 30 ноября 2010

Почему вы создаете новый ObservableCollection<AccountDetail> каждый раз, когда извлекается свойство Phones?Как правило, класс Person будет иметь поле члена типа ObservableCollection<AccountDetail>, которое будет просто возвращено в методе получения свойства Phones вместо создания нового каждый раз.Вы можете заполнить эту коллекцию, например, когда создается экземпляр Person.

Я не знаю, решит ли это вашу проблему или нет, но похоже, что это должно помочь.

1 голос
/ 30 ноября 2010

звучит так, как будто у вас есть ObservableCollection<AccountDetail> с не только телефонами, так что, похоже, вам действительно нужен CollectionViewSource с добавленным Filter:

public class Person
{
    public ObservableCollection<AccountDetail> Details { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}


<Window.Resources>
    <CollectionViewSource x:Key="phonesSource" 
        Source="{StaticResource ResourceKey=WindowController}"
            Path="SelectedPerson.Details"  />
</Window.Resources>
<Grid>
    <ListBox 
        Name="PhonesListBox" 
        Margin="0,25,0,0" 
        HorizontalAlignment="Stretch" 
        VerticalAlignment="Top" 
        ItemsSource="{Binding Source={StaticResource phonesSource}}"
        HorizontalContentAlignment="Stretch" />
</Grid>

public MainWindow()
{
    InitializeComponent();
    CollectionViewSource source = 
        (CollectionViewSource)FindResource("phonesSource");
    source.Filter += (o, e) =>
            {
                if (((AccountDetail) e.Item).Type == DetailType.Phone)
                    e.Accepted = true;
            };
}
0 голосов
/ 30 ноября 2010

Попробуйте что-то вроде:

public class Person : INotifyPropertyChanged
{
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
    public ObservableCollection<AccountDetail> Details
    {
        get { return details; }
        set { details = value; }
    }

    public void AddDetail(AccountDetail detail) {
        details.Add(detail);
        OnPropertyChanged("Phones");
    }

    public IEnumerable<AccountDetail> Phones
    {
        get
        {
            return details.Where(d => d.Type == DetailType.Phone);
        }
    }

    private string firstName;
    private string lastName;
    private ObservableCollection<AccountDetail> details;


    /// <summary>
    /// Called when a property changes.
    /// </summary>
    /// <param name="propertyName">Name of the property.</param>
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #region INotifyPropertyChanged Members

    /// <summary>
    /// Occurs when a property value changes.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion

}

Вы можете вызвать метод AddDetail из обработчика события кнопки:

private void AddPhoneButton_Click(object sender, RoutedEventArgs e)
{
    PersonWindowController windowController;
    ObservableCollection<AccountDetail> details;

    windowController = (PersonWindowController)this.FindResource("WindowController");
    windowController.SelectedPerson.AddDetail(new AccountDetail(DetailType.Phone));
}

Повышение события OnPropertyChanged для свойства Phones просто вызовет WPFинфраструктура привязки для запроса правильности и запрос Linq для повторной оценки после добавления сведений о телефоне в список сведений.

0 голосов
/ 30 ноября 2010

Изменение класса Person на что-то вроде следующего должно работать:

public class Person
{
    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; }
    }
    public string LastName
    {
        get { return lastName; }
        set { lastName = value; }
    }
    public ObservableCollection<AccountDetail> Details
    {
        get { return details; }
        set { details = value; }
    }

    public ObservableCollection<AccountDetail> Phones
    {
        get
        {
            if (phones == null)
            {
                phones = new ObservableCollection<AccountDetail>();
            }

            phones.Clear();
            foreach (AccountDetail detail in Details)
            {
                if (detail.Type == DetailType.Phone)
                {
                    phones.Add(detail);
                }
            }
            return phones;
        }
        set
        {
            phones.Clear();

            foreach (var item in value)
            {
                phones.Add(item);
            }

            foreach (AccountDetail detail in Details)
            {
                if (detail.Type == DetailType.Phone)
                {
                    Details.Remove(detail);
                }
            }

            foreach (AccountDetail detail in phones)
            {
                if (!string.IsNullOrEmpty(detail.Value))
                {
                    Details.Add(detail);
                }
            }
        }
    }

    private string firstName;
    private string lastName;
    private ObservableCollection<AccountDetail> details;
    public ObservableCollection<AccountDetail> phones;
}

Код не протестирован, и для его работы может потребоваться несколько изменений.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...