I am facing some problems using GalaSoft's RelayCommand.
I have a NextCommand property that works, but only several times.
Afterwards, it stops working completely.
You can try this out with the sample project:
http://s000.tinyupload.com/?file_id=65828891881629261404
The behaviour is as follows:
Steps to replicate:
The number of repetitions needed (to replicate the bug) is inconsistent.
Sometimes I get it after 4 repetitions; other times up till 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; }
}
When I stepped into the RelayCommand's code, the execute action's isAlive flag was false. But I can't seem to figure out how that might happen.
Two words: Garbage Collector
In your example project--which you should post the relevant bits of to make your question future-proof--you set the DataContext
on your window like this:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var logic = new LogicObject();
DataContext = logic.Collection;
}
}
Because nothing else retains a reference to the LogicObject
created here, it will be collected at the next opportunity.
The command stops functioning because in LogicObject
, you set the NextCommand
of the ItemCollection
to use private members of the soon-to-be-collected LogicObject
:
public class LogicObject
{
public LogicObject()
{
Collection = new ItemCollection();
Collection.NextCommand = new RelayCommand(AddItem, CanAddItem);
AddItem();
}
private bool CanAddItem()
{
// snip...
}
private void AddItem()
{
// snip...
}
}
Once LogicObject
is collected, the command can no longer work because it no longer has references to valid methods (AddItem
and CanAddItem
). This is why the isAlive
field on both of the RelayCommand
's weak references to the methods is false.
You can fix this by just hanging on to the LogicObject
, or by moving the AddItem
and CanAddItem
methods into the collection.
To get in the spirit of GIFs for this question, here's one that shows the button stop working as soon as a Gen 0 collection occurs.
why dont you simply use the methods from ICollectionView? there you have:
something like this
private ICollectionView MyView {get;set;}
this.MyView = CollectionViewSource.GetDefaultView(this._items);
if (!this.MyView.IsCurrentBeforeFirst)
{
this.MyView.MoveCurrentToPrevious();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With