Как заставить ItemsSource обновить свою привязку?
Вопрос
У меня есть представление, в котором отображается поле списка, которое привязано к GetAll():
<DockPanel>
<ListBox ItemsSource="{Binding GetAll}"
ItemTemplate="{StaticResource allCustomersDataTemplate}"
Style="{StaticResource allCustomersListBox}">
</ListBox>
</DockPanel>
GetAll() - это свойство ObservableCollection на мой взгляд, модель:
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 на данный момент.Так что здесь ценится помощь на любом уровне.
Решение
Ан ItemsControl
запрашивает его привязку один раз и после этого кэширует ссылку.
Если содержимое объекта коллекции изменено, и он реализует INotifyCollectionChanged
(как ObservableCollection
делает), он подберет любой добавленный или удаленный объект.
Теперь, если вы хотите, чтобы привязка предоставила новый объект коллекции в ListBox
, вы можете реализовать свою view-модель INotifyPropertyChanged
и поднять PropertyChanged
, проходящий в GetAll
в качестве имени свойства.Это приведет к предупреждению привязки о том, что значение свойства изменилось (появилось новое ObservableCollection
готов к приему), который он будет поставлять в ListBox
, который повторно сгенерирует свои элементы.
Таким образом, до тех пор, пока вы вносите изменения в свое приложение, работая над ObservableCollection
возвращенный GetAll
, вы можете добавлять и удалять, и список останется синхронизированным.Если вы хотите внести внешние изменения (возможно, у вас где-то есть кнопка обновления или естественная точка, где имеет смысл перезагрузить весь файл), вы можете попросить свою view-model поднять PropertyChanged
событие, которое автоматически вызовет средство получения свойства, которое вызовет статический метод, который вернет свежую новую коллекцию.
Замечание придирчивого критика:почему вы даете имена методов свойствам?
Другие советы
Строка ниже работает так же, как при удалении для добавления объекта в коллекцию:
CollectionViewSource.GetDefaultView(CustomObservableCollection).Refresh();
Сохраните ссылку на свой ObservableCollection
и время последнего изменения XML-файла на момент его загрузки.Всякий раз, когда окно попадает в фокус, проверяйте временную метку в файле на диске.Если оно было изменено, очистите и повторно заполните ObservableCollection
.Графический интерфейс автоматически отслеживает события изменения из ObservableCollection
и будет повторно заполняться автоматически при изменении содержимого коллекции.