I am new to the MVVM pattern and I am trying to write my own custom Commands. What is the best method to write custom commands? (I read a lot of articles here and there, but could not obtain the idea of creating my commands). And in particular if someone can help me with the idea of creating a command, after a button is clicked to get the items from one ListView and put them in another. (The list view is bounded to ObservableCollection). Thanks in advance!
Just implement the ICommand interface. There are many on the web or even implemented in nuget packages. Search for RelayCommand or DelegateCommand with ICommand and you will find many implementations. After you have that you just wrap the VMs private method in a command. e.g.
ICommand startTestCommand;
public ICommand StartTestCommand { get { return startTestCommand ?? (startTestCommand = new RelayCommand(StartTest)); }
private void StartTest()
{
//This will execute if the Command is bound in XAML
}
To bind the command in XAML (assuming your view model is the data context) just bind the Command property of the button to "StartTestCommand" or whatever your command is called.
So in essence you do not "Create your own command" for what you are asking, but wrap the delegate for a Command mediator to handle preventing coupling. There are reasons to create your own commands, but I would recommend using what is out there.
You just have to implement the ICommand interface. Most MVVM frameworks have a generic delegate based command class which implements it (e.g. RelayCommand in MVVM light). You just pass the methods to execute to their constructor.
Related
I am currently studying the MVVM pattern. So thus far I developed a simple demo programm which contains a view and a viewmodel with commands etc. Now I want to implement a Model but I am not quite sure how to do so. My demo contains a view with a textbox and a button. When the Button gets pressed a Command is launched.
The text from the textbox should be written in a textfile with upper cased letters. This functionality should be part of my model. How do i call this functionality from my viewmodel? Should the viemodel contain a instance of the model class and call a methode in the command execute? And how does the viewmodel get data from a model?
Thank you very much for your help!
Yes. You could instantiate a model object in the viewmodel and have it save the text in a textfile (Or whatever you want your application to do)
class ViewModelDefault : INotifyPropertyChanged
{
// Bound to your textbox
public string TextboxProperty { get; set;}
// Instantiate modellayer in viewmodel
private ModelClass _modelClass = new ModelClass();
// RelayCommand property -> bound to button on viewmodel
// Will execute method "ExecuteCommand" that contains a call to a method in the ModelClass
public ICommand ExecuteModelMethod
{
get {
RelayCommand relayCommand = new RelayCommand(ExecuteCommand);
return relayCommand;
}
}
// Method that the RelayCommand will execute.
private void ExecuteCommand()
{
_modelClass.SaveTextInTextfile(TextboxProperty);
}
...
}
In the code above I've made an example of how this could be done using RelayCommand.
RelayCommand is a class that makes use of delegates such as Action and Func. This means you can pass a method into the RelayCommand object and have it execute it.
What RelayCommand allows you to do is basicly binding a method through delegate to UI control in the view layer.
Read up on Delegates if you wish to study further on that topic.
Delegates (C# Programming Guide)
Usually for data storage and retrieval, I create a separate class called repository.
Your view model has an instance of the repository (or better: an interface of it).
In the repository class, you can do your file access.
By the way: If your view model just knows the interface of the repository, you could replace it later with a database access, and the view model would not be affected.
The view model can then interact with the repository i.e. call it methods when the command code in the view model executes.
You write...
"The text from the textbox should be written in a textfile with upper
cased letters. This functionality should be part of my model."
The model usually is just data, so a model class does not have functionality but only properties. Like I said: Do your data access in the view model or in the repository class.
In case of MVVM it would be good if the properties implement INotifyPropertyChanged , like the properties of your view model.
If you just want to write the content of a single text box, then your model would be a class with just one property.
I have been writing all my MVVM application with basic design pattern generally mentioned in MVVM examples available online. The pattern that I am following is described below:
Model
This section include DTO classes with their properties and Interfaces IDataService and like:
public class Employee
{
public string EmployeeName { get; set; }
public string EmployeeDesignation { get; set; }
public string EmployeeID { get; set; }
}
public interface IDataService
{
public Task<Employee> GetEmployeeLst();
}
Proxy
This layer contains Dataservice calls which implement IDataservice like:
public class DataService : IDataService
{
public async Task<Employee> GetEmployeeLst()
{
// Logic to get employee data from HTTPClient call
}
}
ViewModel
This layer contains ViewModel and reference to Model and Proxy layer from which all data is received:
public class BaseViewModel
{
public BaseViewModel(INavigationService nav, IDataService data, IAESEnDecrypt encrypt, IGeoLocationService geoLocation, IMessageBus msgBus, ISmartDispatcher smtDispatcher)
{
}
// This also include common methods and static properties that are shared among most of the ViewModels
}
All the ViewModel inherits BaseViewModel. Each viewModel also contains Delegatecommand which is executed when UI triggers an event. Which then fetches the data from the server by calling DataService in proxy layer and perform business logic and populates the properties in ViewModel which is binded to the view. For each View there is a VM which is binded to the Datacontext of the View.
ViewModel is also responsible for starting an animation I have used trigger to start storyboard which is binded to my enums in VM for state change of these trigger as in example in: http://www.markermetro.com/2011/05/technical/mvvm-friendly-visual-state-management-with-windows-phone-7/
View
In this layer I have all my Views, Usercontrols and business logic with implementation of certain dependencies like GeoLocation Service, AES encryption, NavigationService between Views etc.
Every View has .xaml and .xaml.cs file. In .xaml.cs file I have binded the data context of the view with VM like this:
this.DataContext = App.IOConatiner.GetInstance<DashboardViewModel>();
and from here on all binding happens.
My problem is that recently I had the knowledge that this pattern is not following a SOLID design pattern which I got know in this answer of my question:
Simple Injector inject multiple dependency in BaseClass
I am trying very hard to change my design as per the suggestion given in my previous question's answer. But I am not able to get some of the things like:
Currently View Datacontext is binded to ViewModel hence all the controls are controlled by a property in VM. How would I change this to your above mentioned pattern with Processor/Service or DialogHandler?
I am using Delegatecommands which are binded to command property of UI element. Execution of these command certain action happens like animation, usercontrol is displayed. How to do it in command pattern?
How can I start changing my current implementation to accommodate all those changes with best possible approach?
First of all an answer to your question 3
How can I start changing my current implementation to accommodate all those changes with best possible approach?
This is the very first step you need to take. It is not a case of some smart refactoring of your current code. You will need to take a step back and design the application. I once read some nice blog about (re)design.
Before starting to write any code, define how many different basic types of views you will want to show to the user? E.g.:
Just show (any type of) data
Edit data
Alert user
Ask user for input
...
When you defined your different requirements, you can translate this to specific interfaces that are tailor made for the job they serve. For example a view that lets the user edit data will typically have an interface that will look something like:
public interface IEditViewModel<TEntity>
{
public EditResult<TEntity> EditEntity(TEntity entityToEdit)();
}
Once you every detail of this design in place, you must decide how you will show your views to the user. I used another interface for this to handle this task for me. But you could also decide to let a navigation service handle this kind of task.
With this framework in place, you can start coding your implementations.
Currently View Datacontext is binded to ViewModel hence all the controls are controlled by a property in VM. How would I change this to your above mentioned pattern with Processor/Service or DialogHandler?
This will not change in this design. You will still bind your view to your viewmodel and set the datacontext to the viewmodel. With a lot of views the use of an MVVM framework like Caliburn Micro will come in handy. This will do a lot of the MVVM stuff for you, based on Convention over Configuration. To start with this model, would make the learning curve even higher, so my advice to start of by hand. You will learn this way what happens under the covers of such an MVVM tool.
I am using Delegatecommands which are binded to command property of UI element. Execution of these command certain action happens like animation, usercontrol is displayed. How to do it in command pattern?
I'm not sure if the command pattern you mention here is the command pattern I advised you in the previous answer. If so, I think you need to reread this blog, because this is totally unrelated to the commands I think you mean in this question.
Animation and that sort of stuff is the responsibility of the view, not the viewmodel. So the view should handle all this stuff. XAML has a lot of ways to handle this. More than I can explain here. Some ideas: Triggers, Dependency Properties
Another option: Code behind! If the logic is purely view related IMO it is not a mortal sin to place this code in the code behind of your view. Just don't be temped to do some gray area stuff!
For commands that just perform a method call in your viewmodel, ICommand is still possible and MVVM tools like Caliburn will do this automagically...
And still: Loose the base class....
Why are you injecting all these services in your viewmodel base class if the viewmodel base class does not make use of these services himself ?
Just inject the services you need in the derived viewmodels that do need those services.
Given a basic C# library, how do I implement functions of this library into my WPF application to handle appropriately the concepts of Binding and Commands?
I mean, need I write some own wrappers for these library classes in order to implement interfaces such as ICommand or should this be done directly in the library itself?
Some code to get my question more comprehensible:
From the library:
public class Item
{
public string Name { get; set; }
public void DoSomething() { throw new NotImplementedException; }
}
I want to implement the function DoSomething() in my XAML markup without any line of code in that .cs file since that is, from what I've read, the best practice.
(Assuming that an instance of Item is bound to the control)
<Button Command="{Binding DoSomething}"/>
Well, in order to do so, I need to implement the interface ICommand and create a command, but that is, as stated above, unclear to me since I'm using a library here.
Should I write my own Wrapper for the Item class of the API and implement the ICommand interface or is there any other way to archieve this? I've written the library by myself so changes are possible. I'm just not entirely sure about changing the library because if I do so, it is (possibly) bound to WPF.
Hi there if anything your ViewModel should handle any requests on your Model that's it's sole purpose, to get these things to work you need ICommand and if you want some more info here is link with a tutorial on RoutedCommands. If you have your Model and ViewModel defined then you can easily assign tasks to the particular Model through its VM.
P.S. I think you could treat your library as a Model and write a "wrapper" ViewModel to handle operations on it. HTH
UPDATE
Consider following:
class libClass
{
void method()
{
//do something here
}
}
code above would be your model and if you want it to be more readable you could do it this way
class libModel
{
private libClass _libClass;
public libClass LibClass { get; set; }
}
Note
You could implement INotfiyPropertyChanged in your Model to handle any changes if needed of course.
now in your VM how you use the Model
class ViewModel
{
private libModel _libModel;
public libModel LibModel { get; set; }
//after you set up your RoutedCommands
//I declare method within my VM to handle the RoutedCommands don't know
//if it works when you use Property Method
void VMMethod()
{
//use VM's property to invoke desired method from your lib
}
}
and voila! ready "wrapper" for your class with implementation in your VM.
Tip
If you want to know how to do the RoutedCommands here is a link to a tutorial.
I'm just starting out with WPF and I want to use custom commands whenever possible as part of the MVVM pattern. The book that I've been using (C# 2010 All-in-One for Dummies) has a sample of a custom command but it uses hard coded information to complete its task and I don't see how to use the Command system to complete my task.
Book Code:
public abstract class CommandBase : ICommand
{
public string Text { get; internal set; }
public abstract void Execute(object parameter);
public abstract bool CanExecute(object parameter);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
public class AddCustomerCommand : CommandBase
{
public AddCustomerCommand()
{
Text = “Add Customer”;
}
public override void Execute(object parameter)
{
var list = parameter as IList<Customer>;
if (list == null)
{
return;
}
list.Add(new Customer { ID = 4, Name = “New Customer”} );
}
public override bool CanExecute(object parameter)
{
return parameter is IList<Customer>;
}
}
In this case, Execute works because it is passed an IList<Customer> and can add to it without needing to return anything. This makes perfect sense to me.
My Problem:
I have an MVVM app that has a data grid, some text boxes, and some buttons. My view model has IList<Entry> Entries, properties for the text boxes, and of course an instance of my custom command AddEntryCommand. The goal is to be able to enter text, and hit add, and have a new Entry be added to Entries using AddEntryCommand.
What I don't understand is how to go about getting Entries and the new data into the command. Here are the possible solutions I've thought of and what I see wrong with them
Pass in the view model so that all its information is available.
Pass in an array of objects.
Pass in a Tuple.
Passing thew view model seems excessive, and if I do that then everything on the view model would have to be mutable.
I try and avoid using object whenever possible, and object[] seems even more work to deal with. I'd have to pick it apart like command line arguments.
Tuples...
My idea of a command is that it's supposed to be a method with bells and whistles for making the UI react nicely. Anything that causes the command to be tied to a specific view or view model breaks that.
So my questions are:
How do you do work with multiple objects using ICommand?
How can you use ICommand to work with immutable objects if it's locked to return void?
Is my idea of what a command is for way off base?
(I've tried searching for a better tutorial or resource for this but my Google fu is weak and I can't seem to locate anything that's clear and concise. There are lots of questions on SO about commands in WPF, but they're all for very specific implementations. I'm looking for a general answer regarding manipulating multiple objects in one command.)
UPDATE
I have been looking around the net some more but I still haven't found anything like the sample provided by my book. I have looked at DelegateCommand and that seems like a pretty straightforward and easy to use system. It still leaves me wondering why such a large chunk of the chapter on MVVM would be dedicated to creating a custom command using just ICommand and not one of the other classes that already inherit from it.
How can I use the RelayCommand in wpf?
Relay command doesn't exist in WPF, it is just a external class that raised to prominence after it was defined in this MSDN article. You need to write it yourself if you want to use it.
Otherwise you can you the Delegate command from the WPF toolkit here which has a little bit of extra functionality over the RelayCommand code.
Ah, the question changed while I was typing this answer. Assuming that you are using the RelayCommand as defined above you need to supply it with one or two delegates, one that returns a bool which determines whether the command is in a valid state to be run, and a second which returns nothing and actually runs the command. If you don't supply a "CanRun" delegate then the command will consider that it is always in a valid state. The code used in the article:
RelayCommand _saveCommand;
public ICommand SaveCommand
{
get
{
if (_saveCommand == null)
{
_saveCommand = new RelayCommand(param => this.Save(),
param => this.CanSave );
}
return _saveCommand;
}
}
Declares a RelayCommand that will call the Save() method when triggered and return the CanSave property as a test for validity. When this command is bound to a button in WPF the IsEnabled property of the Button will match the CanSave property of the ViewModel and when the button is clicked (assuming it is enabled) the Save() method will be called on the ViewModel.
As an alternative to creating RelayCommand wrappers for all your methods can I suggest a free library and source that will allow you to use the binding {BindTo Save()}. I created it to simplify my bindings. It also makes relative binding much easier. You can find it here: http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html