I am working on an app where I am trying to use MVVM for the first time. After reading some things, I think I might have misunderstood what goes in the Model.
All my app does right now is make a request to get some data, display it, allow the user to edit it, and save it if changes were made.
Here is an example of my current setup. I read some Employee data, which returns groups of employees ("Managers", "VPs", etc.). Each group contains a list of people. I created an interface to represent the groups:
public interface IEmployeeGroup : INotifyPropertyChanged
{
bool IsDirty { get; set; }
string GroupName { get; set; }
ObservableCollection<IPerson> People { get; set; }
}
public interface IPerson : INotifyPropertyChanged
{
bool IsDirty { get; set; }
string PersonName { get; set; }
int Id { get; set; }
}
I then create concrete EmployeeGroup and Person classes implementing those interfaces. And thats all they do, expose the specified properties.
That is all I have for my model.
My view model implements the below interface:
public interface IEmployeeGroupsViewModel
{
ICommand AddEntryCommand { get; }
ICommand SaveCommand { get; }
ObservableCollection<IEmployeeGroup> EmployeeGroups { get; set; }
ObservableCollection<IPerson> People { get; set; }
}
The view model makes the call to get the actual data, creates the EmployeeGroup and Person objects, and then returns them in properties for the view to bind to. When the user wants to save his changes, the view model makes the call to persist the changes.
Am I putting too much in my view model, which should be in the model instead? Right now my model does nothing, they are just the classes that represent the objects.
If I am off track here, can someone give me some advice? How would I change my above scenario for example?
Thank you.
There's nothing wrong with your approach. You are free to either expose mapped model properties from your view model if they require formatting, or you can expose your model directly from your view model if no changes need to be made.
MVVM is about testability, not pattern purity. As long as what you are doing works, you can always refactor later.
That looks right to me.
I could be wrong, but I don't really see a benefit from making your view model interfaces derive from INotifyPropertyChanged. That seems like unnecessarily coupling together two things that don't really have any intrinsic relationship to one another. I'd just declare the PersonViewModel class (for instance) as:
public class PersonViewModel : IPerson, INotifyPropertyChanged
Related
I have the Expense screen that contains a textbox where I can put the price of an expense. As I have built lot of logic (validation etc.) for this textbox I would like to extract it to a separate control and reuse it on other screens. I'm trying to build it in the mvvm style. Here's what I have for now:
ExpenseView
<page>
<Label Text={Binding Date} />
<wpfControls:CurrencyTextBoxView ViewModel="{Binding PriceViewModel}" />
</page>
ExpenseViewModel
public class ExpenseViewModel : INotifyPropertyChanged
{
private ExpenseModel Model { get; }
public string Date
{
get { return Model.Date.ToString(); }
set
{
Model.Date = DateTime.Parse(value);
RaisePropertyChanged();
}
}
private CurrencyTextBoxViewModel _priceViewModel;
public CurrencyTextBoxViewModel PriceViewModel
{
get { return _priceViewModel; }
set { _priceViewModel = value; }
}
}
ExpenseModel
public class ExpenseModel
{
public DateTime Date { get; set; }
public decimal Price { get; set; } // This is the bit I don't know how to implement correctly
}
CurrencyTextBoxView
<control>
<TextBox Content={Binding Price} />
</control>
CurrencyTextBoxViewModel
public class CurrencyTextBoxViewModel : INotifyPropertyChanged
{
private CurrencyModel Model { get; }
public string Price
{
get { return Model.Price.ToString(); }
set
{
Model.Price = decimal.Parse(value);
RaisePropertyChanged();
}
}
}
CurrencyModel
public class CurrencyModel
{
public decimal Price { get; set; }
}
And now the problem is: I need to have the Price property in my ExpenseModel as well (as it's being saved in the db). I don't want to have the Date property in my CurrencyModel (as not always it makes sense).
Should I keep the CurrencyModel inside of my ExpenseModel? How would I update it efficiently when the text in the currency textbox would change?
Also the ExpenseModel is located in different project than the rest of my classes and I wouldn't like to make this project dependend on the project with the CurrencyModel.
Should I listen to PropertyChanged events from CurrencyTextBoxViewModel and update the ExpenseModel.Price whenever the CurrencyTextBoxViewModel.Price string changes? I like the way my view models act as parsers of models for views (the Date property example). Is there any way to implement the PriceViewModel so that its getter returns data straight from the ExpenseModel (so it acts as a parser)?
I know there are lot of ways to implement it but I'm looking for the most mvvm-consistent one. Also, I'm not sure if I have implemented the whole pattern correctly?
As for Date property, place it only on the view model if it needs no serialization.
How I would do:
If you want to reuse your CurrencyTextBox, I would not tie the control with the model. No CurrencyModel is needed. Prepare a DependencyProperty (say CurrencyText) on CurrencyTextBox. The view goes as:
<xxx:CurrencyTextBox CurrencyText="{Binding Currency}" />
You can omit CurrencyTextBoxViewModel because the CurrencyText can be bound to the internal TextBox.Text (or, just update relevant property on the view model). Anyway, with two-way binding, when CurrencyText is updated, ExpenseViewModel.Currency is also update, and here you can update your model.
I think it is ok to listen event of the model because the view model live shorter than the model. However you should block propagate event firing if the new value is the same as the old one.
The model serves as the origin of data and does business logic. The view model is just a shadow of the model, thus it is usually thin. Consider using some MVVM frameworks to get a sense of that.
I am attempting to build an application that will show different columns in the same XamDataGrid for different Projects. Here is an example:
public class Project
{
public ICollection<Person> People { get; private set; }
public string DisplaySpec { get; private set; }
}
public class Person{
{
public Name Name { get; set; }
}
public class Name
{
... a bunch of dynamic properties that vary by project...
}
I can look up the properties for each Name dynamically with no problem, and if I write Xaml and compile it in the actual executable I can display them. But each project has a different list of fields to bind to, and I want them to be able to inject the field names to display.
Is there any easy manner in which I can allow them to specify the name of the fields that they want to use?
The fields themselves can't be bound. Your best options are to either to auto generate the fields or to have a method in code that would add the fields needed dynamically. If you are looking to have a solution that you can use a binding in XAML with you could put the logic to add the fields into a behavior on the grid that exposes a property that you could bind your list to.
To auto generate the fields you would need to set the AutoGenerateFields on the FieldLayoutSettings to True.
I'm using the MVVM pattern in our WPF application to allow for comprehensive unit testing. The MVVM pattern itself is working great, however I'm struggling to adapt the pattern in a way that means I can use the design-time data support of WPF.
As I'm using Prism the ViewModel instances are generally injected into the constructor of the view, like so
public MyView(MyViewModel viewModel)
{
DataContext = viewModel;
}
Dependencies for the ViewModel are then injected into the constructor, like so
public class MyViewModel
{
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// Read-only properties that the view data binds to
public ICollectionView Rows { get; }
public string Title { get; }
// Read-write properties are databound to the UI and are used to control logic
public string Filter { get; set; }
}
This is generally working really well except when it comes to design data - I wanted to avoid compiling design-data specific classes into my released assembly and so I opted to use the {d:DesignData} approach instead of the {d:DesignInstance} approach, however in order for this to work correctly my ViewModel now needs to have a parameterless constructor. In addition, I also often need to change additional properties either to have setters or to be modifiable collections in order to be able to set these properties in XAML.
public class MyViewModel
{
public MyViewModel()
{
}
public MyViewModel(IFoo foo, IBar bar)
{
// ...
}
// Gets and sets the model represented in the view
public MyModel { get; set; }
// My read-only properties are no longer read-only
public ObservableCollection<Something> Rows { get; }
public string Title { get; set; }
public string Filter { get; set; }
}
This is worrying me:
I have a parameterless constructor that is never intended to be called and isn't unit tested
There are setters for properties that only the ViewModel itself should be calling
My ViewModel is now a jumbled mixture of properties that should be modified by the view, and those that shouldn't - this makes it tricky to tell at a glance which piece of code is responsible for maintaining any given property
Setting certain properties at design time (e.g. to see styling on the Filter text) can actually end up invoking ViewModel logic! (so my ViewModel also needs to be tollerant of otherwise mandatory dependencies being missing at design time)
Is there a better way to get design-time data in a WPF MVVM application in a way that doesn't compromise my ViewModel in this way?
Alternatively should I be building my ViewModel differently so that it has more simple properties with the logic separated out somewhere else.
First, I would recommend you to have a look at this video where Brian Lagunas provides several best practices about MVVM. Brian is - at least - involved in the development of Prism, as his name appears in the nuget packages information. Didn't check further.
On my side I only use bits of Prism, and my Model and ViewModel always offer blank constructors (like what Brian shows), the data context is assigned in the view's XAML, and I set the properties values like :
<MyView.DataContext>
<MyViewModel />
</MyView.DataContext>
and
public void BringSomethingNew()
{
var myView = new View();
(myView.DataContext as ViewModel).Model = myModel;
UseMyView();
}
Another benefit with this approach is that the ViewModel is created once, with the same path at design and run time, so you create less objects and save GC efforts. I find this elegant.
With regards to the setters, the design data will still work if you make them private, like:
public string MyProp { get; private set; }
Ok, customize it to manage NotifyPropertyChange at your convenience, but you've got the idea.
Now, I don't have yet a solution to manage ObesrvableCollections (I face the same problem, although putting multiple values in XAML sometimes work... ???), and yes, I agree that you have to manage the case when the properties are not set, like setting default values in the constructor.
I hope this helps.
I too have worked with NUnit testing with WPF and MVVM implementation. However, my version is reversed from yours. You are creating the view first, then creating the model to control it.
In my version, I create the MVVM model FIRST and can unit test it till the cows come home and not worry about any visual design... if the model is broken, so too will the visual implementation.
in my MVVM model, I have a method to "GetTheViewWindow". So, when I derive from my MVVM baseline, each view model has its own view its responsible for. So via a virtual method, each instance will do its own new view window when being applied for production.
public class MyMVVMBase
{
private MyViewBaseline currentView;
public MyMVVMBase()
{ // no parameters required }
public virtual void GetTheViewWindow()
{ throw new exception( "You need to define the window to get"; ) }
}
public class MyXYZInstanceModel : MyMVVMBase
{
public override void GetTheViewWindow()
{
currentView = new YourActualViewWindow();
}
}
Hope this helps as an alternative to what you are running into.
I have my model all setup for my WPF application and working with entity framework ctp5 code first, here's a sample model class:
public class Task
{
public int ID { get; set; }
public int Index { get; set; }
public string Content { get; set; }
public int Indentation { get; set; }
public DateTime Start { get; set; }
public decimal Effort { get; set; }
public decimal CompletedEffort { get; set; }
public decimal Cost { get; set; }
}
What would be the recommended way to build my view model? My view models will implement INotifyPropertyChanged, I do not want the model classes to have any UI specific code - so that they can be easily reused in other apps.
Should I make all of the model properties virtual then override them in the view model? (seems like a lot of unnecessary coding...) Would EF code first play nice with this type of format?
Edit
This is a somewhat similar question In MVVM should the ViewModel or Model implement INotifyPropertyChanged? however, the only solutions appear to be adding in what I consider to be UI logic into the model. Perhaps I can add some sort of delegate to the model and hook into that from the viewmodel, which will in turn use INotifyPropertyChanged... something like this?
public class Task
{
public delegate void HandleChange(string propertyName);
public HandleChange ChangeHandler;
public int ID
{
get
{
return ID;
}
set
{
if(ID != value)
{
ID = value;
ChangeHandler("ID");
}
}
}
...
What I am doing is to make an instance of my model class to a property in the ViewModel and then implement INotifyPropertyChanged directly on the Model for the Model properties and on the ViewModel only for the Model instance, like so:
public class Task : INotifyPropertyChanged
{
// Implementation of INotifyPropertyChanged
// Raising the PropertyChanged event in the Setters of all properties
}
public class TaskViewModel : INotifyPropertyChanged
{
private Task _task;
public Task Task
{
get
{
return _task;
}
set
{
if (_task != value)
{
_task = value;
RaisePropertyChanged("Task");
}
}
}
// INotifyPropertyChanged implementation
}
Then in XAML I bind directly to Model properties, for instance:
<TextBox Text="{Binding Task.Content}" />
(TaskViewModel would be here the DataContext for the View.)
I do this mainly to avoid this "lot of unnecessary coding" that you mention, and I could not find a drawback. (I make my model persistent with EF Code-First too.)
I know this is an old thread, but I was googling about this very topic and stumbled upon this blogs.msdn.com article: http://bit.ly/iE3KHI
In short, starting with CTP 4 of EF CodeFirst there is a new property of the CodeFirst dbSet object .Local. .Local is an ObservableCollection that implements INotifyPropertyChanged. So if you have a code first dbcontext that exposes a DbSet(Of Task) called Tasks you can set your forms data context to Tasks.Local.
I need someone to confirm what I am seeing before I may a change to the domain of the application because of this issue. The issue is that when databinding against interfaces that inherit from one another, you can not see the properties on the base interfaces.
I am working on a WinForms application that uses databinding. This is in .net3.5 and no I can not use wpf.
Anyways, I have a setup something like this.
public interface IClassOne
{
string Prop1 { get; set; }
}
public interface IClassTwo : IClassOne
{
string Prop2 { get; set; }
}
public abstract class ClassOne : IClassOne
{
public string Prop1 { get; set; }
}
public class ClassTwo : ClassOne, IClassTwo
{
public string Prop2 { get; set; }
}
The base class would hold common properties and logic. The base interface would have those common properties on it so they would have to be implemented on each concrete implementation.
If I was databinding to my class structure above, I would be binding to IClassTwo. The problem is when I databind to IClassTwo, I can not see Prop1 in any of the designer operations for WinForms. Even if I get around that limitation and get a control to be bound to Prop1, it does not work.
However if I bind two ClassTwo, then databinding works.
I do not want to deal with the concrete classes because that would make using mocks and testing too hard. I also do not want to put everything on IClassTwo because I would have to repeat code when I make another concrete implementation.
What I need to know is if this truly doesn't work. If you know why, that would be a bonus.
Thank you
Tony
http://social.msdn.microsoft.com/Forums/en-US/winformsdatacontrols/thread/4151e6b6-44f7-45e2-9a8e-92c4f8539095/?prof=required
Here is a snippit of what is posted on MSDN as to why this doesn't work. The poster who wrote this goes by "franking".
No, it's not possible to bind to an interface! BindingSource offers some help to use a type as data source. Internally it will instantiate a BindingList<> instance using the type information. Also adding new items will work, but AddNew() will fail unless you subscribe the AddingNew event.