Implementing NotifyPropertyChange on EF Generated Models to achieve TwoWay binding - c#

My goal is to do TwoWay binding off a generated EntityFramework model.
What is the best way to implement NotifyPropertyChanged on properties in a generated entity model?
For example, suppose I have this entity from a database:
public partial class Survey
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool Answer { get; set; }
}
I then create a ViewModel...
public class SurveyViewModel : ViewModelBase
{
private Survey _survey = new Survey();
public Survey
{
get { return _survey; }
set
{
_survey = value;
}
}
}
How could I achieve 2 way binding other than writing dependency properties for every single property in the entity model, like so...
//below the declaration of the Survey entity in the viewmodel
public string FirstName
{
get { return Survey.FirstName; }
set
{
Survey.FirstName = value;
NotifyPropertyChanged("FirstName");
}
}
//This works but is very time consuming for large models
Let me know if I'm attempting this wrong...

PropertyChanged.Fody may be what you are looking for:
// Non-auto generated partial class declaration
[ImplementPropertyChanged]
public partial class Survey
{
}

As commented by TyCobb, this question has been asked repeatedly and the result remains the same... here is a summary.
While there are ways pollute your data models with UI accommodating
features such as INotifyPropertyChanged, the MVVM mantra teaches us
that it is the View-Model's job to interact with the UI and the
Data-Model should remain as pure as possible (POCO).
So what? How do we keep to MVVM but avoid the boiler-plate codes of exposing individual properties on the View-Model?
From experience, calling a RaisePropertyChanged is not reserved only for property setters but could be used to manually raise a property changed for a model that has had its own properties modified, thus, cause the UI to update.
Here is a code example...
public class SurveyViewModel : INotifyPropertyChanged
{
private Survey _survey;
public Survey Survey
{
get { return _survey; }
set
{
_survey = value;
RaisePropertyChanged(() => Survey);
}
}
public void ModifySurvey()
{
// Modify a property of the model.
Survey.FirstName = "Modified";
// Make other modifications here...
// Notify property changed
RaisePropertyChanged(() => Survey);
}
}

Related

Nested view model in WPF

Still trying to learn MVVM and WPF here.
I'm trying to create a complex view model EditArticleViewModel. It has some code that is repeated for similar controls and so I've moved the repeating code into another class. Then, I've added several instances of that other class into EditArticleViewModel.
I will set an instance of EditArticleViewModel as my window's DataContext. And I will bind to things like Categories.Items and Subcategories.SelectedItem.
public class CategoryView
{
public ObservableCollection<object> Items { /* */ }
public object SelectedItem { /* ... */ }
}
public class SubcategoryView
{
public ObservableCollection<object> Items { /* */ }
public object SelectedItem { /* ... */ }
}
public class EditArticleViewModel : INotifyPropertyChanged
{
public CategoryView Categories { get; private set; }
public SubcategoryView Subcategories { get; private set; }
public EditArticleViewModel()
{
Categories = new CategoryView();
SubcategoryView Subcategories new SubcategoryView();
}
// Additional properties and methods here
}
As you can see, my EditArticleViewModel class implements INotifyPropertyChanged so that I can notify the visual elements when something has changed.
My question is about how I notify visual elements about changes within CategoryView and SubcategoryView. Is there a way to notify the window about changes within these classes directly? Or must I raise an event from each class and have EditArticleViewModel handle that event in order to send the appropriate notification?
Any tips appreciated.
There should only be one ViewModel per View, with an extend that primary ViewModel can contain other "ViewModels".
So when you set DataContext to your primary ViewModel all the content of it will be have a subscription to NotifyPropertyChanged event, thus implementing INotifyPropertyChanged interface in other derived ViewModel will be notified.
I would suggest implementing a base class with INotifyPropertyChanged interface which you could derive from in your other ViewModels.
By having this alteration you should solve the problem you are having:
public class ObservableViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName]string propName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
}
public class CategoryView : ObservableViewModelBase
{
public ObservableCollection<object> Items { /* */ }
public object SelectedItem { /* ... */ }
}
public class SubcategoryView : ObservableViewModelBase
{
public ObservableCollection<object> Items { /* */ }
public object SelectedItem { /* ... */ }
}
public class EditArticleView : ObservableViewModelBase
{
public CategoryView Categories { get; set; } = new CategoryView();
public SubcategoryView Subcategories { get; set; } = new SubcategoryView();
}
Regarding ObservableCollection. It will notify view to change only when you add/remove items but it does not notify when content is changed. To update view on item content change you should have something like that:
public class GridRowItemViewModel : ObservableViewModelBase // From previous example.
{
private string _sampleProp;
public string SampleProp
{
get
{
return _sampleProp;
}
set
{
_sampleProp = value;
OnPropertyChanged();
}
}
}
And thus your Main ViewModel should look something like this:
public class MainViewModel : ObservableViewModelBase // This is your DataContext.
{
public ObservableCollection<GridRowItemViewModel> GridCollection { get; set; }
}
EDIT: You cannot bind to fields, WPF does not resolve fields. It can only handle properties. So by creating plain fields of child ViewModels you are getting no where. Change these into properties and you will be able to access its content in the View by the property name.

