How to update MVVM nested ViewModels when Model changes and vice versa? - c#

I'm looking for some advice on how to solve a problem which is bugging us at the moment.
Let's say we have a couple of business objects (POCOs) like
public class UserGroup
{
public virtual ICollection<Person> People { get; set; }
}
public class Person
{
public virtual ICollection<Adress> Adresses { get; set; }
}
public class Adress
{
public virtual string StreetName { get; set; }
}
This is a bit simplistic but I hope it's enough so that you get the idea. UserGroup has a collection of Person instances and each Person instance has a collection of Address instances.
The ViewModel for the UserGroup POCO could possibly look like this:
public class UserGroupViewModel
{
private UserGroup userGroupModel;
public UserGroup UserGroupModel
{
get { return this.userGroupModel; }
set
{
this.userGroupModel = value;
this.PeopleViewModelCollection =
new ObservableCollection<PeopleViewModel>();
foreach (Person p in this.UserGroupModel.People)
{
var personViewModel = new PersonViewModel();
personViewModel.PersonModel = p;
this.PeopleViewModelCollection.Add(personViewModel);
}
}
}
public ObservableCollection<PersonViewModel> PersonViewModelCollection
{
get;
set;
}
}
Where as the ViewModel for the Person POCO could look like this:
public class PersonViewModel
{
private Person personModel;
public Person PersonModel
{
get { return this.personModel; }
set
{
this.personModel = value;
this.AddressViewModelCollection =
new ObservableCollection<AddressViewModel>();
foreach (Address a in this.PersonModel.Adresses)
{
var addressViewModel = new AddressViewModel();
addressViewModel.AddressModel = a;
this.AdressViewModelCollection.Add(addressViewModel);
}
}
}
public ObservableCollection<AddressViewModel> AddressViewModelCollection
{
get;
set;
}
}
Again it is overly simplistic but what I want to show is that ViewModels have ObserableCollections of other ViewModels nested inside them.
The setter of the respective Model property, e.g. PersonViewModel.PersonModel does create ViewModels for all the adresses of the Person and adds them to the ObservableCollection<AdressViewModels> AdressViewModelCollection property of the PersonViewModel.
At this point we could use this code to display these ViewModels in a View. We can e.g. display the StreetName of a Person's Adress.
Now what should you do when you delete an Adress of a Person? Removing the AdressViewModel from the PersonViewModel.AdressViewModelCollection will update the GUI but it actually does not allow to update the underlying models.
Similar to that if you add another Adress to a Person Model the existing ViewModels are not going to reflect this change since the PersonViewModel.AdressViewModelCollection would only be rebuilt once the PersonViewModel.PersonModel property is set again.
Is it there a (preferably easy) way to achieve this two-way update between ViewModel and Model? Or maybe this is not advisable and it's better to handle this problem in a completely different way?
I'm keen to hear different opinions on this problem!
EDIT:
I would like to state that our model classes are generated by the Entity Framework 4.0 and are POCOs (see example of business objects above). I'm not sure if that was clear enough in the question itself. We would like to expose navigational properties (e.g. Person.Addresses) as ICollection<T>.

You could simplify things using dynamic proxies (e.g Castle.Proxy), take a look at this post for an idea how to accomplish this.

It sounds like it's not the cascading that is the issue. It's the synchronization between the model and view model.
You will need to listen to the observable collections collectionchanged event and an implementation is provided here.
I think your only option is to implement the INotifyPropertyChanged in your model since the entity framework doesn't provide a way to update your ViewModel.

Related

Is it acceptable to bind Entity Framework entities to Window Forms controls?

