Reputation: 510
I can't really wrap my head around the following problem:
All I have in the application is a textbox
for the user input, a button
for performing a background calculation on that input and a textblock
. Imagine I have to use MVVM, so I have my view
, viewmodel
and model
classes.
I bind the controls (textbox
, button
and textblock
) from the view to the viewmodel
on corresponding properties and commands. However, I'm not sure where the viewmodel
functionality should end. For instance, would the following be a way to structure the application?
Model:
public class Model
{
public string Input { get; set; }
public string Output { get; set; }
public void FancyMethod ()
{
// Use input to calculate output
}
}
ViewModel:
public class ViewModel
{
public string Input {get; set;}
public string Output {get; set;}
public ICommand command {get; set;}
public Model model {get; set;}
public ViewModel()
{
model = new Model();
}
// When the button is pressed, model.input = Input and then execute model.FancyMethod()
}
Upvotes: 0
Views: 2808
Reputation: 17658
If you want to keep a clean layer model, you should not include public Model model {get; set;}
in your ViewModel
.
So, for example, if you have a command, targeting some business model, your structure should be something like this:
//you don't have this one... but well, maybe other cases have
public class SomeService : ISomeService
{
//member of ISomeService
public void SomeFancyMethod(Model model)
{
//do stuff..
}
}
public class Model //might be database, or domain model.
{
public string Input { get; set; }
public string Output { get; set; }
}
As for your viewmodel, it will become something like this:
public class ViewModel
{
private ISomeService _someService;
//note: someService is passed through a IoC service like ninject, unity, autofac etc.
public ViewModel(ISomeService someService)
{
_someService = someService;
//initialize the command:
command = new RelayCommand(() =>
{
_someService .SomeFancyMethod(new Model()
{
//properties could be mapped with an automapper.
});
});
}
public ICommand command {get; private set;}
public string Input {get; set;}
public string Output {get; set;}
}
Note: there are some additional techniques involved:
"So why make this so 'complicated'? You are just making a copy.", a commonly heard argument against this pattern:
Well:
Upvotes: 2
Reputation: 169200
I guess the FancyMethod()
contains your business logic and produces a value that you want to display in the view. In this case, FancyMethod()
belongs to your model as it contains some business logic that is the same regardless of whether it's being executed in the context of a client application or some other component.
So your model would look something like this, i.e. it accepts an input and produces an output but it doesn't expose any properties that a view may bind to:
public class Model
{
public string FancyMethod(string input)
{
// Use input to calculate output
}
}
You could then inject your view model with the model and call the FancyMethod
when the user executes the command by clicking on the Button
in the view:
public class ViewModel
{
private readonly Model _model;
public ViewModel(Model model)
{
_model = model;
command = new RelayCommand(Execute, CanExecute);
}
public string Input { get; set; }
public string Output { get; set; }
public ICommand command { get; private set; }
private bool CanExecute(object _)
{
return !string.IsNullOrEmpty(Input);
}
private void Execute(object _)
{
Output = _model.FancyMethod(Input);
}
}
Obviously the view model class should also implement the INotifyPropertyChanged
interface and raise change notifications to the view.
In short the business logic belongs to the model and the application logic, for example what happens when a user clicks a Button
, belongs to the view model.
Upvotes: 1
Reputation: 53
I think its not necessary to outsorce the Input
and Output
properties in another class. The reason for this is that the properties reflect the input and output of the view. So they have to be in the viewmodel.
You can outsorce the SomeFancyMethod
in a service class to separate the logic from the viewmodel anlogous to mvc.
Upvotes: 0