Should i create a Class for each button in the interface? - c#

I have a question, i watched a lot of tutorial about MVVM but i'm still confused.
I have an interface with more than one button on it, i have to implement the ICommand interface for bind the command to the View.
I did it like this:
MainSolution
Main Solution
Model
SomeClass.cs
ViewModel
Commands
SomeCommands.cs
SomeViewModel.cs
Ok, now in the interface i have more than one button, each one do separate things, example, one is for start a thread the other one for cancel it and a third one for another thing.
Should i create a separate class, that implement ICommand interface, for each button that i have on the View?
Main Solution
Model
SomeClass.cs
ViewModel
Commands
StartCommands.cs
CancelCommands.cs
OtherCommands.cs
SomeViewModel.cs
I'm asking this because when i implement the ICommand interface i have only one "Execute" method, and only one "CanExecute" method. What is the common way to implement multiple button on a View through binding?
I searched for example online without any luck... A lot of them are so confusing, and surely not for a newbie like me.
The other thing is when i have multiple View and Multiple ViewModel, should i create multiple Commands Folder for nesting it?
Main Solution
Model
SomeClass.cs
ViewModel
FirstCommands
StartCommands.cs
CancelCommands.cs
OtherCommands.cs
SecondCommands
StartCommands.cs
CancelCommands.cs
OtherCommands.cs
FirstViewModel.cs
SecondViewModel.cs

IMHO having a separate class for each command in a classic MVVM approach is an overkill. Use something like the MVVMLight's RelayCommand (and the generic one if you want to pass a parameter).
Then you can define your commands as your ViewModel members and provide Execute/CanExecute implementation as part of your ViewModel as well:
public RelayCommand MyCommand { get; }
public MyView()
{
//[...]
this.MyCommand = new RelayCommand(this.ExecuteMyCommand, this.CanExecuteMyCommand);
}
public void ExecuteMyCommand()
{
//do work!
}
public bool CanExecuteMyCommand()
{
//optional - control if command can be executed at a given time
}
And you can bind to MyCommand in XAML (assuming your View is bound to your ViewModel):
<Button Content='WORK!' Command='{Binding MyCommand}' />

What you want is a DelegateCommand class. You can use Prism, or just google around and steal one; here's one on StackOverflow that I haven't tested but it looks legit. If you don't need a parameter for a command, just ignore the parameter argument.
A DelegateCommand implements ICommand, and calls an Action or Action<object> that you pass to its constructor, like so (from the StackOverflow answer linked above):
public DelegateCommand AddFolderCommand { get; protected set; }
public MyViewModel(ExplorerViewModel explorer)
{
AddFolderCommand = new DelegateCommand(ExecuteAddFolderCommand, (x) => true);
}
public void ExecuteAddFolderCommand(object param)
{
MessageBox.Show("this will be executed on button click later");
}
This should have been included in WPF, but wasn't, for whatever reason.

Related

MVVM Handling Window Management using Factory Approach

I delegate creation(showing) of my Windows to my WindowFactory, that attaches a ViewModel to the View and shows the window. It is injected into my MainViewModel Constructor parameters.
The factory itself is very simple:
public class ProductionWindowFactory : IWindowFactory
{
public void CreateNewWindow()
{
PhoneWindow window = new PhoneWindow();
{
window.DataContext = new phoneWindowViewModel();
}
window.Show();
}
}
Now, I'm aiming at implementing more functionality of my new windows, that will happen on certain button clicks IN that new window.
As I am fairly new to Factories in general, I'm struggling to grasp a certain concept:
Example:
We have a ViewA that has a ViewModelA attached to it.
That view has a button with a command attached, that tells our WindowFactory to show a new ViewB.
ViewB has a ViewModelB and a close button, that tells it to close ViewB.
Now, since we shouldn't reference our ViewB in our ViewModelB, we have to somehow let it know which view it should close.
I have come up with possible ideas / solutions, but I would really
appreciate you letting me know which one follows the MVVM and Factory
pattern "the most", and which one is usually used in such situations.
Make our ViewModelB take an instance of windowFactory that created ViewB as a parameter on initialization, and build a method in the Factory that closes ViewB and is executed through button click -> command.
Create an IWindowManager? that inherits from IWindowFactory and build a WindowManager class, that extends the capabilities of our WindowFactory, and push it in ViewModel constructors as described above.
Any other correct solution, that I am completely unaware of?
Please bear in mind, that the above is just an example. Ideally, I'd like to implement more of advanced functionality to my windows, and have an ability to create & manage multiple different ones using that one factory.
I have not attached much code, since I'm still at the stage of learning and deciding which solution should I go with.
EDIT - REGARDING POSSIBLE DUPLICATE:
My question differs from the proposed duplicate, as the other one is simply about managing of closing windows - My question is about doing that as well, but following a FactoryPattern.
I have specified very clear guidelines in what I am trying to achieve and in what ways, that are completely different from the question linked.
First of all, the answer is none. The job of a factory is to create new objects, think of it as an elaborate new operator. Also, the idea of following a pattern "the most" is problematic in and of itself. You employ patterns because they help you achieve certain goals, e.g. you employ mvvm to evade coded-ui tests as much as possible, because they are fragile, normally.
That being said, what to do with its view is completely up to the view's view model.
Example: if one view model needs to close its own window, do it with a command as illustrated in the comment. If a view has a close all-button, its view model will have a dependency on some kind of window registry that can enumerate all open windows for the close all-command to close.
When looking at your view model, try to come up with an idea of what services it needs from the rest of the application, and inject those dependencies as interfaces. When implementing the interfaces, most likely there will be classes that implement more than one, e.g. WindowManager might implement IWindowFactory and IWindowRegistry thus making it very easy to put all newly created windows into the list of open windows. The window will have a dependency on the IWindowRegistry, too, most likely, to unregister itself when it gets closed.
The duplicate was not far off. Here is a simple adaptation of the scenario in OP
interface IView {
void Close();
}
class ViewAdapter : IView {
readonly Window view;
public ViewAdapter(Window view){
this.view = view;
}
public void Close() {
view.Close();
}
}
public class ProductionWindowFactory : IWindowFactory {
public void CreateNewWindow() {
var view = new PhoneWindow();
var viewAdapter = new ViewAdapter(view)
var viewModel = new phoneWindowViewModel(viewAdapter);
//Bind
view.DataContext = viewModel;
view.Show();
}
}
If the view model wants to instruct that the view be closed it can ask the injected contract to do so.

