MVVM Understanding Issues

2019-01-27 11:58发布

问题:

A list of my questions towards mvvm, you don't need to answer on your own, links which help me further are always appreciated:

  1. If I have a Mainpage.xaml file and I'm using a viewmodelclass which code should be in the Mainpage.xaml.cs file? Nothing?

  2. Should that piece of code be in the Mainpage.xaml.cs file:

    Viewmodel base = new Viewmodel();

  3. If I implement ICommands how can I access for example a textbox.text on the Mainpage.xaml?

  4. ICommands completely replace the Button.Click event? Don't they?

回答1:

  1. Ideally, yes. But in most of cases it's hard to follow
  2. Not in every case. If your ViewModel's constructor does not accept arguments, you can write it in xaml:

    <Window.Resources>
        <local:ViewModel x:Key="viewModel" /> <!-- this row will automatically create instance of ViewModel class-->
    </Window.Resources>
    

If view model class accepts arguments, then yes, you will have to write:

ViewModel base = new Viewmodel(yourArgs);
this.DataContext = base;

in code-behind.

  1. If you want to follow MVVM, bind TextBox's Text property to Viewmodel property:

    <TextBox Text="{Binding MyText}" />
    

and in ViewModel:

private string _myText;
public string MyText
{
    get { return _myText; }
    set 
    {
        if (_myText != value)
        {
            _myText = value;
            // NotifyPropertyChanged("MyText"); if needed
        }
    }
}

Then you could use RelayCommand or DelegateCommand (google it) to operate with text of your TextBox inside ViewModel.

  1. Yes. Command allows also to pass parameter to ICommand (for example, when you will use RelayCommand)

Hope, it helps.



回答2:

  1. If I have a Mainpage.xaml file and I'm using a viewmodelclass which code should be in the Mainpage.xaml.cs file? Nothing?

You need to understand what's is view's and what viewmodel's responsibility. Codebehind is part of view, so only code that is covered by view's responsiblity should be in code behind.

Sometimes databinding to viewmodel is hard in xaml (e.g. PasswordBox) Then you can use codebehind to get the password or catch changes and set property in viewmodel. You should not validate the password agains't server in codebehind.

Sometimes it's difficult to define animations in xaml. Feel free to create or trigger them in C# (but in that case you wont be able to edit then in Expression Blend)

It's ok to use evens like Loaded / Unloaded in codebehind, e.g. I use them to call Activate/Deactivate methods in my viewmodels.

This is codebehind sample, that does not violate the view and viewmodel separation of concerns:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        Closing += MainWindow_Closing;
    }

    MainWindowViewModel ViewModel
    {
        get { return (MainWindowViewModel)DataContext; }
    }

    void MainWindow_Closing(object sender, CancelEventArgs e)
    {
        var canExit = ViewModel.ShowConfirmExitDlg();
        if (!canExit) e.Cancel = true;
    }
}

In other words, sometimes you have to use codebehind. There are people that are saying that you should never use it, but be pragmatic and use it, when it helps you.

  1. Should that piece of code be in the Mainpage.xaml.cs file: Viewmodel base = new Viewmodel();

yep, that's ok. However you should use d:DataContext in xaml in order to let Visual Studio Designer know what datacontext you are using so it could provide you with intellisense and design time support. There is a lot of ways how to set instantiace viewmodel and set it to datacontext. It's up to you whatever you choose.

  1. If I implement ICommands how can I access for example a textbox.text on the Mainpage.xaml?

Create string property in viewmodel and databind the textbox.text to it. Use DelegateCommand, where you can pass method that has access to the property:

public class MainWindowViewModel 
{
    public MainWindowViewModel()
    {
        LoginCommand = new DelegateCommand(Login);
    }

    public DelegateCommand LoginCommand { get; private set; }

    public string Username { get; set; }
    public string Password { get; set; }

    private void Login()
    {
        if (Username == "user" && Password == "user")
        {

        }
    }
}

just FYI, there is also another way of passing parameter to command: check CommandParameter feature [link]

  1. ICommands completely replace the Button.Click event? Don't they?

Almost. The same rules as in answer to first question applies also here.



回答3:

I think your questions indicate that you have not really started to dig too deep into WPF with MVVM yet.

Most "Getting Started" tutorials will address your questions. My favorite tutorial is WPF Apps With The Model-View-ViewModel Design Pattern by Josh Smith.

That one will give you an valid answer to all questions. Do not forget to also download the code example of the article to get the fully working demo application! :-)



回答4:

This question might get deleted for not being specific enough but here goes anyway....

If I have a Mainpage.xaml file and I'm using a viewmodelclass which code should be in the Mainpage.xaml.cs file? Nothing?

Not just MainPage, any other window or control class as well (with some exceptions that I won't go into here). You should be able to create, run and unit test your entire application without creating a single view. The viewmodels are your application, the views are simply the loosely-bound graphical UI representation presented to your users when you're running your application in a way that requires user interaction (i.e. not unit testing).

Viewmodel base = new Viewmodel();

This is a somewhat complex topic but the high-level answer is "use a dependency injection framework". Adding MVVM Lite to your project via NuGet will automatically set this up for you with a very simple framework, otherwise Google is your friend.

If I implement ICommands how can I access for example a textbox.text on the Mainpage.xaml?

You add a string property to your view model with a getter and setter and you bind the textbox's Text property to that.

ICommands completely replace the Button.Click event? Don't they?

In general, yes. The "correct" way to use WPF is to bind commands to your command handlers. Things like event handlers were added for the same reason that property getters and setters were added i.e. to help ease the transition from the old WinForms way of doing things. Just because the framework supports it doesn't mean it's the right way to go about things.



回答5:

  1. I try to keep the code behind to a minimum. I still tend to put the form closing logic in there.

  2. Many people use dependency injection to do this externally from the WPF Form.

  3. You can use data binding to a property on your viewmodel for textbox.text (that uses INotifyPropertyChanged) and modify it in the ViewModel. The form will automatically update to reflect any changed.

  4. Yes, it abstracts the code from the form to the viewmodel.

There are some great videos on YouTube which explains these concepts in detail.

Hope this helps.



标签: c# wpf xaml mvvm