Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
488 views
in Technique[技术] by (71.8m points)

c# - MVVM: Is code-behind evil or just pragmatic?

Imagine you want a Save & Close and a Cancel & Close button on your fancy WPF MVVM window?

How would you go about it? MVVM dictates that you bind the button to an ICommand and inversion of control dictates that your View may know your ViewModel but not the other way around.

Poking around the net I found a solution that has a ViewModel closing event to which the View subscribes to like this:

private void OnLoaded(Object sender
    , RoutedEventArgs e)
{
    IFilterViewModel viewModel = (IFilterViewModel)DataContext;
    viewModel.Closing += OnViewModelClosing;
}

private void OnViewModelClosing(Object sender
    , EventArgs<Result> e)
{
    IFilterViewModel viewModel = (IFilterViewModel)DataContext;
    viewModel.Closing -= OnViewModelClosing;
    DialogResult = (e.Value == Result.OK) ? true : false;
    Close();
}

But that is code-behind mixed in with my so far very well designed MVVM.

Another problem would be showing a licensing problem message box upon showing the main window. Again I could use the Window.Loaded event like I did above, but that's also breaking MVVM, is it not?

Is there a clean way or should one be pragmatical instead of pedantic in these cases?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

First, create an interface that contains only the Close method:

interface IClosable
{
    void Close();
}

Next, make your window implement IClosable:

class MyWindow : Window, IClosable
{
    public MyWindow()
    {
        InitializeComponent();
    }
}

Then let the view pass itself as IClosable as command parameter to the view model:

<Button Command="{Binding CloseCommand}" CommandParameter="{Binding RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />

And lastly, the command calls Close:

CloseCommand = new DelegateCommand<IClosable>( view => view.Close() );

And what have we now?

  • we have a button that closes the window
  • we have no code in code-behind except , IClosable
  • the view model knows nothing about the view, it just gets an arbitrary object that can be closed
  • the command can easily be unit tested

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...