How to access to all viewmodels via the viewmodel base?

I've created a ViewModel class that have inside the implementation of INotifyPropertyChanged, now I also have other ViewModels that inherit from the ViewModel (base).
All working good actually but I have a doubt.
So let's say that I've in the CustomerViewModel an ObservableCollection called Price, like this:
private ObservableCollection<Models.Price> _price = new ObservableCollection<Models.Price>();
public ObservableCollection<Models.Price> Price
{
get { return _price; }
}
this ObservableCollection should be populated by other classes, 'cause I need to access to the same resource.
I really don't understand how can I do this in mvvm. I though to a Singleton ViewModel, so something like this defined in the base VM:
public static ViewModel Instance { get; set; }
So import all the childs VM into the base and access them via ViewModel.Instance.Price;
but doesn't seems a good practice for me. Any idea?
With this implementation, you can share the same Datasource to all ViewModels
public class PriceGenerator {
private PriceGenerator() {
this.Prices = new ObservableCollection<Price>();
this.Generate();
}
void Generate() {
//Generate Objects here
this.Prices.Add(generatedPrice);
}
public ObservableCollection<Price> Prices {
get;
}
private static PriceGenerator _instance;
public static PriceGenerator Instance => _instance ?? (_instance = new PriceGenerator());
}
There are generally two approaches to this.
Even if you don't have a real database/repository, implement a singleton class that simulates this. This singleton class should also implement INotifyPropertyChanged (and/or INotifyCollectionChanged as appropriate). All ViewModels will be able to access this simulated repository, and interested ViewModels can choose to subscribe to this repository's PropertyChanged callback. For your question, it is generally tidier to have a repository that handles just prices, rather than having a simulated repository that stores 101 different information.
Have a main ViewModel. Some people would visualize that the MainWindow being the main view, with a corresponding main ViewModel. This ViewModel is intentionally made a singleton, which other ViewModels can access through static call. This main ViewModel is basically acting just like #1 - it is like a repository that stores 101 different information. That main ViewModel is likely to look untidy, but it is simply to trace where things are stored - if you need any data, it's probably in there.
Personally, I prefer to use the first approach. lokusking's answer is an example of this approach. Although his "repository" does more than storing data.

mvvm update listview when repository.save is called from a different window

