Force reevalution of guard methods in Caliburn Micro
I have an ItemsControl which has a move up, move down, and delete button in each item (via template). My ItemsControl source binds to a collection of Items which are model DataContracts/POCOs (not VMs).
I've attached a Caliburn message handler in my main page's view model.
<Button cal:Message.Attach="MoveUp($dataContext)" >Up</Button>
<Button cal:Message.Attach="MoveDown($dataContext)" >Down</Button>
I believe I had to be explicit with cal:Message.Attach and not rely on convention because I was within my ItemTemplate.
View Model:
ObservableCollection<Item> MyCollection = new ObservableCollection<Item>();
//Item class is simple -- only has a string Name property
开发者_如何转开发
public bool CanMoveUp(Item item)
{
var index = MyCollection.IndexOf(item);
return index > 0;
}
public void MoveUp(Item item)
{
var index = MyCollection.IndexOf(item);
if (index > 0)
{
MyCollection.Remove(item);
MyCollection.Insert(index - 1, item);
}
}
public bool CanMoveDown(Item item)
{
var index = MyCollection.IndexOf(item);
return index > -1 && index < class1.Count - 1;
}
public void MoveDown(Item item)
{
var index = MyCollection.IndexOf(item);
if (index > -1 && index < class1.Count - 1)
{
MyCollection.Remove(item);
MyCollection.Insert(index + 1, item);
}
}
The first item's up button is initially disabled. When I move down the first item, the 2nd item becomes the first item, but its up button is not automatically disabled. How do I force reevaluation of the CanMoveUp guard method?
In your MoveUp
and MoveDown
methods, you can notify the UI that the bindings for CanMoveUp/Down
have been invalidated using NotifyOfPropertyChanged(() => this.CanMoveUp);
(or this.CanMoveDown as appropriate).
This is assuming your ViewModel derives from Screen
, Conductor
, or PropertyChangedBase
which it should.
Update
What you'll want to do is refactor the code to bind the SelectedItem
of the ListBox
to a property on your view model of type Item
. In fact, Caliburn.Micro will do this for you, if your ListBox
has an x:Name="Items"
for example, it will look for a property called SelectedItem
(there are other conventions too that it searches for). Then, your CanMoveUp/Down
methods can be properties instead that check the SelectedItem
property, and therefore you can use NotifyOfPropertyChanged()
to invalidate those bindings.
I ended up promoting my Item class to a full fledged ViewModel. I used IoC / MEF so that the Item class could find its container, so it could tell if it was the first or last item in the container. If I need to force reevaluation, I created a method that reevaluates guard properties:
public void ReevaluateButtons()
{
NotifyOfPropertyChange(() => CanMoveDown);
NotifyOfPropertyChange(() => CanMoveUp);
}
Still don't know if there is yet a way to force reevaluation of guard methods
NotifyOfPropertyChange(() => CanMoveDown(item));
精彩评论