How to open a modal dialog (view) from a ViewModel (in mvvm) - c#

I have an application which holds objects in a list view. I want to enable user to change those objects using modal dialogs when an item is double clicked in the list view.
I am using the mvvm light toolkit. When I double click an item in the list view I know which object and therefor which model type is chosen. I am retrieving the corresponding ViewModel via a ServiceLocator and I am using Execute to "launch" the viewmodels' relay command passing the model as object with the needed data information. However, now, in the ViewModel, I am struggling how to open the corresponding view as a model dialog bound to the ViewModel?
Edit (add some code fragments)
public class ViewModelLocator
{
public ViewModelLocator
{
SimpleIoc.Default.Register<OptionSpecificViewModel>();
}
public OptionSpecificViewModel OptionSpecificView
{
get
{
return ServiceLocator.Current.GetInstance<OptionSpecificViewModel>();
}
}
}
the view locator works fine
public class MyListViewManager
{
public void CallMyDialog(Guid xxx)
{
var objModel = GetMyModelByGuid(xxx);
var vm = CommonServiceLocator.ServiceLocator.Current.GetInstance<ObjectSpecificViewModel>();
vm.EditCommand.Execute(objModel);
}
}
the "ListViewManager" works also
My Problem is, that I am in the correct ViewModel with the correct model (data).
public class OptionSpecificViewModel : ViewModelBase
{
public OptionSpecificViewModel()
{
InitRelayCommands();
RegisterMessages();
}
...
public void OnEditCommand(object model)
{
// I reach here in the correct view model with the correct model
// but how can I open the view here??
}
}
As far as I understood MVVM, the view model does know the model and the view has a "connection" to the ViewModel via binding.
But the ViewModel does not know the view. so how do I start the view?

Related

MVP pattern WinForms: How to correctly update UI?

Given the following MVP setup how would you update the winforms UI? This is my first time trying to implement MVP and I believe I have been following a "Passive View" implementation of MVP.
I really didn't want my model to reference the presenter because I thought that was against the idea of the MVP pattern but then isn't the purpose of the Presenter to update the View? And obviously didn't want my Model updating my view. Let me know if I have made a mistake in my thinking though!
public class HomePresenter
{
Item item;
Model model
SomeTask()
{
model.AnotherTask(item);
}
}
public class Model
{
public void AnotherTask(Item item)
{
/* SOME COMPLEX LOGIC HERE */
if (item.BoolProperty)
// How do I write "Success" to richtextbox in View
else
// How do I write "Failure to richtextbox in View
}
}
Your Presenter should sync your View and your Model. The View only shows the data. The Model know's the business logic and "real" data and the Presenter link the Model data to your View. So you won't access the Richtextbox from your Model. Instead you do this from your Presenter. To stay independent you should use Interfaces. So you have no direct access to View elements in Presenter or Model.
Create an IView Interface and an IModel Interface. Both of them are
known by your Presenter.
Your example could look like this:
public class HomeView : IHomeView
{
public string Text
{
get {return richtextbox.Text;}
set {richtextbox.Text = value;}
}
}
public class HomePresenter
{
IHomeView view;
IModel model;
HomePresenter(IHomeView view, IModel model)
{
view = view;
model = model;
//Update View
view.Text = model.Text;
}
public void UpdateModel
{
model.Text = view.Text; //Set the Model Property to value from Richtextbox
}
}
public class Model : IModel
{
public string Text {get;set} //Property which represent Data from Source like DB or XML etc.
}
You find another example here.

Can Pass View to ViewModel in MVVM?

For my project I need to know which View is using my ViewModel
So i created this ViewModel:
public class HistoriqueViewModel : INotifyPropertyChanged
{
public HistoriqueViewModel(MetroWindow view)
{
this.MetroWindow = view;
this.ExportCommand = new RelayCommand(Export_Ex);
}
private MetroWindow _metroWindow;
public MetroWindow MetroWindow
{
get { return _metroWindow; }
set
{
if (Equals(value, _metroWindow)) return;
_metroWindow = value;
OnPropertyChanged();
}
}
//.........
}
And in the View constructor:
public partial class ViewHisto : MetroWindow
{
public ViewHisto()
{
InitializeComponent();
DataContext=new HistoriqueMV(this) ;
}
}
It Work perfectly for me but I want to know if this Break the MVVM Pattern?
Yes, this breaks MVVM. A properly constructed view model shouldn't care about what the view is.
Nothing in your code really suggests why you are passing that reference (other than exposing the view as a public property, which is an even bigger no-no) but there are several ways around it:
Pass the view as an interface and hold/expose that
Use a mediator to pass whatever messages necessary between the view model/view
Have the view invoke whatever methods it needs on the view model, and have the view model raise events that the view can listen to.
Any of the above approaches will provide far better decoupling than the one you are going with.
One other thing, its "View Model", not "Model View"

