Как заставить ItemsSource обновить свою привязку?

У меня есть представление, которое показывает список, привязанный к GetAll():

<DockPanel>
    <ListBox ItemsSource="{Binding GetAll}"
             ItemTemplate="{StaticResource allCustomersDataTemplate}"
             Style="{StaticResource allCustomersListBox}">
    </ListBox>
</DockPanel>

GetAll() — это свойство ObservableCollection в моей ViewModel:

public ObservableCollection<Customer> GetAll
{
    get
    {
        return Customer.GetAll();
    }
}

который, в свою очередь, вызывает метод модели GetAll(), который считывает файл XML для заполнения ObservableCollection.:

public static ObservableCollection<Customer> GetAll()
{
    ObservableCollection<Customer> customers = new ObservableCollection<Customer>();

    XDocument xmlDoc = XDocument.Load(Customer.GetXmlFilePathAndFileName());
    var customerObjects = from customer in xmlDoc.Descendants("customer")
                          select new Customer
                          {
                              Id = (int)customer.Element("id"),
                              FirstName = customer.Element("firstName").Value,
                              LastName = customer.Element("lastName").Value,
                              Age = (int)customer.Element("age")
                          };
    foreach (var customerObject in customerObjects)
    {
        Customer customer = new Customer();

        customer.Id = customerObject.Id;
        customer.FirstName = customerObject.FirstName;
        customer.LastName = customerObject.LastName;
        customer.Age = customerObject.Age;

        customers.Add(customer);
    }

    return customers;
}

Все это работает нормально, ЗА ИСКЛЮЧЕНИЕМ случаев, когда пользователь переходит к другому представлению, редактирует XML-файл и возвращается к этому представлению, где по-прежнему отображаются старые данные.

Как я могу указать этому представлению "обновить свои привязки", чтобы отображать фактические данные.

Такое ощущение, что я говорю о WPF здесь со слишком большим количеством метафоры HTML/HTTP, я чувствую, что есть более естественный способ заставить ObservableCollection обновлять себя, отсюда и его название, но это единственный способ, которым я могу заставить пользователя иметь возможность редактировать данные в приложении WPF в данный момент. Так что здесь приветствуется помощь на любом уровне.


person Edward Tanguay    schedule 30.04.2009    source источник


Ответы (3)


ItemsControl запрашивает свою привязку один раз и после этого кэширует ссылку.

Если содержимое объекта коллекции изменено и он реализует INotifyCollectionChanged (как это делает ObservableCollection), он подберет любой добавленный или удаленный объект.

Теперь, если вы хотите, чтобы привязка предоставила новый объект коллекции для ListBox, вы можете сделать так, чтобы ваша модель представления реализовала INotifyPropertyChanged и подняла PropertyChanged, передав GetAll в качестве имени свойства. Это приведет к предупреждению привязки об изменении значения свойства (есть новый ObservableCollection, готовый к выбору), который он передаст ListBox, который повторно сгенерирует свои элементы.

Таким образом, пока вы вносите изменения из своего приложения, работая с ObservableCollection, возвращенным GetAll, вы можете добавлять и удалять, и список будет оставаться синхронизированным. Если вы хотите получить внешние изменения (где-то у вас может быть кнопка обновления или естественная точка, в которой имеет смысл перезагрузить весь файл), вы можете сделать так, чтобы ваша модель представления вызывала событие PropertyChanged, которое автоматически вызовет свойство getter, который вызовет статический метод, который вернет свежую новую коллекцию.

Примечание Nitpicker: почему вы даете имена методов свойствам?

person Denis Troller    schedule 30.04.2009
comment
Я изменил GetAll() на GetAll, спасибо. Проблема в том, что у меня есть два представления, каждое из которых получает отдельный GetAll ObservableCollection из соответствующих ViewModels, и когда одно ObservableCollection изменяется, другое не меняется. Нужно ли мне хранить их где-то глобально? - person Edward Tanguay; 30.04.2009
comment
Если оба вида должны синхронизироваться при редактировании, то да, нужно как-то расшарить один и тот же объект. В вашем случае может быть система доступа к данным, которая загружает и кэширует коллекцию, и каждая ViewModel будет запрашивать текущую коллекцию. Таким образом, они оба знают об изменениях друг друга. Теперь, если вам нужно перезагрузить коллекцию из файла, у вас будет способ предупредить каждую модель представления об изменении объекта коллекции, чтобы они могли вызвать свое событие PropertyChanged после получения новой ссылки. - person Denis Troller; 30.04.2009
comment
Итак, на данный момент мое решение обновлять DataSource каждый раз, когда загружается пользовательский элемент управления (представление), отлично работает, спасибо! - person Edward Tanguay; 30.04.2009
comment
Конечно, было бы неплохо узнать, где это кешируется. (У меня есть проблема, когда кеш обновляется, когда он не должен.) Хотите обновить эту информацию? - person Vaccano; 21.11.2012
comment
Обязательно добавьте двустороннюю привязку в список - person Aravind Mungara; 22.09.2016

Строка ниже работает так же, как когда мы удаляем, чтобы добавить объект в коллекцию:

CollectionViewSource.GetDefaultView(CustomObservableCollection).Refresh();
person user2267032    schedule 10.04.2013

Сохраните ссылку на ObservableCollection и время последнего изменения файла XML на момент его загрузки. Всякий раз, когда окно получает фокус, проверяйте отметку времени в файле на диске. Если он изменился, очистите и заново заполните файл ObservableCollection. Графический интерфейс автоматически прослушивает события изменения из ObservableCollection и автоматически повторно заполняется при изменении содержимого коллекции.

person Joe White    schedule 30.04.2009