I've got a settings window in the app, which has a button for essentially "save and close" action.
Now, the viewmodel knows how to save the data, the command lives there and is linked via {Binding ...}
in Xaml.
To close the window I'm passing the element itself as a command parameter. I don't care about it in practice, but I was wondering what a "nice MVVM way" of solving this would be. What's the ideal/textbook way to keep the UI behaviour separate in that case?
CodePudding user response:
Closing the window is a view responsibility, so that should be done by something in the view. Saving the data is a model responsibility, via the viewmodel. What you need is something in the view that'll close that window. And some way to tell it to close from the viewmodel. The obvious way for a viewmodel to tell a view something changes is binding.
The way I approach this is to bind a command from the viewmodel. That command does the saving and then sets a bound bool property. The view binds to this property and closes itself. This way the viewmodel doesn't need any reference to a window. All it does is sets one of it's properties.
Here's some code to give you a flavour.
I think as soon as you see it you'll likely get the idea.
There's a class inherits from control which has no ui.
CloseMe looks like:
public class CloseMe : Control
{
public bool? Yes
{
get
{
return (bool?)GetValue(YesProperty);
}
set
{
SetValue(YesProperty, value);
}
}
public static readonly DependencyProperty YesProperty =
DependencyProperty.Register("Yes",
typeof(bool?),
typeof(CloseMe),
new PropertyMetadata(null, new PropertyChangedCallback(YesChanged)));
private static void YesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if ((bool?)e.NewValue != true)
{
return;
}
var me = (CloseMe)d;
Window parent = Window.GetWindow(me) as Window;
parent.Close();
}
}
And in my window:
<local:CloseMe Yes="{Binding CloseWindow, Mode=TwoWay}"/>
CloseWindow is the bool property I mentioned in that viewmodel. Set it true and the CloseMe control YesProperty changes to true. The callback fires and it looks up the visual tree for it's parent window. It then closes that window and... done.