I have two entities: the first is SalesOrder and the second is SalesOrderDetails. In the SalesOrder entity, I have an ObservableListSource list type that keeps track of SalesOrderDetails. The entities look something like this:
public class SalesOrder{
public int Id {get; set;}
public DateTime Date {get; set;}
...
public virtual ObservableListSource<SalesOrderDetails> OrderDetails { get; set; }
publi SalesOrder()
{
OrderDetails = new ObservableListSource<SalesOrderDetails>()
}
}
public class SalesOrderDetails{
public int Id { get; set; }
public int Quantity { get; get; }
public decimal Price { get; set; }
...
}
ObservableListSource extends ObservableCollection and implements IListSource. The GetList method returns a bindingList that stays in sync with the ObservableCollection. The GetList method is an extension method defined in the System.Data.Entity assembly. ObservableListSource looks like this:
public class ObservableListSource<T> : ObservableCollection<T>, IListSource
where T : class
{
private IBindingList _bindingList;
bool IListSource.ContainsListCollection { get { return false; } }
IList IListSource.GetList()
{
return _bindingList ?? (_bindingList = this.ToBindingList());
}
}
To bind the SalesOrder and SalesOrderDetails entities to my form, I use two binding source controls: salesOrderBindingSource and salesOrderDetailsBindingSource. The binding looks like this:
salesOrderBindingSource.DataSource = SalesOrder;
salesOrderDetailsBindingSource.DataSource = salesOrderBindingSource;
salesOrderDetailsBindingSource.DataMember = OrderDetails;
I bind every entity that needs change tracking the same way I bind SalesOrder and SalesOrderDetails. I've been reading that it's not recommended to bind the entities to the UI, that I should use view models and bind those to the UI instead. But that means that I would have to write the change tracking code or find a library that does change tracking.
What do you think?
If it's acceptable for your application to bind to DataSet and DataTable, then it's OK to bind to EF models.
In general, it depends to the requirements of your application; For example, usually for a small-scale or data-centric forms application it makes sense to bind to DataTable or Entity models, but usually in a large-scale application, you may want to consider better patterns for separation of concern.
If databinding to EF models makes sense to your application, then to do it in a correct way, follow this Microsoft Docs article:
EF 6 Fundamentals - Databinding with WinForms
Some notes about the IBindingList, IListSource
The interface that you need in Windows Forms to support databinding to lists, is IBindingList. BindingList<T> is a good implementation of that.
IListSource provides functionality to an object to return a list that can be bound to a data source. So while the object doesn't implement IBindingList, but it can return a bindable list from its GetList method. It's very well supported and used in Windows Forms. For example, DataGridView, ComboBox, ListBox, BindingSource check if the data source implemented IListSource and in this case, they get the data source by calling GetList method. That's why DataTable supports databinding without implementing IBindingList, instead, it returns a DataView in GetList, which implements IBindingList.

From anemic domain to domain driven

