How to implement MVVM Custom Control? - wpf

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.

Related

Using WPF design data with the MVVM pattern

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.

Commands across View-Models

I am working on my first WPF/MVVM application, and I have come across a limitation in my knowledge of commands!
Here is my scenario.
I have a window - Customer.xaml.
It houses 2 usercontrols
viewCustomerSearch.xaml
viewCustomerDetails.xaml
Each of THOSE has it's own view model.
So, the hierarchy looks like this:
... Customer.xaml
... ... viewCustomerSearch.xaml
... ... ... viewmodelCustomerSearch.xaml
... ... viewCustomerDetails.xaml
... ... ... viewmodelCustomerDetails.xaml
I understand this to be a 'not uncommon' scenario.
For what it is worth, the user selects a customer by double clicking on a listview line in the viewCustomerSearch.xaml control.
The problem is: I now need to tell the viewmodelCustomerDetails.xaml class which customer the user has just selected. I cannot work this out at all.
Does anyone have any help on where I declare the command I need, how it gets hooked up, where the implementation code fires, etc?
Any help gratefully appreciated,
DS
Typically, to do inter-viewmodel communication, you can either:
Use standard .NET events, and use the parent view model as the mediator - in your case the Customer view model would have references to the 2 child view models, and can subscribe to events, and call appropriate methods on the child view models when the events are published
Use an event aggregator pattern
Frameworks such as Caliburn.Micro and Prism provide an implementation of the event aggregator pattern.
Alternatively, if you don't need completely decoupled view-models, then your Customers.xaml could set its DataContext to an instance of CustomersViewModel. The search view would inherit this data context, would bind it's list view to the list of customers, and would set the SelectedItem property in response to a double click. The detail view DataContext would be bound to the SelectedItem property.
public class CustomersViewModel : ViewModelBase
{
public Customer SelectedItem
{
get { return _selectedItem; }
set { Set(() => SelectedItem, ref _selectedItem, value); }
}
private Customer _selectedItem;
public IEnumerable<Customer> Customers { get; private set; }
}
public class Customer : ViewModelBase
{
private string _name;
public string Name
{
get { return _name; }
set { Set(() => Name, ref _name, value); }
}
...
}

Creating the Model part of MVVM

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

Entity Framework CTP5 Code First, WPF - MVVM modeling

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.

Binding ContextMenu on flattened ViewModel

suppose the following classes:
public class Model
{
public ObservableCollection<A> Items { get; set; }
}
public class A
{
ObservableCollection<B> Data { get; set; }
//... some more properties
}
public class B
{
//..properties
}
The model is bound to a RibbonMenu and should also be used in a context menu. The context menu must be bound to all items of class B in the model. Changes in the model (new items added, items removed, items changed ...) should change both the context menu and the RibbonMenu.
The RibbonMenu works nicely but how is it possible to bind the contextmenu without creating a separate model?
You could create wrapper properties that flatten your A and B entities as needed for the view controls and expose them publicly from Model.
So, for instance, in Model, you have a private backer of ObservableCollection<A>. Then you have a public ObservableCollection<A> that simply returns the private backer for the ribbon to bind to.
Then also have a public ObservableCollection<B> that does whatever it needs to do in its getter to return what you want for the context menu. For example, if you want the distinct Bs across all As, have the getter do a query on all of A's Bs to return the correct list.
Finally, to tell the view that changes were made in Model, implement INotifyPropertyChanged and raise the PropertyChanged event in the setters of your public members.

Resources