how to refresh ObservableCollection in View1 when coming back from view2 in wp8 mvvm project

I have an MVVM project in which the main view ("View1") has a button called Save and listbox control which has binding of model emp.
The viewmodel (ViewModel1) implements inotifypropertychanged and it has SavedButtonCommand binding to Save button of View1 and saves the record to SavedEMp.In View1 there is a button "Next" which takes to the "View2" page.View2 page has ViewModel2 which has SaveAgain button .And viewmodel2 has a binding to the SaveAgainButtonCommand and it also saves the record to the localdb called SavedEmp of emp records.
View1 listbox gets refreshed when the statement RaisePropertyChanged("SavedEmpDataSoruce") gets executed and the observablecollection "SavedEmpDataSoruce" is binding to this listbox.Since these two are in View1 after the save button whenenever the statement RaisePropertyChanged("SavedEmpDataSoruce") gets executed it is refreshing the data.
But when user comes back from View2 to View1 the listbox in View1 is not refreshed with the data of View2 saved emp record.
private ObservableCollection<Emp> _SavedEmp;
public ObservableCollection<Emp> SavedEmp
{
get
{
if(_SavedEmp == null)
{
_SavedEmp = Emp.GetSavedEmps();
}
return _SavedEmp;
}
set
{
this._SavedEmp = value;
RaisePropertyChanged("SavedEmp");
}
}
Is there a way we can refresh the listbox data when moved from View2 to View1 again ?
Communication between dependent views can be accomplished using a Messenger-style object. An implementation of this object comes standard with the MVVM Light toolkit if you are making use of it. The pattern consists of one object registering with the messenger to receive messages of a given type at a provided callback, and another object dispatching a message of that type. The messenger maintains the lists of addressees for these messages and delivers them accordingly as parameters to the callback function provided by the recipient. A sample implementation using MVVM Light's messenger follows:
// Message container
public class AccountChangedMessage : GalaSoft.MvvmLight.Messaging.GenericMessage<Account>
{
public AccountChangedMessage(Account a) : base(a) { }
}
// Dependent ViewModel
public class AccountsViewModel : GalaSoft.MvvmLight.ViewModelBase
{
public AccountsViewModel()
{
MessengerInstance.Register<AccountChangedMessage>(this, OnAccountChanged);
}
private void OnAccountChanged(AccountChangedMessage msg)
{
// TODO: Rebuild bound data
}
}
// Initiating ViewModel
public class AccountEditViewModel : GalaSoft.MvvmLight.ViewModelBase
{
public void SaveAccount()
{
_accountService.Save(_account);
MessengerInstance.Send(new AccountChangedMessage(_account));
}
}
In a sense, this is akin to raising events and registering listeners for those events, but the model is very powerful and much more disconnected, so please use it as sparingly as possible, as this does create a maintenance concern for programmers who come behind you and attempt to follow control flow.

Is it possible to have a view and viewmodel without a model?