I was trying to find a clear and simple example of what an anemic domain really means. There is a lot of theory around, and also many well answered questions. Still, I could not get a clear picture about to what extent "anemic domain" meaning really goes. Therefore, I believe it would be simpler to see a dummy practical example of an anemic domain design and than ask you how could this be evolved to a domain driven one...
So, let's say we have a data entity of type TaskData:
public class TaskData
{
public Guid InternalId { get; set; }
public string Title { get; set; }
public string Details { get; set; }
public TaskState ExplicitState { get; set; }
public IEnumerable<TaskData> InnerTasks { get; set; }
}
And there is the need of an additional property called "ActualState", which is a computed state: if the Task has inner sub-tasks, the value strictly depends of the children, otherwise, the "ActualState" is equal to "ExplicitState"
If I write this logic in a separate service class (I call them "engines") we have:
internal class TaskStateCalculator
{
public TaskState GetState(TaskData taskData)
{
if (taskData.InnerTasks.Any())
{
if (taskData.InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (taskData.InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
return taskData.ExplicitState;
}
}
The first question is:
Does the code above reflect an anemic domain design, even if the TaskStateCalculator service/engine is part of my Domain Layer?
If yes, in order to avoid it, we'll need to move the logic inside the TaskData class (and rename TaskData to Task). Am I right?
The second question is (actually a chain of them):
What if we have a more difficult situation? Let's say there is the need for a property called ComputeSomething inside Task entity, and the logic of this property needs to access the entire Task's repository. In this case, the Task class would have a dependency on TaskRepository. Would this be ok? How would EF construct an instance of such class? What is the alternative?
I was trying to find a clear and simple example of what an anemic domain really means
It's in fact really easy to go from an anemic domain model to a rich one.
Set all property setters to private and then add methods if you want to change state of a model.
Evaluate all Law of Demeter violations and add methods where suitable.
Eventually you will have a correct model.
In your case I would encapsulate that logic inside TaskData as your TaskStateCalculator violate Law of Demeter
public class TaskData
{
public Guid InternalId { get; private set; }
public string Title { get; private set; }
public string Details { get; private set; }
public TaskState ExplicitState { get; private set; }
public IEnumerable<TaskData> InnerTasks { get; private set; }
public TaskState GetState()
{
if (!InnerTasks.Any())
return ExplicitState;
if (InnerTasks.All(x => this.GetState(x) == TaskState.Done))
{
return TaskState.Done;
}
if (InnerTasks.Any(x => this.GetState(x) == TaskState.InProgress))
{
return TaskState.InProgress;
}
return TaskState.Default;
}
}
another thing is that I would probably not expose InnerTasks collection at all to the outside world (just have it as a member field). But it's hard to say as I do not know how the class is used in other scenarios.
Why private setters
Every time you have to change more than one property it's often better to describe the behavior with a method, as it's then impossible to forget to change all required properties. A method also describes better what you are trying to do than changing a set of properties.
Even if you just change a single property, that property can set the class in an invalid state as the change may not be compatible with the rest of the information in the class. Don't forget that encapsulation is one of the core principles in OOP

MVVM: Modified model, how to correctly update ViewModel and View?

Case
Say I have a Person class, a PersonViewModel and a PersonView.
Updating properties from PersonView to the Person model is simple enough. PersonViewModel contains a Person object and has public properties the PersonView binds to in order to update the Person model.
However.
Imagine the Person model can get updated by Service. Now the property change needs to be communicated to the PersonViewModel and then to the PersonView.
This is how I would fix it:
For each property on the Person model I would raise the PropertyChanged event. PersonViewModel subscribes to the PropertyChanged event of Person. PersonViewModel would then raise another PropertyChanged in order to update the PersonView.
This to me seems the most obvious way but I kind of want to throw this question out there in the hope of someone showing me a nicer way. Is it really this simple or are there better ways to mark the model as modified and update the respective properties on the ViewModel?
Additions
The PersonView's DataContext is PersonViewModel. Person gets populated from JSON and gets updated many times during its lifetime.
Feel free to suggest architectual changes for my particular case.
Answer
I marked aqwert as the answer of my question since it provided me with an alternative to the solution I already proposed.
When the view binds directly to the model (which is also the case when the ViewModel exposes the Model) you are mixing UI code and data code. The goal of MVVM is to separate these two code domains. That's what the ViewModel is for.
The view model has to have it's own properties the view can bind to. An example:
class PersonViewModel
{
private Person OriginalModel { get; set; }
public ValueViewModel<string> Name { get; set; }
public ValueViewModel<int> Postcode { get; set; }
protected void ReadFromModel(Person person)
{
OriginalModel = person;
Name.Value = OriginalModel.Name;
Postcode.Value = OriginalModel.Postcode;
}
protected Person WriteToModel()
{
OriginalModel.Name = Name.Value; //...
return OriginalModel;
}
}
Using such a ViewModel-design really separates your data objects from your user interface code. When the structure of the class Person is changed, the UI doesn't need to be fit accordingly, because the ViewModel separates them from each other.
Now to your question. As you can see in the example above, I used a generic ValueViewModel<T>. This class implements INotifyPropertyChanged (and some other stuff). When you receive a new Person instance, you only have to call ReadFromModel(newPerson) on your ViewModel to have the UI updated, because the ValueViewModels the View binds to will inform the UI when their value changes.
Here an extremely simplified example of the internal structure of the ValueViewModel:
class ValueViewModel<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get { return _value;}
set
{
_value = value;
RaisePropertyChanged("Value");
}
}
}
This is an approach we used in our MVVM library. It has the advantage that it forces the developer to clearly separate code from the designers concerns. And, as a side effect, it generates a standardized code layout in all your Views and ViewModels and thus improves code quality.
If the view is binding to the Model directly then as long as the service is using the same instance any changes to the model properties will be propogated to the view.
However if you are recreating a new model in the service then you will give the viewmodel the new model. I expect to see the model as a property on the view model so when you set that property all binding should be alerted to the change.
//in the ViewModel
public Person Model
{
get { return _person; }
set { _person = value;
RaisePropertyChanged("Model"); //<- this should tell the view to update
}
}
EDIT:
Since you state there are specific ViewModel logic then you can tailor those properties in the ViewModel
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if(e.PropertyName == "Prop1") RaisePropertyChanged("SpecicalProperty");
...
}
public string SpecicalProperty
{
get
{
reutrn Model.Prop1 + " some additional logic for the view";
}
}
IN XAML
<TextBlock Text="{Binding Model.PropertyDirect}" />
<TextBlock Text="{Binding SpecicalProperty}" />
This way only both the Model and ViewModel propertys are bound to the view without duplicating the data.
You can get fancier creating a helper to link the property changes from the model to the view model or use a mapping dictionary
_mapping.Add("Prop1", new string[] { "SpecicalProperty", "SpecicalProperty2" });
and then find the properties to update by getting the list of properties
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
string[] props;
if(_mapping.TryGetValue(e.PropertyName, out props))
{
foreach(var prop in props)
RaisePropertyChanged(prop);
}
}

3 tier app - navigation properties

