Auto cancel changes in DataForm when selection is changed
I wonder how you do such thing. Assume, we have MVVM CRUD app which modifies a tree (menu structure, for example). We have a view model with the menu items and two views: the first with a TreeV开发者_开发知识库iew
and the second with a DataForm
. Main problems are:
DataForm
can not handle hierarchical data.- Depending on the menu item selected
in the
TreeView
theDataForm
should display different set of fields (for example for menu items with children or without).
I've ended up with the following. View model has 3 fields:
Items
— the collection ofMenuItem
objects which have their ownChildren
collection for building hierarchical data source.SelectedItem
— currently selectedMenuItem
in theTreeView
.EditedItem
—EditViewModel
object which basically has two descendants:MenuItemEditViewModel
andLeafMenuItemEditViewModel
. This property is set automatically whenSelectedItem
is changed. Its actual type is inferred from theSelectedItem.Children
emptiness.
TreeView
is bound to Items
and SelectedItem
. DataForm
is not required to maintain currency in this case (instead current item is set by the TreeView
) nor it is responsible for creating and deleting items. That's why I decided to bind only its CurrentItem
to view model's EditedItem
(ItemsSource
is unbound). Its AutoCommit
is set to False
(when it is True
and ItemsSource
is unbound all current item changes get copied to newly selected item when you select different item in the TreeView
, which is not so nice). DataForm
fields are autogenerated.
Obviously, that now if we select an item in the TreeView
, then make some changes in the DataForm
and try to select different item in the TreeView
we'll get well-known
Cannot change currency when an item has validation errors or it is being edited and AutoCommit is false. Set ItemsSource to a ICollectionView to manage currency instead
In this case I want DataForm
to discard all changes implicitly. There is a workaround to call DataForm.CancelEdit()
before TreeView
selected item is changed (usually an event like PreviewSelectionChanged
or BeforeSelectionChanged
). But it is not the MVVM way since the TreeView
and the DataForm
are defined in completely different views (read: is not acceptable).
Is there something like AutoCancel which forces DataForm
to cancel changes when its CurrentItem
is changed? Maybe someone from dev team can answer? Or how would you deal with such problem?
I was surprised to find the Silverlight is severly lacking in this functionality, considering all the business oriented RIA functionality. AutoCommit is not acceptable to me because I want the user to explicitly acknowledge pending changes, rather than just commit something to the database that they may not want.
You can reliably track the edit mode of the DataForm using a private member variable and trapping the BeginningEdit and EditEnded events of the DataForm (naming inconsistency! Why one is called xxxEdit and the others are Editxxx is beyond me. Should it not be EditBeginning and EditEnded??). Inside the event handler for BeginningEdit, set the flag to true and set it to false in EditEnded.
In your SelectionChanged event, you can then check the flag. If it is true, you can call the CancelEdit on the DataForm.
private bool _editing = false;
public MainPage() {
DataForm1.BeinningEdit +=
new EventHandler<CancelEventArgs>(DataForm1_BeginningEdit);
DataForm1.EditEnded +=
new EventHandler<DataFormEditEndedEventArgs>(DataForm1_EditEnded);
}
protected void DataForm1_BeginningEdit(object sender,
System.ComponentModel.CancelEventArgs e) {
_editing = true;
}
protected void DataForm1_EditEnded(object sender,
DataFormEditEndedEventArgs e) {
_editing = false;
}
void TreeView1_SelectedItemChanged(object sender,
RoutedPropertyChangedEventArgs<object> e)
{
if (_editing) {
object previous = DataForm1.SelectedItem;
object current = TreeView1.SelectedItem;
if (MessageBox.Show("Are you sure you want to cancel the changes?",
"Confirm", MessageBoxbutton.OKCancel) == MessageBoxResult.OK) {
DataForm1.CancelEdit();
}
else {
TreeView1.SelectedItem = previous;
}
}
}
Have you tried to set AutoCommit at True ?
精彩评论