I have a static property which tracks property changes in my viewmodels:
public static class Global
{
public static int Warning
{
get { return _warning; }
set { _warning = value; OnStaticPropertyChanged(); }
}
private static int _warning;
}
Then, in viewmodels I have CanExecute commands (for buttons to cancel changes):
private bool Cancel_CanExecute(object parameter)
{
bool changes=false;
if (!string.IsNullOrEmpty(Name) && !string.IsNullOrEmpty(SurName))
{
changes= true;
}
if (changes)
{
Global.Warning = 1; //Changes are true, store this state
}
return changes;
}
When there are changes in my views, and user want to switch a view, I want to show them a warning MessageBox. So in my main Window viewModel I have a command for changing views:
private void Open_view(object parameter)
{
if (Global.Warning != 0)
{
var msg = _windowservice.ShowMessage("Want to leave? Changes won't be saved.");
if (msg == true) //User clicked OK in MessageBox
{
Global.Warning = 0; // reset static property to default, and proceed with code
}
else
{
return; //Prevent opening new view
}
}
//Switch to new view - Calling this line before 'Global.Warning = 0;' doesn't help either
Open_view = new SomeViewModel();
//...
}
But, when I confirm MessageBox to leave view without saving changes & with reseting static property Warning to 0, CommandManager still invokes CanExecute command of old viewmodel, so my Warning property gets again value of 1.
My views are all UserControls with defined DataTemplates in resource dictionary, and only way I could manage to solve this behaviour is by UserControl code behind, like this:
private void UserControl_Unloaded(object sender, System.Windows.RoutedEventArgs e)
{
this.DataContext = null; //
}
Question: How to properly handle this situations in MVVM ? Bottom line is that I want to track property changes in my view while still be able to inform user of unsaved changes If he wants to leave this same view.
EDIT: not sure If helpful, but here is my command implementation too:
public class MyCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Predicate<object> _canExecute;
public MyCommand(Action<object> execute, Predicate<object> canExecute)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute?.Invoke(parameter);
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public void RaiseCanExecuteChanged()
{
CommandManager.InvalidateRequerySuggested();
}
}
Defined DataTemplates (resource dictionary, which is registered in app.xaml):
<!--Each view has It's own reference of ViewModel-->
<DataTemplate DataType="{x:Type ViewModels:HomeViewModel}">
<Views:HomeView />
</DataTemplate>
//...etc..
Property for changing views:
///<summary>Inherited Base property</summary>
public object Open_view
{
get { return _open_view; }
set { _open_view = value; OnPropertyChanged(); }
}
private object _open_view;
All views are opened in MainWindow via ContentControl (tried with UpdateSourceTrigger here too..) :
<ContentControl Grid.Column="1" Grid.Row="2" Content="{Binding Open_view,UpdateSourceTrigger=PropertyChanged}">