In the context of the MVVM pattern, how would one structure the ViewModel when Models do not implement the INotifyPropertyChanged interface?
I like to keep my Models as simple as possibile and implementing the INotifyPropertyChanged interface only for binding purposes seems like unwanted complexity. That's why most of the times i require my VMs to wrap model properties like in the following example:
class ViewModel : INotifyPropertyChanged
{
private Model model;
public int MyProperty
{
get { return model.MyProperty; }
set
{
if (value != model.MyProperty)
{
model.MyProperty = value;
// Trigger the PropertyChanged event
OnPropertyChanged("MyProperty");
}
}
}
/* ... */
}
This will make bindings work ok, including two-way ones.
Now, what would happen if a command executes a model method with complex logic (affecting the value of many properties of different objects)? The model is not implementing INotifyPropertyChanged so there's no way we can know it was updated. The only solution that comes to my mind is to use messaging (mediator pattern) to inform all VMs of the execution of the method so that each VM fires the PropertyChanged event for each potentially affected property:
// Sample ICommand.Execute() implementation
public void Execute(object parameter)
{
var model = (Model)parameter;
model.VeryComplexMethod();
// Just an example, the string "VeryComplexMethodExecuted" is
// sent to all listening VMs. Those VMs will in turn fire the
// PropertyChanged event for each property that may have changed
// due to the execution of the complex model method.
Messaging.Broadcast("VeryComplexMethodExecuted");
}
Please share your ideas, thanks.
Declare your members virtual and use something like Castle Dynamic Proxy to inject change notification automatically:
http://ayende.com/blog/4106/nhibernate-inotifypropertychanged
This has to be used with care when your models are being created in your data layer because it returns a new instance entirely. Your database code will think the object has changed and serialize it back out again which will in turn have a huge impact on performance. Fortunately all the good ORMs provide mechanisms for you to substitute in class wrappers at creation time.
Related
I'm creating a BPMN editor using WPF and need to include, among other things, a set of different task types.
Each task type share some common properties, but also include some type-specific information.
However, for a given task element, the user should be able to change its type and even the information specific to the given task type should be retained between such changes.
Therefore, I thought about creating:
one model class, TaskModel, which would combine properties of all task types
a separate XXXTaskViewModel class for each task type, exposing only properties related to that type
a common TaskView class representing the task as a visual element in the editor canvas
When a user changes the type of a task (using a property grid), a PropertyChanged event is fired, which is handled in TaskView to change the DataContext view model for the new one.
Since I'm totally new to C# and need to refactor and enhance someone else's code, my initial questions are:
Is such a design correct, i.e., in accordance with MVVM principles? Or maybe there exist other better patterns/solutions I could use?
Is it possible at all to handle PropertyChanged events in a view?
I tried to implement the INotifyPropertyChanged in my view (to change DataContext):
public partial class BaseElementView : DragableUserControl, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public BaseElementView()
{
InitializeComponent();
PropertyChanged += PropertyChangedHandler;
}
private void PropertyChangedHandler(object sender, PropertyChangedEventArgs e)
{
Console.WriteLine("A property has changed: " + e.PropertyName); // just a proof-of-concept
}
// ...
}
However, no PropertyChanged is actually catched (although the same event is handled by a view model class). Also, I get a code analyzer hint:
The event BaseElementView.PropertyChanged is never used.
I don't know why that happend.
Ok, I guess I found a solution to my problem - I've created a model containing all properties (for all different kind of tasks), a view model bound to that model (i.e., also containing all properties) and then dynamically adjusted the Browsable attribute of the appropriate properties in the view model (in the setter of the TaskType property).
This post was helpful to adjust the Browsable attribute: Make a Property Read-Only in PropertyGrid
I adjusted the proposed method to handle the BrowsableAttribute attribute:
public static void SetBrowsableAttribute(this PropertyDescriptor p, bool value)
{
var attributes = p.Attributes.Cast<Attribute>().Where(x => !(x is BrowsableAttribute)).ToList();
attributes.Add(new BrowsableAttribute(value));
typeof(MemberDescriptor).GetProperty("AttributeArray", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(p, attributes.ToArray());
}
and then used it like this:
[RefreshProperties(RefreshProperties.Repaint)]
public TaskType Type
{
get { return _taskActivity.Type; }
set
{
_taskActivity.Type = value;
TypeDescriptor.GetProperties(this)[nameof(AvailableImplementations)].SetBrowsableAttribute(UseImplementation);
// ...
NotifyOfPropertyChange(nameof(Type));
}
}
I've created a ViewModel class that have inside the implementation of INotifyPropertyChanged, now I also have other ViewModels that inherit from the ViewModel (base).
All working good actually but I have a doubt.
So let's say that I've in the CustomerViewModel an ObservableCollection called Price, like this:
private ObservableCollection<Models.Price> _price = new ObservableCollection<Models.Price>();
public ObservableCollection<Models.Price> Price
{
get { return _price; }
}
this ObservableCollection should be populated by other classes, 'cause I need to access to the same resource.
I really don't understand how can I do this in mvvm. I though to a Singleton ViewModel, so something like this defined in the base VM:
public static ViewModel Instance { get; set; }
So import all the childs VM into the base and access them via ViewModel.Instance.Price;
but doesn't seems a good practice for me. Any idea?
With this implementation, you can share the same Datasource to all ViewModels
public class PriceGenerator {
private PriceGenerator() {
this.Prices = new ObservableCollection<Price>();
this.Generate();
}
void Generate() {
//Generate Objects here
this.Prices.Add(generatedPrice);
}
public ObservableCollection<Price> Prices {
get;
}
private static PriceGenerator _instance;
public static PriceGenerator Instance => _instance ?? (_instance = new PriceGenerator());
}
There are generally two approaches to this.
Even if you don't have a real database/repository, implement a singleton class that simulates this. This singleton class should also implement INotifyPropertyChanged (and/or INotifyCollectionChanged as appropriate). All ViewModels will be able to access this simulated repository, and interested ViewModels can choose to subscribe to this repository's PropertyChanged callback. For your question, it is generally tidier to have a repository that handles just prices, rather than having a simulated repository that stores 101 different information.
Have a main ViewModel. Some people would visualize that the MainWindow being the main view, with a corresponding main ViewModel. This ViewModel is intentionally made a singleton, which other ViewModels can access through static call. This main ViewModel is basically acting just like #1 - it is like a repository that stores 101 different information. That main ViewModel is likely to look untidy, but it is simply to trace where things are stored - if you need any data, it's probably in there.
Personally, I prefer to use the first approach. lokusking's answer is an example of this approach. Although his "repository" does more than storing data.
I have a WPF listview containing ingredients bound to viewmodel.Ingredients(MVVM pattern)
Now i want this listview to update when i add and save an ingredient in the database in a different window(calls repository.Save()).
(viewmodel.Ingredients calls repository.findAll())
I see 2 possible ways of doing this:
1) Using MVVM : Raise the property change event in Repository.Save(). But then i need to register the repository as a 2nd datasource on my view or do something else that will cause my view to update. How do i implement this?
2) An alternative would be using the MVC pattern for updates from the repository(together with the mmvm)
the viewmodel could then implement the IUpdateIngredients interface
public interface IUpdateIngredients
void Update()
then my repository has the methods:
public void removeHandler(IUpdateIngredients handler)
public void AddHandler(IUpdateIngredients handler)
public void RaiseUpdateEvent() // call Update() on all the handlers
The viewmodel registers itself with the addHandler method. The repository.Save method calls RaiseUpdateEvent();
This would do the job, but i really want to get rid of the removehandler method. Is there a way the .NET framework can do the removing for me, perhaps using events? I want to get rid of the removeHander method because i reuse this listview on many different places, sometimes in popup widows, and i want to make sure i dont forget the call the removehandler method somewhere.
Thanks for helping me!
I had a similar problem, I used a Mediator in the class that was doing the database updates, to send the message to other ViewModels to refresh their collections.
As mediator stores the target ViewModels as WeakReferences , there’s no need for removing the event handlers. Here’s a great article with sample code about the Mediator pattern by Josh Smith …
I modified the code from the above article to my needs, most importantly Mediator was implemented as a Singleton, like this.
private static readonly Lazy<Mediator> _lazy = new Lazy<Mediator>(() => new Mediator());
public static Mediator Instance { get { return _lazy.Value; } }
Now every ViewModel and broadcaster get the instance of Mediator …
public Mediator Mediator
{
get { return Mediator.Instance; }
}
And the class that updates the database sends the message to ViewModel that needs to refresh.
Mediator.NotifyColleagues(MediatorMessages.DBUpdated);
ViewModel registers for messages in the constructor and then updates the collection.
Mediator.Register(MediatorMessages.DBUpdated, new Action(RefreshCollection));
I have a simple MVVM architecture where I'm using a view model to bind commands to a xaml view. My commands are fairly generic and I'll be binding them to a couple of views so I've put them into their own classes implementing the ICommand interface. Inside of the view model I have public accessors like so:
private ICommand _myCommand;
public ICommand MyCommand
{
get
{
if (_myCommand == null)
{
_myCommand = new MyCommand(_injectedModel);
}
return _myCommand ;
}
}
This all works and I'm happy with the architecture but ... I have tons of these functions. They all roughly do the same thing - expose the command as a public property, check if a private command already exists and if so use it otherwise create a new command. It's a bit "boilerplate" for my taste.
I would like a nice way to abstract this. I could create a method that looks up commands based on an identifier from some sort of command map. I could just create all of my commands in the view models constructor (rather than doing so lazily).
What would you consider best practice? Should I avoid instantiating a new command inside each view model and have a central command lookup?
I could just create all of my commands in the view models constructor (rather than doing so lazily).
I often do this. The cost of a command is fairly cheap, in most implementations. Depending on your implementation, it's likely just a small class with a single delegate reference (or a pair of delegate references). This is unlikely to be significant enough overhead, IMO, to warrant the lazy construction.
I often write this as:
// Constructor
public MyViewModel()
{
this._injectedModel = SetModel();
this.MyCommand = new MyCommand(_injectedModel);
}
ICommand MyCommand { get; private set; }
You seem to be looking for Caliburn.Micro. It maps ViewModel methods to x:Name in XAML.
You won't need the "boilerplate" code for commands anymore.
Example:
<Button x:Name="Save" />
Will call:
public void Save()
{
//Save logic
}
On button click.
Notice that at no point i made any Command, it's all done behind the scene.
This is a very simple example, you can add parameter(s) to the call and make it use a different event than Click.
I'm looking for a clean and elegant solution to handle the INotifyPropertyChanged event of nested (child) objects. Example code:
public class Person : INotifyPropertyChanged {
private string _firstName;
private int _age;
private Person _bestFriend;
public string FirstName {
get { return _firstName; }
set {
// Short implementation for simplicity reasons
_firstName = value;
RaisePropertyChanged("FirstName");
}
}
public int Age {
get { return _age; }
set {
// Short implementation for simplicity reasons
_age = value;
RaisePropertyChanged("Age");
}
}
public Person BestFriend {
get { return _bestFriend; }
set {
// - Unsubscribe from _bestFriend's INotifyPropertyChanged Event
// if not null
_bestFriend = value;
RaisePropertyChanged("BestFriend");
// - Subscribe to _bestFriend's INotifyPropertyChanged Event if not null
// - When _bestFriend's INotifyPropertyChanged Event is fired, i'd like
// to have the RaisePropertyChanged("BestFriend") method invoked
// - Also, I guess some kind of *weak* event handler is required
// if a Person instance i beeing destroyed
}
}
// **INotifyPropertyChanged implementation**
// Implementation of RaisePropertyChanged method
}
Focus on the BestFriend Property and it's value setter. Now I know that I could do this manually, implementing all steps described in the comments. But this is going to be a lot of code, especially when I'm planning to have many child properties implementing INotifyPropertyChanged like this. Of course they are not going to be always of same Type, the only thing they have in common is the INotifyPropertyChanged interface.
The reason is, that in my real scenario, I have a complex "Item" (in cart) object which has nested object properties over several layers (Item is having a "License" object, which can itself have child objects again) and I need to get notified about any single change of the "Item" to be able to recalculate the price.
Do you some good tips or even some
implementation to help me to solve
this?
Unfortunately, I'm not able/allowed to use post-build steps like PostSharp to accomplish my goal.
since I wasn't able to find a ready-to-use solution, I've done a custom implementation based on Pieters (and Marks) suggestions (thanks!).
Using the classes, you will be notified about any change in a deep object tree, this works for any INotifyPropertyChanged implementing Types and INotifyCollectionChanged* implementing collections (Obviously, I'm using the ObservableCollection for that).
I hope this turned out to be a quite clean and elegant solution, it's not fully tested though and there is room for enhancements. It's pretty easy to use, just create an instance of ChangeListener using it's static Create method and passing your INotifyPropertyChanged:
var listener = ChangeListener.Create(myViewModel);
listener.PropertyChanged +=
new PropertyChangedEventHandler(listener_PropertyChanged);
the PropertyChangedEventArgs provide a PropertyName which will be always the full "path" of your Objects. For example, if you change your Persons's "BestFriend" Name, the PropertyName will be "BestFriend.Name", if the BestFriend has a collection of Children and you change it's Age, the value will be "BestFriend.Children[].Age" and so on. Don't forget to Dispose when your object is destroyed, then it will (hopefully) completely unsubscribe from all event listeners.
It compiles in .NET (Tested in 4) and Silverlight (Tested in 4). Because the code in seperated in three classes, I've posted the code to gist 705450 where you can grab it all: https://gist.github.com/705450 **
*) One reason that the code is working is that the ObservableCollection also implements INotifyPropertyChanged, else it wouldn't work as desired, this is a known caveat
**) Use for free, released under MIT License
I think what you're looking for is something like WPF binding.
How INotifyPropertyChanged works is that the RaisePropertyChanged("BestFriend"); must only be fored when the property BestFriend changes. Not when anything on the object itself changes.
How you would implement this is by a two step INotifyPropertyChanged event handler. Your listener would register on the changed event of the Person. When the BestFriend gets set/changed, you register on the changed event of the BestFriend Person. Then, you start listening on changed events of that object.
This is exactly how WPF binding implements this. The listening to changes of nested objects is done through that system.
The reason this is not going to work when you implement it in Person is that the levels can become very deep and the changed event of BestFriend does not mean anything anymore ("what has changed?"). This problem gets larger when you have circular relations where e.g. the best friend of your monther is the mother of your best fiend. Then, when one of the properties change, you get a stack overflow.
So, how you would solve this is to create a class with which you can build listeners. You would for example build a listener on BestFriend.FirstName. That class would then put an event handler on the changed event of Person and listen to changes on BestFriend. Then, when that changes, it puts a listener on BestFriend and listens for changes of FirstName. Then, when that changes, it sends raises an event and you can then listen to that. That's basically how WPF binding works.
See http://msdn.microsoft.com/en-us/library/ms750413.aspx for more information on WPF binding.
Interesting solution Thomas.
I found another solution. It's called Propagator design pattern. You can find more on the web (e.g. on CodeProject: Propagator in C# - An Alternative to the Observer Design Pattern).
Basically, it's a pattern for updating objects in a dependency network. It is very useful when state changes need to be pushed through a network of objects. A state change is represented by an object itself which travels through the network of Propagators. By encapsulating the state change as an object, the Propagators become loosely coupled.
A class diagram of the re-usable Propagator classes:
Read more on CodeProject.
I have been Searching the Web for one day now and I found another nice solution from Sacha Barber:
http://www.codeproject.com/Articles/166530/A-Chained-Property-Observer
He created weak references within a Chained Property Observer. Checkout the Article if you want to see another great way to implement this feature.
And I also want to mention a nice implementation with the Reactive Extensions #
http://www.rowanbeach.com/rowan-beach-blog/a-system-reactive-property-change-observer/
This Solution work only for one Level of Observer, not a full Chain of Observers.
I wrote an easy helper to do this. You just call BubblePropertyChanged(x => x.BestFriend) in your parent view model. n.b. there is an assumption you have a method called NotifyPropertyChagned in your parent, but you can adapt that.
/// <summary>
/// Bubbles up property changed events from a child viewmodel that implements {INotifyPropertyChanged} to the parent keeping
/// the naming hierarchy in place.
/// This is useful for nested view models.
/// </summary>
/// <param name="property">Child property that is a viewmodel implementing INotifyPropertyChanged.</param>
/// <returns></returns>
public IDisposable BubblePropertyChanged(Expression<Func<INotifyPropertyChanged>> property)
{
// This step is relatively expensive but only called once during setup.
MemberExpression body = (MemberExpression)property.Body;
var prefix = body.Member.Name + ".";
INotifyPropertyChanged child = property.Compile().Invoke();
PropertyChangedEventHandler handler = (sender, e) =>
{
this.NotifyPropertyChanged(prefix + e.PropertyName);
};
child.PropertyChanged += handler;
return Disposable.Create(() => { child.PropertyChanged -= handler; });
}
Check-out my solution on CodeProject:
http://www.codeproject.com/Articles/775831/INotifyPropertyChanged-propagator
It does exactly what you need - helps to propagate (in elegant way) dependent properties when relevant dependencies in this or any nested view models change:
public decimal ExchTotalPrice
{
get
{
RaiseMeWhen(this, has => has.Changed(_ => _.TotalPrice));
RaiseMeWhen(ExchangeRate, has => has.Changed(_ => _.Rate));
return TotalPrice * ExchangeRate.Rate;
}
}
Please take a look at EverCodo.ChangesMonitoring. This is a framework to handle PropertyChanged and CollectionChanged events on arbitrary hierarchy of nested objects and collections.
Create a monitor to handle all change events of the object tree:
_ChangesMonitor = ChangesMonitor.Create(Root);
_ChangesMonitor.Changed += ChangesMonitor_Changed;
Do arbitrary modifications on the object tree (all of them will be handled):
Root.Children[5].Children[3].Children[1].Metadata.Tags.Add("Some tag");
Root.Children[5].Children[3].Metadata = new Metadata();
Root.Children[5].Children[3].Metadata.Description = "Some description";
Root.Children[5].Name = "Some name";
Root.Children[5].Children = new ObservableCollection<Entity>();
Handle all events in one place:
private void ChangesMonitor_Changed(object sender, MonitoredObjectChangedEventArgs args)
{
// inspect args parameter for detailed information about the event
}