When I read this line:
The viewmodel exposes not only models, but other properties (such as state information, like the "is busy" indicator) and commands.
http://www.codeproject.com/Articles/100175/Model-View-ViewModel-MVVM-Explained
I am wondering whether current settings on the view should be considered a property of the view or part of the state and placed in a view model.
For example I currently have a preferences window bound to a view model containing the current colors with a bunch of color pickers bound to the view model. Commands then cancel changes and reapply the old settings if ok or cancel are clicked.
Should the current colors be properties on the view instead or is their current location ok?
public class PreferencesWindowViewModel:DependencyObject
{
private DelegateCommand updatePreferencesCommand;
public ICommand UpdatePreferencesCommand
{
get { return updatePreferencesCommand; }
}
private DelegateCommand cancelCommand;
public ICommand CancelCommand
{
get { return cancelCommand; }
}
public Color HighValuePenColor
{
get { return (Color)GetValue(HighValuePenColorProperty); }
set
{
SetValue(HighValuePenColorProperty, value);
}
}
I like them to be on the view model. For the simple reason that this functionality is testable in a unit testing harness. If they were on the view you would have to jump through so many more hoops to get it tested. In my opinion, the view model should contain most of the presentation logic. Colors and their relation to certain application states belong in that category of code.

C# MVVM: Adding new ViewModel (strict non-exposed Model design)

I've been working on an MVVM application in C# but consistiently run into some problems when working with the collections of ViewModels my View digests. Specifically, they all tend to relate to the issue of the Model being a private member of the ViewModel.
An example of this is creating new ViewModels (as requested by the View). For some preamble (although you might not need these to help me) here are example Model and ViewModel classes:
Private Class Model()
{
public string Name { get; set; }
}
Public Class ViewModel()
{
Private Model _Model;
Public Void ViewModel(Model model)
{
_Model = model;
}
Public String Name
{
get
{
return _Model.Name;
}
set
{
_Model.Name = value;
}
}
}
The entire model is never directly exposed as a public member of the ViewModel. The MainWindowViewModel handles collections of Models (private, the view cant see these) and ViewModels (public for View digestion):
Public Class MainWindowViewModel
{
Private List<Model> _NamesModel;
Private ObservableCollection<ViewModel> _NamesViewModel;
Public Void MainWindowViewModel()
{
//Lets pretend we have a service that returns a list of models
_NamesModel = Service.Request();
foreach(Model model in _NamesModel)
{
ViewModel viewmodel = new ViewModel(model);
_NamesViewModel.Add(viewmodel);
}
}
Public ObservableCollection<ViewModel> NamesViewModel
{
get
{
return _NamesViewModel;
}
}
}
Now thats the preamble but now I have a problem. How do I add a new ViewModel? Do methods within my view create a new ViewModel and populate that? Being a purist, I'm assuming the View should not be allowed to create or populate Models at all. Should my ViewModel contain a constructor that accepts nothing (i.e. no underlying model) and instead creates a blank to populate?
These kinds of issues keep coming up with a "pure" MVVM approach. I've had to create a public method in my ViewModel (bool compare(Model model)) that will compare a model (ready for deletion etc.) to it's internal one. If the models were publicly exposed (breaking purity) then it would be much easier to do stuff like find the ViewModel thats connected to a Model.
I can sympathize with some of those problems. I recently wrote an MVVM application where similar questions came up frequently. One of the tricks is to decide - definitively - which class is going to be responsible for Model instances. Do you want it to be your MainWindowViewModel? Or your NameViewModel? You don't want to share the responsibilities of creating/deleting the model between both of those classes; you'll have quite a logistical nightmare.
Secondly, even a "pure" MVVM approach doesn't dictate that you can't expose the model publicly. You said yourself that doing so would save you a lot of headache: DO IT. MVVM dictates only that the ViewModel has no knowledge/access of the View. There are many "official" MVVM examples that go so far as to implement their Model using the INotifyPropertyChanged interface, and bind directly to properties on the Model.
Personally, I think I would dictate control of the NameModel to the NameViewModel. This means that you should remove the list of NameModels completely from the MainWindowViewModel. If you want to give the NameViewModel an optional constructor which takes a Model, that would be fine too.
I'm a fan of this approach:
public NameViewModel : ViewModelBase
{
public NameModel Model
{
get { /* get stuff */ }
set { /* set stuff */ }
}
// Default constructor creates its own new NameModel
public NameViewModel()
{
this.Model = new NameModel();
}
// Constructor has a specific model dictated to it
public NameViewModel(NameModel model)
{
this.Model = model;
}
//Model wrapper properties
public String Name
{
get { return Model.Name; }
set { Model.Name = value; }
}
}
and...
public class MainWindowViewModel
{
Private ObservableCollection<ViewModel> _NameViewModels;
Public Void MainWindowViewModel()
{
//Lets pretend we have a service that returns a list of models
var nameModels = Service.Request();
foreach(Model model in nameModels)
{
ViewModel viewmodel = new NameViewModel(model);
NameViewModel.Add(viewmodel);
}
}
Public ObservableCollection<ViewModel> NameViewModels
{
get
{
return _NameViewModels;
}
}
}
In this way your MainWindowViewModeldoesn't keep an entirely separate copy of the Models; it only tracks the NameViewModels. Each NameViewModel is responsible for its own underlying model, while still making the option available to have a specific model passed to it during construction.
All the creation-related issues can be resolved with introduction of factory design pattern. The factory will take care of creating view models basing on model that was provided.
public class MainWindowViewModel
{
private List<Model> _NamesModel;
private ObservableCollection<ViewModel> _NamesViewModel;
private IViewModelFactory factory;
public void MainWindowViewModel(IViewModelFactory factory)
{
//Lets pretend we have a service that returns a list of models
_NamesModel = Service.Request();
_NamesViewModel = factory.CreateNamesViewModels(_NamesModel);
}
public ObservableCollection<ViewModel> NamesViewModel
{
get
{
return _NamesViewModel;
}
}
}
What is more, you could even get rid of Service dependency in view model and move it to the factory itself, thus reducing the need to keep model in view model (admittedly though, removal of model might not work in more complex scenarios):
public ObservableCollection<ViewModel> CreateNamesViewModels()
{
var models = Service.Request();
return new ObservableCollection(models.Select(m => new ViewModel(m)));
}
Also, your main window view model can expose commands that utilize factory to create any new instances. This way, no model is leaking to view and also no creation details are exposed (since commands will hide actual implementation).

Categories