У меня есть 2 представления списка... и добавлять/удалять кнопки между ними.
В событии изменения коллекции коллекции списка-представления в модели представления могу ли я отменить изменения для определенного условия?
У меня есть 2 представления списка... и добавлять/удалять кнопки между ними.
В событии изменения коллекции коллекции списка-представления в модели представления могу ли я отменить изменения для определенного условия?
Вы можете обработать событие CollectionChanged
ObservableCollection
для резервного копирования (через или что-то еще) старые значения (см. NotifyCollectionChangedEventArgs.OldItems
a> свойство) и возвращать их при необходимости, например, когда пользователь нажимает «Отменить» и т. д.
Обновление В отношении комментариев ниже:
Если вы хотите откатить коллекцию из обработчика событий CollectionChanged
, создайте флаг, в котором вы избегаете обработчика рекурсивного вызова (не тестировалось с многопоточным приложением), вот простой пример, вы можете легко настроить его на подходит для вашего V/VM.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var x = new ObservableCollection<string>();
x.CollectionChanged +=
new NotifyCollectionChangedEventHandler(x_CollectionChanged);
x.Add("asdf");
x.Remove("asdf");
}
bool rollingBack = false;
void x_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (rollingBack) return;
if (e.Action == NotifyCollectionChangedAction.Remove)
{
if (e.OldItems.Contains("asdf"))
{
var oc = (ObservableCollection<string>)sender;
rollingBack = true;
oc.Add("asdf");
rollingBack = false;
}
}
}
ReadOnlyList
.
- person Shimmy Weitzhandler; 25.12.2010
sender
, переданный обработчику CollectionChanged
, является самим ObservableCollection
.
- person Shimmy Weitzhandler; 25.12.2010
var x = (ObservableCollection<object>)sender;
(ваш ObservableCollection
и его тип), затем foreach (var item in e.OldItems) x.Add(item);
- person Shimmy Weitzhandler; 25.12.2010
CollectionChanged
, этот обработчик следует использовать для извлечения и резервного копирования измененных данных, поэтому, когда пользователь нажимает «Отменить», вы имейте это прямо там. Если вы хотите сделать откат из обработчика, просто создайте флаг, который обработчик должен экранировать, когда он один, просмотрите мой обновленный ответ.
- person Shimmy Weitzhandler; 25.12.2010
Учитывая, что вы получаете отправителя события как объект (т.е. первый параметр события) и список объектов, которые были изменены, да, вы можете это сделать. Хотя я бы этого не советовал. Если вы столкнулись с таким условием, предоставьте метод ViewModel, который предоставляется с EventArgs
, и позвольте ему сделать свою работу. Представление не место для логики.
Еще лучше: проверьте условие в самой ViewModel (т.е. в командах, отвечающих за добавление/удаление)! Модель представления отвечает за состояние информации, поэтому держите там свою логику. Представление предназначено только для отображения данных.
Ответ Шимми не сработал для меня в приложении Магазина Windows, вы все равно столкнетесь с проблемами повторного входа и получите InvalidOperationException
сообщение «Невозможно изменить ObservableCollection во время события CollectionChanged».
Мне пришлось использовать диспетчер пользовательского интерфейса и отключить/включить обработчик событий, чтобы избежать этих проблем.
Имейте в виду: это взлом, и разработчики фреймворка сделали все возможное, чтобы помешать вам это сделать. Так что, если вы хотите проигнорировать их предупреждение, будьте осторожны, чтобы не выстрелить себе в ногу.
Items.CollectionChanged += ItemsChanged;
private async void ItemsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if(condition)
{
//rollback
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(
CoreDispatcherPriority.Normal, () => {
//disable/enable event handler
Items.CollectionChanged -= ItemsChanged;
Items.Remove(e.NewItems[0]);
Items.CollectionChanged += ItemsChanged;
})).AsTask();
}
}
Это позволит избежать исключения, избежать рекурсивного вызова обработчика и правильно обновить пользовательский интерфейс.