What is the purpose of DataItem in the MVVM light sample code? Why is it implemented like this?

I was given this sample code when creating a new MVVM light(WPF451) project and it made me confusing.
DataItem.cs:
public class DataItem
{
public string Title { get; private set; }
public DataItem(string title)
{
Title = title;
}
}
This class declares a set of properties that is needed in the ViewModel. It's used in the Model layer DataService, which provides data to the VM in its constructor.
DataService.cs
public class DataService : IDataService
{
public void GetData(Action<DataItem, Exception> callback)
{
// Use this to connect to the actual data service
var item = new DataItem("Welcome to MVVM Light");
callback(item, null);
}
}
I thought it would be used in the VM as well to hold properties, like this:
public DataItem Data { get; set; }
but instead, the MVVM light developer decided to re-declare the properties in the VM.
MainViewModel.cs:
public class MainViewModel : ViewModelBase
{
private readonly IDataService _dataService;
private string _welcomeTitle = string.Empty;
public string WelcomeTitle
{
get{ return _welcomeTitle; }
set{ Set(ref _welcomeTitle, value); }
}
public MainViewModel(IDataService dataService)
{
_dataService = dataService;
_dataService.GetData(
(item, error) =>
{
WelcomeTitle = item.Title;
});
}
}
I couldn't understand why they implemented like this. Yes, it reduces redundant INotifyPropertyChanged implemented object so it uses less resource. However, if I had to implement tons of properties to the VM, I'll have to write properties on both VM and DataItem, and also when I want to add or delete properties I'll have to edit both of them.
Couldn't I just hold a DataItem property in the VM? Or am I missing something?
DataItem simply represents the Model in this case. If the Model is an entity that cannot be modified (database auto-generated POCO), this scenario would work.
Yes, you will have to have each applicable Model property in your ViewModel so that it can RaisePropertyChanged, and yes, this is more 'work', but it provides an abstraction between the two.
Some people are okay with modifying the Model to have it implement INotiftyPropertyChanged, others believe the Model shouldn't and all the work should be done in the ViewModel (which is what is being done in this case).

Avoiding logic in setter properties when using NHibernate

I have a design like this:
public class Employee {
//...
}
public class Company {
private IList<Employee> _employees;
public IList<Employee> Employees {
get { return _employees; }
set {
if (_employees == value) {
return;
}
_employees = value;
//Some logic here. Eg:
//Raise PropertyChanged
//Iterate over the new values to suscribe to some events, etc.
}
}
}
when I try to do something like:
var employees = session.Query<Company>().Fetch(x => x.Employees).ToList();
it throws a LazyInitializationException:
illegal access to loading collection
The only workaround I've found is moving the logic to a method, making this method public (and virtual) and calling the method for every instance in employees, but I don't like that since I will be calling that method from my repositories.
Any ideas?
You are mixing fetching data from the database with control logic. I'd recommend fetching the data into simple value objects. Then transform it into your Company and Employee logic-laden classes afterwards. That way you separate data entities from functionality based on that data.
In Nhibernate you collection class should not be exposed to the out side world. Your typical domain would look like this
public class Company
{
public virtual String Id { get; set; }
public virtual ICollection<Employee> Employees { get; protected set; }
public Company()
{
Employees = new List<Employee>();
}
public void AddEmployee(Employee employee)
{
if (Employees.Contains(employee))
return;
Employees.Add(employee);
employee.Company = this;
}
public void RemoveEmployee(Employee employee)
{
if (!Employees.Contains(employee))
return;
Employees.Remove(employee);
}
}
public class Employee
{
public virtual String Id { get; set; }
public virtual String FullName { get; set; }
public virtual Company Company { get; set; }
}
I agree with the first responder who said to user view models and INPC those, but if you want to bind directly to your domain objects, you can inject INPC directly into your domain objects.
Please see this original post from Ayende and this updated one from Ricardo
I guess you are using 'property' as collection accessor in your mapping, if so the behavior you describe is the expected one when your code tries to modify the collection.
If you want to use that pattern in your domain model, you should change collection accessor to 'field' (with the appropriate naming strategy), in order to tell NHibernate to set the backing field '_employees' and not the property 'Employees'.
This will not trigger your code that tries to access the collection anymore.