I have a WPF listview containing ingredients bound to viewmodel.Ingredients(MVVM pattern)
Now i want this listview to update when i add and save an ingredient in the database in a different window(calls repository.Save()).
(viewmodel.Ingredients calls repository.findAll())
I see 2 possible ways of doing this:
1) Using MVVM : Raise the property change event in Repository.Save(). But then i need to register the repository as a 2nd datasource on my view or do something else that will cause my view to update. How do i implement this?
2) An alternative would be using the MVC pattern for updates from the repository(together with the mmvm)
the viewmodel could then implement the IUpdateIngredients interface
public interface IUpdateIngredients
void Update()
then my repository has the methods:
public void removeHandler(IUpdateIngredients handler)
public void AddHandler(IUpdateIngredients handler)
public void RaiseUpdateEvent() // call Update() on all the handlers
The viewmodel registers itself with the addHandler method. The repository.Save method calls RaiseUpdateEvent();
This would do the job, but i really want to get rid of the removehandler method. Is there a way the .NET framework can do the removing for me, perhaps using events? I want to get rid of the removeHander method because i reuse this listview on many different places, sometimes in popup widows, and i want to make sure i dont forget the call the removehandler method somewhere.
Thanks for helping me!
I had a similar problem, I used a Mediator in the class that was doing the database updates, to send the message to other ViewModels to refresh their collections.
As mediator stores the target ViewModels as WeakReferences , there’s no need for removing the event handlers. Here’s a great article with sample code about the Mediator pattern by Josh Smith …
I modified the code from the above article to my needs, most importantly Mediator was implemented as a Singleton, like this.
private static readonly Lazy<Mediator> _lazy = new Lazy<Mediator>(() => new Mediator());
public static Mediator Instance { get { return _lazy.Value; } }
Now every ViewModel and broadcaster get the instance of Mediator …
public Mediator Mediator
{
get { return Mediator.Instance; }
}
And the class that updates the database sends the message to ViewModel that needs to refresh.
Mediator.NotifyColleagues(MediatorMessages.DBUpdated);
ViewModel registers for messages in the constructor and then updates the collection.
Mediator.Register(MediatorMessages.DBUpdated, new Action(RefreshCollection));

How to (correctly) update the M in MVVM of WPF application?

Having passed a series of Edward Tanguay's questions refractoring the usage of MVVM for WPF app which can be found in Linked sidebar of his Fat Models, skinny ViewModels and dumb Views, the best MVVM approach?, I am a little confused by his
final WPF application in Big smart ViewModels, dumb Views, and any model, the best MVVM approach?
Its M (Model) is Customer class:
//model
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime TimeOfMostRecentActivity { get; set; }
public static Customer GetCurrentCustomer()
{
return new Customer
{ FirstName = "Jim"
, LastName = "Smith"
, TimeOfMostRecentActivity = DateTime.Now
};
}
}
which returns current user. Kind of, beause it returns duplicates of newly created "current" user...
But where is the M's data stored and updated in case of need?
Suppose, I want to change the model's current user's FirstName to "Gennady"?
I added a button for updating the model with this button click event handler:
private void button1_Click(object sender, RoutedEventArgs e)
{
}
aiming to change the model's data from it which will be reflected in GUI.
How can I do this, by clicking this button... sorry, by placing the code into this button1_Click()?
Or it is something wrong with my wish to do it?
Then. how to correctly update/change M in MVVM ?
Update:
All answers seem refer that I should not make changes in M but on VM.
Though I've specifically asked about referenced M-V-VM implementation with:
public CustomerViewModel()
{
_timer = new Timer(CheckForChangesInModel, null, 0, 1000);
}
private void CheckForChangesInModel(object state)
{
Customer currentCustomer = CustomerViewModel.GetCurrentCustomer();
MapFieldsFromModeltoViewModel(currentCustomer, this);
}
public static void MapFieldsFromModeltoViewModel
(Customer model, CustomerViewModel viewModel)
{
viewModel.FirstName = model.FirstName;
viewModel.LastName = model.LastName;
viewModel.TimeOfMostRecentActivity = model.TimeOfMostRecentActivity;
}
So, for example, upon implementing the code from Adolfo Perez's answer changes, the TextBox's content is changed from "Jim" to "Gennady" only for a period of interval set in _timer = new Timer(CheckForChangesInModel, null, 0, 1000);.
All logic of referenced by me M-V-VM in WPF approach is such that it is "M" should be updated, in order VM has caught up those changes, but not the "VM".
Even more, I cannot understand, if to make changes in VM how can they be reflected in M if the VM knows about M but - not vice versa - Model does not know about ViewModel).
In MVVM you should avoid code-behind. The reason is that you want to end up with testable classes, in this case your VM's that are completely independent from your V. You could run a set of unit tests on your VM without involving the V. You could also hook different types of Views without affecting your business logic.
Your button will bind its Command property to an ICommand property exposed in your VM. This Command in your VM will handle your click event in the method you specify.
In your View:
<Button Content="Change FirstName"
Command="{Binding Path=ChangeFirstNameCommand"}/>
In your ViewModel:
//Define your command
public ICommand ChangeFirstNameCommand {get;set;}
//Initialize your command in Constructor perhaps
ChangeFirstNameCommand = new RelayCommand(OnChangeFirstName,CanChangeFirstName);
private void OnChangeFirstName()
{
//Your FirstName TextBox in your V will be updated after you click the Button
this.FirstName = "Gennady";
}
private bool CanChangeFirstName()
{
//Add any validation to set whether your button is enabled or not.
// WPF internals take care of this.
return true;
}
It is very important to keep in mind that in this pattern your V knows about your VM and your VM knows about your M but not the other way around.
In your example if you want to change your Model FirstName property you woud have to do the following:
Create a VM which implements INotifyPropertyChanged
Expose your M FirstName property in your VM notifying changes
Create a TextBox in your XAML View and bind its Text property to your VM.FirstName setting Binding Mode=TwoWay.
<TextBox Text=
"{Binding Path=FirstName,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
As you type in the TextBox your FirstName will be directly populated in the VM-M. Also, thanks to the Two way binding, if you modify your FirstName property in your VM, that change will be reflected automatically in your V
Set your View.DataContext to your VM. This is what sets the Context for all your data bindings, unless you specify a different binding source.
If you want to persist changes in a DB then inject a service class in your VM which will take care of CRUD operations
Take a look at this simple example:
http://www.codeproject.com/Articles/126249/MVVM-Pattern-in-WPF-A-Simple-Tutorial-for-Absolute
Your model is your domain (business) objects. There are number of ways you can get them. For example you may have a repository class that gives you your data when you request it and handles the persistance when you wish to store it.
Your view-model is a class that handles UI logic, like updating fields, reacting on user actions, etc. In your case, you may pass an instance of CustomerRepository class to your view model. Then in view-model code you get the instance of Customer from the repository and fill your view-model properties on wich your UI elements are bound.
Your view is just a set of rules of how you wish to show the information to a user. It must be as declarative and logic free as possible.
Having a code like this:
private void button1_Click(object sender, RoutedEventArgs e)
{
}
in your view (or even worse - in your view-model) is a huge mistake wich breaks the pattern and may (and surely will) lead to troubles. You should bind ICommand fields of ViewModel to the buttons. You should not try to write a WPF application in a WinForm event-driven style.
That's how mvvm works in general and it's main purpose is to support multi-tier architecture in your application.
First off, you need to work on your V and VM.
If you are using a Click event for a button, you definatly aren't following this architecture.
You need to use WPF and XAML in your view to bind to your ViewModel, your ViewModel should be a subset of a particular or potentially many models and present the properties to the View which allows for binding.
I would also consider researching:
RelayCommand and ICommand for binding your buttons.
Repository pattern for interchanging your models and creating a way of CRUD
The tutorial which you have followed doesn't seem to be very good in that the concepts haven't really been put across properly or you haven't understood them.
If you have a pure WPF application it could be interesting to investigate the MVVM 'reverse' pattern, ViewModel-First.
For webdevelopment it is common to use MVVM because webpages get loaded through a browser and the View is constructed wich creates the ViewModel.
WPF users do not browse to pages (unless you use Page navigation) so it gets more interesting to follow VM-V-VM-M :
interface IMyView
Show();
//view implementations in different assemblies:
//silverlight
class SilverlightMyView:IMyView
Show();
//wpf
class WpfMyView:IMyView
Show();
class MyViewModel
IMyView _view;
MyModel _model;
//ex. view resolved by DI (Unity, ..)
MyViewModel(IMyView view)
_view = view
Show(model as MyModel)
_model = model;
_view.DataContext = this;
_view.Show();