I'd using 3 tier architecture on my web project.
DAL -> EF 4 wrapper with classic CRUD method (AddEntity, RemoveEntity adn so on)
BAL -> business logic and query exposing (selectByName, byCity, bySomeOtherProperty).
UI - Aspx page
My problem is about navigationProperty exposed by EF. If I have a CustomerRepostiory, aspx side I don't want allow operation on entity that are not Customer, supposing follwing POCO class:
public class Customer
{
public int Id {get; set;}
public string Name {get; set;}
public ICollection<Orders> Order{get;set;}
}
and on aspx you execute something like this:
var customer = bll.getCustomerByName("alex");
customer.Order.Add(new ..) // BAD, I don't want allow it
What should I do? Maybe I must create a poco class wrapper in order to "hide" some properties?
Which really is best approach?
Expose your collection as an IEnumerable instead, that way the collection will be read only
You would have to do something like:
class Customer
{
private List<Order> orders();
Customer()
{
this.orders = new List<Order>();
}
public IEnumerable<Order> Orders { get { return this.orders.AsEnumerable(); } }
// you will need a public method to mutate the collection
public void AddOrder(Order order)
{
// implement custom logic, fire domain events, etc
this.orders.Add(order);
}
}
EDIT:
If you cannot modify your entity (which seems odd to me...) you could try to use the ObservableCollection<>
Something odd like this
class MyCustomer : Customer
{
private ObservableCollection<Order> orders;
internal bool AllowMutateCollection;
public MyCustomer()
{
this.Orders = this.orders = new ObservableCollection<string>();
this.orders.CollectionChanged += (_, __) =>
{
if(!this.AllowMutateCollection)
{
throw new NotImplementedException();
}
};
}
}
Now you would have to set the AllowMutateCollection when you will allow to mutate your entity, which becomes a real pain and probably this will be cause of some bugs... I do not recommend it
However I would strongly recommend you to redefine a little bit your design, wrapping your class and expose an IEnumerable instead, that would be cleaner and easier to maintain
Check this question
Fire an event when Collection Changed (add or remove)
Write a subclass for Customer, override Orders, make the getter do whatever access right checking you want

Aggregate detail values in Master-Detail view

I have a master-detail relationship in some custom entities. Say I have the following structure:
class Master : INotifyPropertyChanged
{
public int Id { get; set; } // + property changed implementation
public string Name { get; set; } // + property changed implementation
public ObservableCollection<Detail> Details { get; }
}
class Detail : INotifyPropertyChanged
{
public int Id { get; private set; }
public string Description { get; set; }
public double Value { get; set; } // + property changed implementation
}
My goal is to have a ListView, using a GridView, showing a list of Master objects. When I select a specific Master, I'll have a separate ListView for the details, allowing editing. Basically, a fairly standard Master-Detail view.
However, I also want the GridView for the Master to show the Sum of all of that master's Detail elements, ie: Details.Select(d => d.Value).Sum();
This is fairly easy to display using a custom IValueConverter. I can convert from the details collection directly to a double displaying sum, and bind a TextBlock's Text to the Details OneWay, via the IValueConverter. This will work, and show the correct values when I open the window.
However, if I change one of the detail members, this will not update (even though detail implements INotifyPropertyChanged), since the collection itself is still the same (the ObservableCollection reference hasn't changed).
I want to have an aggregated value in a master list, showing the sum (or average/count/etc) within the detail list, and have this stay up to date when the user changes properties in details. How can I go about implementing this?
Edit:
Ideally, I would prefer if there is a means of accomplishing this that doesn't involve changing the Master class directly. The application in question is using the MVVM pattern, and I'd really prefer to not change my Model classes in order to implement a specific View. Is there a way to do this without introducing custom logic into the model?
I was considering possibilities with the UI where you'd make the binding explicit and perform binding/updates from a command... but it seems that the easiest way to do it would be to extend the ObservableCollection to add/remove listeners to each Detail instance as its added/removed, then just fire CollectionChanged when any of them change. Call it DeeplyObservableCollection<T>.
class Master : INotifyPropertyChanged
{
public int Id { get; set; } // + property changed implementation
public string Name { get; set; } // + property changed implementation
public double Sum {get {return Details.Sum(x=>x.Value);}}
public DeeplyObservableCollection<Detail> Details { get; }
// hooked up in the constructor
void OnDOCChanged(object sender, CollectionChangedEventArgs e)
{ OnPropertyChanged("Sum"); }
}
Worst case you'd have to wrap an ObservableCollection in another type if you can't properly override all the methods you need...

Categories