Using DataAnnotation's on POCO and reflecting results using MVVM WPF

I have been looking into DataAnnotations and creating my own DataAnnotations for future use - mainly in MVC4 (which is fairly easy it's safe to say). I want to verify how useful, effective and easy to use they will be if I use the same Model classes in a WPF project.
public class Customer
{
public int Id { get; set; }
[Required()]
public string Name { get; set; }
}
public class ViewModelBase : IDataErrorInfo, INotifyPropertyChanged
{
//... (INotifyPropertyChanged)
public string Error
{
get
{
return string.Empty;
}
}
public string this[string columnName]
{
get
{
//According to tutorials, something here
return string.Empty;
}
}
}
So if I were to move on to creating a CustomerViewModel which inherits from the base class, would I have to present a subset view of the model properties like:
public class CustomerViewModel : ViewModelBase
{
[Required]
public string Name { get; set; }
}
Meaning I have to implement the annotations again, or is it possible to just use the model and somehow reflect model validation back to the front end using WPF's MAGICAL binding?
I have been looking at numerous articles, but none of which seem to be neat or very consice - such as:
http://blog.paulbetts.org/index.php/2010/04/27/wpf-data-validation-using-dataannotations/
Why would you put another Name property in your viemodel?
If you have a Customer property in your viewmodel, you can access it in you xaml like:
{Binding Customer.Name}
This will automatically take your dataanotations from your model class.
Edit: For a good example see: http://www.codeproject.com/Articles/98681/Validating-User-Input-WPF-MVVM

Model And ViewModel Relations and Inheritance - how should be implemented?

Sorry for the confusing title of the question. I am uncertain about how should I implement ViewModels and Models which derive from a base class.
My ViewModel classes are based on a ViewModelBase, the ViewModelBase holds a ModelBase which serves as a base class for all other models.
Each ViewModel holds a "Model" Property, however, because a Model property was defined by the base ViewModel class as the ModelBase class, I always have to create another property which casts the Model - from ModelBase to the relevant Model class.
My question is - is there not a simpler solution? Is there a design pattern which is relevant for these issues?
Here's a code sample:
public abstract class BasicViewModel : ViewModelBase
{
public BasicViewModel()
{
}
public ModelBase Model { get; set; }
}
public class ModelBase
{
}
public class ContainableViewModel : BasicViewModel
{
public ContainableViewModel(ContainableModel model)
{
this.Model = model;
}
public ContainableModel MyModel { get { return (ContainableModel)Model; } }
public int Children { get { return MyModel.Children; } set { MyModel.Children = value; } }
}
public class ContainableModel : ModelBase
{
public ContainableModel()
{
Children = 2;
}
public int Children { get; set; }
}
As you can see, the "MyModel" property is the one which bugs me.
Thank you very much for your help and time!
If each of your view model contains a Model property, you could use generics:
public abstract class BasicViewModel<TModelType> : ViewModelBase
where TModelType : ModelBase
{
public BasicViewModel(TModelType model)
{
Model = model;
}
public TModelType Model { get; set; }
}
public class ModelBase
{
}
Your containable view model is now defined as follows:
public class ContainableViewModel : BasicViewModel<ContainableModel>
{
public ContainableViewModel(ContainableModel model)
: base(model)
{
}
// you can now omit this method, it is defined on the abstract superclass
//public ContainableModel Model { get { return ()Model; } }
public int Children { get { return MyModel.Children; } set { MyModel.Children = value; } }
}
public class ContainableModel : ModelBase
{
public ContainableModel()
{
Children = 2;
}
public int Children { get; set; }
}
I generally don't use a base class for the different Model types, as there is generally not a one to one correspondance between ViewModel and Model objects. Further, the Model objects generally don't have much in common. This is different from the ViewModel objects, which all tie in via data binding and therefore could benefit from various helper methods that standardize the way you bind to your ViewModel instances.
The 'Model' in Model-View-ViewModel is a layer which provides your business logic and data interaction (everything not related to visualization and interaction with the user.) Your CustomerViewModel for your CustomerWindow might make use of a Customer object from your Model layer, but it very likely has references to other objects from your model, like some sort of Repository. Other Views, like say your MainWindow, might have a MainViewModel that doesn't directly correspond to any Model object, but probably has at least a few dependencies on your Model.

Categories