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.
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 trying to understand how WPF binding works in junction with MVVM and Entity Framework. So far I understand databinding as a concept related to properties. However, when it gets to EF I lose understanding of which objects to use to define the Model for database. For instance, I have a Model class for a Category:
public class Category : INotifyPropertyChanged
{
string _CategoryId;
public string CategoryId
{
get
{
return _CategoryId;
}
set
{
if (_CategoryId != value)
{
_CategoryId = value;
RaisePropertyChanged("CategoryId");
}
}
}
string _CategoryName;
public string CategoryName
{
get
{
return _CategoryName;
}
set
{
if (_CategoryName != value)
{
_CategoryName = value;
RaisePropertyChanged("CategoryName");
}
}
}
/// <summary>
///
/// </summary>
/// <param name="prop"></param>
void RaisePropertyChanged(string prop)
{
if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); }
}
public event PropertyChangedEventHandler PropertyChanged;
}
and POCO version:
public class CategoryPoco
{
public CategoryPoco() { }
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
Properties of the non Poco class in my understanding can be then used in databinding. However, I also need to build the database context model:
public DbSet<Category> Categories { get; set; }
Now here is where I lose my understanding, do I use Poco or non-Poco classes when building the context model?
How do I match the two classes when I start exchanging data with the Database?
You use the "POCO version" to build the context model for your database. If you will, POCO is just defined as
Plain Old CLR Object.
Just a normal class, no attributes describing infrastructure concerns or other responsibilities that your domain objects shouldn't have.
so technically, your Category is also considered as POCO. POCO doesn't have a different meaning when used with MVVM or EF. EF just uses those objects to map it back to the database.
In your Category class, I normally don't create another Model class just to have that INotifyPropertyChanged. It's more flexible and clear that your Category class should be called CategoryViewModel.
If I read your code and I see an INotifyPropertyChanged interface where WPF uses it also for DataBinding, then I would be against it as you are now using Model -> View pattern without the ViewModel as your middleman. (Assuming you use category as your binding source)
If you decided that you need to extend Category class, then I would suggest to use T4 template to generate your POCO Classes as a partial class, and create another partial class that implements INotifyPropertyChanged or add more properties that are not in the columns of a given table e.g., CategoryStatus, CategoryDescription and mark those properties with [NotMapped] attribute.
That way you don't have to do matching between the two classes and mostly your Model is already setup in the ViewModel to communicate it back with EF. You also have the flexibility to add more functionality to the object, which complies with the Open-Closed design principle.
I'm primarily from an ASP.Net background with some MVC. I've also done a little Silverlight and MVVM, however I'm now about to move into Winforms which I have very little experience of, so I'm wondering how to tackle MVP.
Typical MVP samples show the presenter setting a view property (via some kind of IView interface), with the concrete view putting that property value into a textbox for example. Instead of this archaic approach, can one utilise INotifyPropertyChanged in MVP, and if so how? A very quick example would be really useful!
If I was to create a model that implemented INotifyPropertyChanged then isn't this more like MVVM? (i.e. the presenter updates the model, and via the magic of INotifyPropertyChanged the view gets updated). Yet everywhere I've read about MVVM and Winforms, people say it isn't suitable. Why? My understanding is that you can databind just about any control's property, so what's Winforms missing? I'm trying to understand the shortcomings of databinding in Winforms compared to WPF, and why MVVM can't be used, as it seems simpler to implement than MVP.
Thanks in advance
Andy.
I have just checked up how data binding in WinForms uses INotifyPropertyChanged.
The data binding through the BindingSource does really support INotifyPropertyChanged if the DataSource object of the BindingSource or model property corresponding to DataMember implements this. You can use M. Fowlers supervising presenter / controller to full extent here:
You don't even need a hand-written code, the BindingSource synchronizes the view with the model properties in both directions (model -> view and view -> model), and if the model supports INotifyPropertyChanged then the view will be updated automatically.
The code constructs I have used so far:
During view initialization:
this.bindingSource.DataSource = this.presenter;
Designer-generated code:
this.textBoxPhone.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.bindingSource, "Model.Phone", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
The model class:
public class Customer : INotifyPropertyChanged
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
if (_firstName == value)
return;
_firstName = value;
NotifyPropertyChanged("FirstName");
}
}
private string _lastName;
public string LastName
{
get { return _lastName; }
set
{
if (_lastName == value)
return;
_lastName = value;
NotifyPropertyChanged("LastName");
}
}
private string _company;
public string Company
{
get { return _company; }
set
{
if (_company == value)
return;
_company = value;
NotifyPropertyChanged("Company");
}
}
private string _phone;
public string Phone
{
get { return _phone; }
set
{
if (_phone == value)
return;
_phone = value;
NotifyPropertyChanged("Phone");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
The presenter class:
public class CustomerPresenter
{
public CustomerPresenter(Customer model)
{
if (model == null)
throw new ArgumentNullException("model");
this.Model = model;
}
public Customer Model { get; set; }
public ICustomerView View { private get; set; }
}
Try to find examples of Supervising Controller MVP flavor, I use that with WinForms, very successfully I would say. The entities support INotifyPropertyChanged, presenter binds them to the view, and presenter subscribes to the PropertyChanged event so that it knows when view changed something (dirty checking). View is responsible only for binding data, all other functionality is moved to the presenter.
You don't miss anything. MVVM is very suitable with WinForms. Microsoft only encoureges the use of WPF and MVVM pattern with it.
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
I have a UserControl with multiple fields that I would like to have bound to a BindingSource. I would also like the UserControl to expose some BindingSource property so that it can be dropped on a Form and be bound to the BindingSource on the form. Is there an easy way to do this? I realize that I can rebind all of the controls of the UserControl in its BindSource setter. But this seems wrong. Is there some BindingSource Proxy that will let me link the BindingSource in the user control to the BindingSource in the form?
As per your question, I can hardly get what you intend to do. Thus I will try my best to provide you with, I hope, interesting information on that matter.
First, let's consider the following UserControl in a Customer management software project.
public partial class CustomerManagementUserControl : UserControl {
public CustomerManagementUserControl() {
InitializeComponent();
_customerBindingSource = new BindingSource();
}
public IList<ICustomer> DataSource {
set {
_customerBindingSource.DataSource = value;
}
}
private BindingSource _customerBindingSource;
}
Second, let's consider the following Form which should be your Customer management form.
public partial class CustomerManagementForm : Form {
public CustomerManagementForm() {
InitializeComponent();
_customerUserControl = new CustomerManagementUserControl();
_customerUserControl.Name = #"customerUserControl";
}
private void CustomerManagementForm_Load(object sender, EventArgs e) {
// CustomersFacade is simply a static class providing customer management features and requirements.
// Indeed, the GetCustomers() method shall return an IList<ICustomer>.
// The IList type and typed IList<T> are both intended to be bindable as a DataSource for DataBinding.
_customerUserControl.DataSource = CustomersFacade.GetCustomers();
this.Controls.Add(_customerUserControl);
}
private CustomerManagementUserControl _customerUserControl;
}
If you're expecting to use CustomerManagementUserControl.DataSource property from within the Property window, please consider adding the following on top of your property definition.
[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")]
This is one way of doing what I guess you might want to do. On the other hand, if what you wish to do is to get the as most abstract as possible by setting a different type of object as your UserControl.BindingSource.DataSource property, then you will have to write a method which could detect the type of the object passed, then binding the properties accordingly. A nice way you could go, perhaps, is by Reflection, if you're comfortable working with it. In any possible way you may imagine working with such polymorphism features, you will have to write yourself an interface that all of your bindable objects will have to implement. This way, you will avoid unknown property names, and when will come the time to bind your UserControl's controls, you will be able to bind the correct property to the correct control and so forth.
Let's try the following:
public interface IEntity {
double Id { get; set; }
string Number { get; set; }
string Firstname { get; set; }
string Surname { get; set; }
long PhoneNumber { get; set; }
}
public interface ICustomer : IEntity {
}
public interface ISupplier : IEntity {
string Term { get; set; }
}
public sealed Customer : ICustomer {
public Customer() {
}
public double Id { get; set; }
public string Number { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
public long PhoneNumber { get; set; }
}
public sealed Supplier : ISupplier {
public Supplier() {
}
public double Id { get; set; }
public string Number { get; set; }
public string Firstname { get; set; }
public string Surname { get; set; }
public long PhoneNumber { get; set; }
public string Term { get; set; }
}
Considering the above code, you could use the DataSource property of your UserControl to bind with an IEntity, so your property could like like this.
[System.ComponentModel.DesignTimeVisible(true), System.ComponentModel.DesignerCategory("CustomerUserControl"), System.ComponentModel.Description("Sets the CustomerUserControl DataSource property")]
public IList<IEntity> DataSource {
set {
_customerBindingSource.DataSource = value;
}
}
That said, if you wish to push even further, you could just expose your UserControl's controls DataBindings properties in order to set them on design-time. Considering this, you will want to expose your BindingSource as a public property either so that you may set it on design-time too, then choose your DataMember from this BindinSource.
I hope this helps you both a little or at least, give you some tracks for further searchings.
I know it's a late answer; however, it might be useful to someone else reading this post.
I have controls on a UserControl that are data-bound. I need to have a BindingSource on the UserControl in order to be able to bind the controls at design time. The "real" BindingSource, however, sits on the Form. In other words, the controls on the UserControl should behave as if they were sitting directly on the form (or on a ContainerControl on the form).
The idea behind this solution is to watch for the DataSourceChanged event of the "real" BindingSource and to assign its DataSource to the local BindingSource when it changes. In order to find the "real" BindingSource I let the Form (or Control) containing it implement the following interface:
public interface IDataBound
{
BindingSource BindingSource { get; }
}
We can watch for the ParentChanged event of a control in order to know when it has been added to a Form or a ContainerControl. The problem here is that this ContainerControl itself might not have been added to the Form (or another ContainerControl) yet at this time. In this case we subscribe to the ParentChanged event of the last parent we find in the parents chain and wait until this last parent has been added, an so on, until we find a Control or Form implementing IDataBound. When a IDataBound has been found, we subscribe to the DataSourceChanged event of its BindingSource.
public partial class MyUserControl : UserControl
{
private IDataBound _dataBoundControl;
private Control _parent;
public MyUserControl()
{
InitializeComponent();
if (LicenseManager.UsageMode == LicenseUsageMode.Runtime) {
_parent = this;
SearchBindingSource();
}
}
private void SearchBindingSource()
{
if (_parent != null && _dataBoundControl == null) {
while (_parent.Parent != null) {
_parent = _parent.Parent;
_dataBoundControl = _parent as IDataBound;
if (_dataBoundControl != null) {
if (_dataBoundControl.BindingSource != null) {
_dataBoundControl.BindingSource.DataSourceChanged +=
new EventHandler(DataBoundControl_DataSourceChanged);
}
return;
}
}
// This control or one of its parents has not yet been added to a
// container. Watch for its ParentChanged event.
_parent.ParentChanged += new EventHandler(Parent_ParentChanged);
}
}
void Parent_ParentChanged(object sender, EventArgs e)
{
SearchBindingSource();
}
void DataBoundControl_DataSourceChanged(object sender, EventArgs e)
{
localBindingSource.DataSource = _dataBoundControl.BindingSource.DataSource;
}
}
If you wanted to do this all automatically you could look for the binding source from the parent form in the load event of your user control or something like that...
Dim components As Reflection.FieldInfo = typ.GetField("components", Reflection.BindingFlags.DeclaredOnly Or Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic)
Dim lstBindingSources As New List(Of BindingSource)
For Each obj As Object In components.Components
Dim bindSource As BindingSource = TryCast(obj, BindingSource)
If bindSource IsNot Nothing Then
lstBindingSources.Add(bindSource)
End If
Next
If lstBindingSources.Count = 1 Then
MyBindingSource.DataSource = lstBindingSources(0).DataSource
End If
If you assign the same object reference as the datasource on two bindingsources, the controls will not be updated consistently on the second bindingsource. Possibly, a compromise to the choices above is the following:
Temporarily add a bindingsource to the usercontrol and use the VS designer to set the bindings to the controls.
bring the designer.vb up in the code editor. Search for all the "DataBindings.Add" lines that were created by the designer. Copy them all to notepad.
delete the bindingsource from the designer and add a bindingsource reference in code. Add a property for the bindingsource with the same name as was used in the designer. In the setter for the property, paste all the lines from notepad above in step 2.
In the Load event of the form, assign the bindingsource of the form to the property on the user control. If the user control is embedded in another user control, you can use the handlecreated event of the parent control to do the same.
There is less typing and less typos because the VS designer is creating all those literal text property names.