How to expose Command classes to XAML views through View Models

I have a simple MVVM architecture where I'm using a view model to bind commands to a xaml view. My commands are fairly generic and I'll be binding them to a couple of views so I've put them into their own classes implementing the ICommand interface. Inside of the view model I have public accessors like so:
private ICommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
{
_myCommand = new MyCommand(_injectedModel);
}
return _myCommand ;
}
}
This all works and I'm happy with the architecture but ... I have tons of these functions. They all roughly do the same thing - expose the command as a public property, check if a private command already exists and if so use it otherwise create a new command. It's a bit "boilerplate" for my taste.
I would like a nice way to abstract this. I could create a method that looks up commands based on an identifier from some sort of command map. I could just create all of my commands in the view models constructor (rather than doing so lazily).
What would you consider best practice? Should I avoid instantiating a new command inside each view model and have a central command lookup?
I could just create all of my commands in the view models constructor (rather than doing so lazily).
I often do this. The cost of a command is fairly cheap, in most implementations. Depending on your implementation, it's likely just a small class with a single delegate reference (or a pair of delegate references). This is unlikely to be significant enough overhead, IMO, to warrant the lazy construction.
I often write this as:
// Constructor
public MyViewModel()
{
this._injectedModel = SetModel();
this.MyCommand = new MyCommand(_injectedModel);
}
ICommand MyCommand { get; private set; }
You seem to be looking for Caliburn.Micro. It maps ViewModel methods to x:Name in XAML.
You won't need the "boilerplate" code for commands anymore.
Example:
<Button x:Name="Save" />
Will call:
public void Save()
{
//Save logic
}
On button click.
Notice that at no point i made any Command, it's all done behind the scene.
This is a very simple example, you can add parameter(s) to the call and make it use a different event than Click.

Categories

Resources