RelayCommand перестает работать через некоторое время
Я столкнулся с некоторыми проблемами при использовании RelayCommand от GalaSoft.
У меня есть свойство NextCommand, которое работает, но только несколько раз.
После этого он перестает работать полностью.
Вы можете попробовать это с примером проекта:
http://s000.tinyupload.com/?file_id=65828891881629261404
Поведение выглядит следующим образом:
- NextCommand:
- выталкивает все элементы до активного индекса
- если осталось менее 50 предметов, толкает 1 новый предмет
- помечает новый элемент как активный
- BackCommand:
- перемещает активный индекс назад на 1 позицию
Шаги для тиражирования:
- ключ '+' (OemPlus) был привязан к NextCommand
- ключ '-' (OemMinus) был привязан к BackCommand
- Удерживайте клавишу "+", пока список не перестанет расти (ограничение в 50 наименований)
- Удерживайте клавишу "-", пока первый элемент в списке не станет активным
- Повторение
Количество повторений, необходимых (чтобы повторить ошибку) не согласовано.
Иногда я получаю это после 4 повторений; в другое время до 9.
// Items Collection
public class ItemCollection : ViewModelBase
{
// List of Items
private readonly ObservableCollection<Item> _items = new ObservableCollection<Item>();
public ObservableCollection<Item> Items
{
get { return _items; }
}
// Constructor
public ItemCollection()
{
BackCommand = new RelayCommand(
() =>
{
// Go to previous page
var index = Items.IndexOf(ActiveItem);
if (index > 0)
{
ActiveItem = Items[index - 1];
}
},
() => ActiveItem != null && Items.IndexOf(ActiveItem) > 0);
}
// Back command
public RelayCommand BackCommand { get; set; }
// Next command
public RelayCommand NextCommand { get; set; }
// The currently-active item
private Item _activeItem;
public Item ActiveItem
{
get { return _activeItem; }
set
{
Set(() => ActiveItem, ref _activeItem, value);
}
}
}
// Item
public class Item : ViewModelBase
{
public string Title { get; set; }
}
Когда я вошел в код RelayCommand, флаг isAlive выполняемого действия был ложным. Но я не могу понять, как это могло произойти.
2 ответа
Два слова: сборщик мусора
В вашем примере проекта - который вы должны опубликовать соответствующие части, чтобы сделать ваш вопрос перспективным - вы устанавливаете DataContext
в вашем окне вот так:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var logic = new LogicObject();
DataContext = logic.Collection;
}
}
Потому что ничто иное не сохраняет ссылку на LogicObject
созданный здесь, он будет собран при следующей возможности.
Команда перестает работать, потому что в LogicObject
Вы устанавливаете NextCommand
из ItemCollection
использовать частных членов, которые скоро будут собраны LogicObject
:
public class LogicObject
{
public LogicObject()
{
Collection = new ItemCollection();
Collection.NextCommand = new RelayCommand(AddItem, CanAddItem);
AddItem();
}
private bool CanAddItem()
{
// snip...
}
private void AddItem()
{
// snip...
}
}
однажды LogicObject
Собран, команда больше не может работать, потому что у нее больше нет ссылок на допустимые методы (AddItem
а также CanAddItem
). Вот почему isAlive
поле на обоих RelayCommand
Слабые ссылки на методы ложны.
Вы можете исправить это, просто повесив на LogicObject
или перемещая AddItem
а также CanAddItem
методы в коллекцию.
Чтобы понять дух GIF-ов по этому вопросу, вот тот, который показывает, что кнопка перестает работать, как только происходит коллекция Gen 0.
Почему вы просто не используете методы из ICollectionView? там у вас есть:
- MoveCurrentTo
- MoveCurrentToFirst
- MoveCurrentToLast
- MoveCurrentToNext
- MoveCurrentToPrevious
- и другие приятные мелочи
что-то вроде этого
private ICollectionView MyView {get;set;}
this.MyView = CollectionViewSource.GetDefaultView(this._items);
if (!this.MyView.IsCurrentBeforeFirst)
{
this.MyView.MoveCurrentToPrevious();
}