RelayCommand перестает работать через некоторое время

Я столкнулся с некоторыми проблемами при использовании RelayCommand от GalaSoft.

У меня есть свойство NextCommand, которое работает, но только несколько раз.

После этого он перестает работать полностью.

Вы можете попробовать это с примером проекта:

http://s000.tinyupload.com/?file_id=65828891881629261404

Поведение выглядит следующим образом:

  1. NextCommand:
    1. выталкивает все элементы до активного индекса
    2. если осталось менее 50 предметов, толкает 1 новый предмет
    3. помечает новый элемент как активный
  2. BackCommand:
    1. перемещает активный индекс назад на 1 позицию

Шаги для тиражирования:

  1. ключ '+' (OemPlus) был привязан к NextCommand
  2. ключ '-' (OemMinus) был привязан к BackCommand
  3. Удерживайте клавишу "+", пока список не перестанет расти (ограничение в 50 наименований)
  4. Удерживайте клавишу "-", пока первый элемент в списке не станет активным
  5. Повторение

Количество повторений, необходимых (чтобы повторить ошибку) не согласовано.

Иногда я получаю это после 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.

Захват на рабочем столе показывает сбой кнопки при возникновении GC

Почему вы просто не используете методы из ICollectionView? там у вас есть:

  • MoveCurrentTo
  • MoveCurrentToFirst
  • MoveCurrentToLast
  • MoveCurrentToNext
  • MoveCurrentToPrevious
  • и другие приятные мелочи

что-то вроде этого

 private ICollectionView MyView {get;set;}


 this.MyView = CollectionViewSource.GetDefaultView(this._items);


 if (!this.MyView.IsCurrentBeforeFirst)
 {
     this.MyView.MoveCurrentToPrevious();
 }
Другие вопросы по тегам