I'm currently working on my first MVVM application using Caliburn.Micro. If understand correctly the concept of Loosely Coupled, I must be able to extract every class of my project, isolated it on a blank solution, and it must compile without problems because there is no direct reference to others classes, right?
So my question is this:
Where is the place to create the viewmodels for distinct views and mantain the loosely coupled model?
I ask this because many examples on the web do something like this:
public class ShellViewModel : Conductor<IScreen>.Collection.OneActive {
int count = 1;
public void OpenTab() {
ActivateItem(new TabViewModel {
DisplayName = "Tab " + count++
});
}
}
Where TabViewModel is the viewmodel for the desired view. But here, shellviewmodel is tightly coupled to TabViewModel
Other option i've try is to create some sort of menu class like this:
class MenuItem
{
public string Title { get; set; }
public Type ViewType { get; set; }
}
and use it like this:
new MenuItem(){Title="My menu",ViewType=typeof(ProductosViewModel)}
And use a generic creation procedure, but again this class is coupled with ProductosViewModel.
So what other options do i have? Or should i forget about strict loosely coupled?
Thank you!
Related
I am trying to understand and implement different UI patterns in .NET to see the pros and cons and where they suite best.
I understand the main concept but I was creating an app and a question appeared.
Say we have a class Customer, which represents the core Information of a customer.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
public string PhoneNumber { get; set; }
}
Now, if I create a WebView or WebForm to show all customers I can use this class to set as source f.e. to a DGV, being able to show all properties above.
But then I want to show for example a View/Form with the Revenue history of each customer.
So there is a class CustomerRevenue like
public class CustomerRevenue
{
public Revenue ActualYearExpectedRevenue { get; set; }
public IList<Revenue> RevenuePerYearList { get; set; }
public decimal ActualYearProjectedRevenue => CalculateYearProyection();
public decimal CalculateYearProyection(int year)
{
var daysInYear = DateTime.IsLeapYear(year) ? 365 : 366;
var actualYearRevenue = RevenuePerYearList.SingleOrDefault(x => x.Year == year);
var dayNumber = DateTime.Now.DayOfYear;
var projection = ((actualYearRevenue.Amount * daysInYear) / dayNumber);
return projection;
}
}
Here, to set RevenuePerYearList we need some time, since let's say we sell a lot and have a huge list of sells with huge lists of articles, so the calculation needs some time.
So now my question:
Should I then have "concrete" classes for each view/model with the data I want to show, i.e. here I would have apart of Customer class, say a CustomerRevenueModel
public class CustomerRevenueModel
{
private readonly CustomerRevenue _customerRevenue = new CustomerRevenue();
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string PostalCode { get; set; }
public CustomerRevenue CustomerRevenue
{
get { return _customerRevenue; }
}
}
}
which has (maybe) different properties, so I need to load this "heavy" properties when needed
or
should I stay with only one class (I mean, a customer always has a revenue) and leave the properties "empty"?
The first option makes me have a lot of classes, one for each view/form I want to show data for (maybe being able to reuse some models in various views/forms) but keeps all clean and in a valid state. And also each class can have it's own logic (domain logic - DDD)
The second option is less classes, less code, but some way I end having a huge (God) class, with all the properties a Customer has and all it's logic (methods). I load only the ones I need, but this appears really bad to me.
The third option is to have the big class with all properties and methods as my (domain)model, and create a "ViewModel" (which contains no methods, only props) each time I need to show sth. like above , using it as source for my GridView. This is the solution with more classes and code (big class + ViewModels + (maybe) DTOs), but also the more organized and SOLID design to my eyes... Here the use of a Mapper like AutoMapper would really help, mapping between objects
But this is the part I'm confused about...
Are these "ViewModels" a bad pattern using MVC or MVP?
Are this the same as the VM in MVVM? Which I Think not, since I've understood VM in MVVM like a "template", but what I talk about appears to me more like DAOs??
Or they don't have nothing to do, are just DAOs
I think I am a bit confused about all the different meanings of Model, ViewModel etc, in the different design patterns.
I am hardly trying to understand right MVC,MVP,MVVM and DDD and I think sometimes I am mixing terms...?
First, try to not "mix" things from different patterns, ViewModels are for MVVM, and you NEED ViewModels if you want to implement MVVM (ASP.Net MVC uses something called ViewModels, but it is not the same than the ViewModels in MVVM design pattern)
The ViewModel is like a model for the View. The ViewModel work is to "convert" the Model(s) to something the View can understand.
You can have one o more models (or none) and use it in the ViewModel, you have a ViewModel for each View.
In your example (a datagridview) you can have a model that will represent the data in a datagridview, a DTO if you want, and you can have a property in the ViewModel, a List and you will fill with data loaded from the database. In the View, you will bind that property (the list) to the dgv datasource.
Think that the ViewModel is something like the code behind of the view, but you are working with properties and commands that will be binded to controla in the view.
I am little confuse on the ViewModel design with Inheritance.
Scenaro:
I have a datamodel and multiple viewmodels of User Enity. I am using ADO.Net to fetch from DB bind to datamodel. And the datamodel can be passed to different ViewModel.It seems Ok with one or two views. But When number of my Views increases, I need different ViewModels. Also I want to avoid redundant fields in my ViewModel. And I create a UserBaseModel. So all ViewModel inherit from it
Problem:
I have password and confirm password fields for UserSetting Views and UserRegistration view and I create UserSettingViewModel and UserRegistrationViewModel. And I dont think other viewmodel do not require this fields. I dont want to define the fields in UserBaseModel and also I dont want to define multiple times for the same fields in both ViewModels.
Is there any alternative? Suggestions and advices are welcome
Since C# doesn't support multiple inheritance you can't derive the models from a second base model. You basically end up with creating another base view model which derives from UserBaseModel and contain the password properties:
public UserBaseModelWithPassword : UserBaseModel
{
public string Password { get; set; }
public string PasswordConfirm { get; set; }
}
Then you can derive UserSettingViewModel and UserRegistrationViewModel from it.
Little more thoughts give me another solution.
public PasswordModel
{
public string Password { get; set; }
public string PasswordConfirm { get; set; }
}
public UserSettingViewModel
{
public PasswordModel Password { get; set; }
}
I'm facing a problem since I have a view where all the controls are created at runtime.
I'm trying to bind each of them to my viewmodel, but I think I might have the wrong approach.
We'll use a combobox as an example.
My model to contain the data:
public class ModelToContainTheData
{
public string BuildType { get; set; }
public string Section { get; set; }
public string QuestionID { get; set; }
public string Values { get; set; }
public int Selectable { get; set; }
public DateTime Changed { get; set; }
public string User { get; set; }
}
I then create an array of this model, bind the following method to ComboBox.SelectionChanged
private void ComboboxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var box = sender as ComboBox;
foreach(ModelToContainTheDatamodel in currentSettingsModel)
{
if(model != null)
if(model.QuestionID == box.Name)
{
model.Changed = DateTime.Now;
model.Values = box.SelectedValue.ToString();
model.User = "wc_set";
}
}
}
What I would then like to do is bind the array to the viewmodel. Is there any proper way to do this, or do I need to change my approch entirely?
I figured an ObservableCollection might be the way to go, but I couldn't figure out how I'd then bind it.
There is a bit of mixing up going on in your example. I would recommend to get familiar with the MVVM pattern and then get back to your actual problem. The main idea of MVVM (and I suppose you're aiming at MVVM, as your talking about models, views, and ViewModels) is to decouple views and models. Subscribing to UI events (like SelectionChanged) is to be avoided in MVVM.
You are coupling UI and models tightly, especially by matching model properties with UI control properties (model.QuestionID == box.Name).
I will briefly explain what the general concept would be to solve your problem in a MVVM way:
Your models need to draw the complete picture of what is going on in the domain-world of your app. You've got questions, etc., etc., all of this needs to be represented in the domain logic, also called business logic. You'd have a couple of classes. I just make something up from what I understand from your code, no idea whether it matches what you're trying to do...
// Model for an answer ('Value' in your question
public class Answer { ... }
// Model for a question containing possible answers and the actual answer
public class Question
{
private Answer _answer;
public List<Answer> PossibleAnswers { get; set; }
public Answer Answer { get; set; }
public DateTime Changed { get; set; }
public Question()
{
// Acquire the values from wherever
PossibleAnswers = ...;
}
}
Note that the model is entirely standalone, this means it doesn't know anything about the ViewModel or the View.
Now you create a ViewModel for this model which will expose properties in a way that a view can be bound to the data you want to display. In the easiest case you just relay the properties of the model. Use a proper base class which implements INotifyPropertyChanged. There are lots of MVVM frameworks for this, like MVVMLight:
public class QuestionViewModel : NotifyingObject
{
public Question Model { get; private set; }
public List<AnswerViewModel> PossibleAnswers
{
get { return _possibleAnswers; }
}
public DateTime Changed
{
get { return Model.Changed; }
public AnswerViewModel Answer
{
get { return _answer; }
set
{
_answer = value;
// Set properties on your model which are effected
_model.Answer = _answer.Model;
_model.Changed = DateTime.Now;
// Raise property changed events. They are needed
// to update the UI
RaisePropertyChanged("Answer");
RaisePropertyChanged("Date");
}
}
public QuestionViewModel(Question model)
{
Model = model;
_possibleAnswers = Model.Answers.Select(a => new AnswerViewModel(a));
}
}
public class AnswerViewModel { ... }
As you see, the ViewModel knows about the Model and relays changes in it's own values to the model. But again, the ViewModel doesn't knwo anything about the View.
The View binds to the ViewModel, using WPF magic. You just need to make sure that the DataContext of your View is set to the ViewModel. There are a number of ways to achieve this, again MVVM frameworks like MVVMLight offer ways to do that. I will only show the usage here. Say you have ComboBox:
<ComboBox ItemsSource="{Binding PossibleAnswers}"
SelectedItem="{Binding Answer}" />
That's it. WPF takes care of the rest.
In a more complex scenario, where you have collections on your model which can change actively, i.e. not only by the user in the UI but also for other reasons, it gets a little more complex. Then you need to synchronize the collections on the Model and on the ViewModel.
This is more advanced stuff which you will run into eventually. If you're getting there, this answer might help you:
SO Answer on Collections on Model and ViewModels
This answer might be a little bit overwhelming at first, so I recommend to dig into MVVM using one of the many very good resources on the web. Use my answer as a guideline to find a solution for your actual problem. If you understand this answer with the help of the MVVM tutorials and docus out there, you'll be fit to solve your problem in a proper MVVM fashion.
EDIT: Regarding the dynamic creation of UI elements
What you describe as the dynamic creation of controls is a quite natural concept in WPF and MVVM. The basic idea is to use an ItemsControl which is bound to a collection of ViewModelItems and use DataTemplates to specify how each ViewModel is rendered. There are no limitations, each item can be rendered in a complex control and the layout can be specified through the 'ItemsControl's ItemsPanel property. Things will get clear for you while digging into MVVM and your scenario is a very common thing to solve with MVVM. Just keep your eyes open for WPF's ItemsControl and what you can do with it...
How can I use one view model for many windows in WPF? I need model to be updated from one window only and handle these changes in others (for ex. property 'Locked').
I have one view model incapsulating the most general info that should be used not only on the A (suppose it is 'Company') window but also on windows child window B (suppose it is 'Person'). So the 'General' view model should be determined by A entity but be passes to all children entity. While updating this view model on A window - we should se changes on all B windows.
public partial class A : WindowBase
{
private GeneralViewModel general;
public GeneralViewModel General
{
get
{
return this.general ?? (this.general = new GeneralViewModel ());
}
}
}
public partial class B : WindowBase
{
private GeneralViewModel general;
public GeneralViewModel General
{
get
{
return this.general ?? (this.general = new GeneralViewModel ());
}
}
public B(GeneralViewModel g)
{
this.general = g;
}
}
I wish the model should be updated only in A and B was simply displaying that changes were maid. In case I pass model as it is shown in this code or if I implement 'General' as property with getter and setter changes are not applied.
Thanks for any help.
You could use a singleton-class as your ViewModel.
Example:
public Window()
{
this.DataContext = ViewModel.Instance.
}
EDIT:
public GeneralViewModel
{
public DataType Model
{
get { return DataType.Instance; }
}
}
Now everytime you access the Model in one of your GeneralViewModels, it is locked for all others.
Initialise your view model in a static member somewhere and have the windows return the value as their GeneralViewModel.
In the scenario you mentioned, your GeneralViewModel is a kind of Dependency to both your Window classes and for these purposes you can use some of the available IoC containers or MEF built into .Net 4. You can register your Dependencies including the GeneralViewModel in some application startup event.
Below is some sample code that will make your GeneralViewModel instance to be then located from the container it is registered with (MEF in below case):
[Export(typeof(B))]
public partial class B : WindowBase
{
private GeneralViewModel general;
public GeneralViewModel General
{
get
{
return this.general ?? (this.general = new GeneralViewModel ());
}
}
[ImportingConstructor]
public B(GeneralViewModel g)
{
this.general = g;
}
}
To learn more about MEF,see these articles:
CodePlex
Ten Reasons to use the Managed Extensibility Framework
Managed Extensibility Framework Overview
An Introduction to Managed Extensibility Framework (MEF) - Part I
There are many other DI and IoC containers available as Open Source downloads.
There is no problem if you use MVVM. In this case your ViewModel will correspond to some View which is basically the UserControl and you can place it to as many Windows as you wish.
And When you implement MVVM you should also use INotifyPropertyChanged or ObservableCollections
I am new to MVC (i.e. the last few days) and i would like to know if what i have done is the best way.
I have a view that is a combination of an insert item form with a list details form underneath for a particular entity. As such i kind of need 2 models for the page in order to avoid doing things like #Html.LabelFor(model => model.FirstOrDefault().EventTypeID, "Event Type").
What i have done is set the model to be Tuple<IEnumerable<Event>,Event> that way i have both the single item and the collection of items. Can anyone suggest a less hacky alternative or is this the best way of doing this?
There are 2 solutions.
You should create a different View Model Class (a simple class with both models as properties)
You can assign it to the ViewBag.Model1 ... ViewBag.Model2 ... But this is dynamic so you will have no intellisense and you can get errors at runtime.
You should use a ViewModel like this
public class ViewModel
{
public TypeOfYourModel MyModel1 { get; set; }
public TypeOfYourModel MyModel2 { get; set; }
}
I suggest you create a ViewModel that would contain both objects you want to pass.
public class NewEventViewModel
{
public Event NewEvent { get; set; }
public Event EventDetails { get; set; }
}
You could also use ViewBag, but it is not strongly typed so you would not get IntelliSense.
I would create a Model object just for the view, with 2 properties, one for the single entity and one for the collection, and then you can pass this composed object as the model for the view