Creating ViewModels WIth Common Properties with OnPropertyChanged? - c#

I relised I have lots of models view models with those two properties
public Visibility OkButtonVisibility
{
get{ return _OkButtonVisibility;}
set{
_OkButtonVisibility = value;
RaisePropertyChanged("OkButtonVisibility");
}
}
public Visibility CancelButtonVisibility
{
get{ return _CancelButtonVisibility;}
set{
_CancelButtonVisibility = value;
RaisePropertyChanged("CancelButtonVisibility");
}
}
I wanted to create attachable interface for them like this:
Interface IOKandCancelButtonsVM
{
public Visibility OkButtonVisibility
{
get{ return _OkButtonVisibility;}
set{
_OkButtonVisibility = value;
RaisePropertyChanged("OkButtonVisibility");
}
}
public Visibility CancelButtonVisibility
{
get{ return _CancelButtonVisibility;}
set{
_CancelButtonVisibility = value;
RaisePropertyChanged("CancelButtonVisibility");
}
}
and have my viewmodels that use this to inherite them and another interfaces with proxy properties like this
class VM1:BaseVM,IOKandCancelButtonsVM,IOtherCommonPropertyVM
{
}
but then I relaised my new interfaces don't impliment INotifyChanged.
would it be a bad idea to haveIOKandCancelButtonsVM impliment INotifyChanged
and have VM1 explicitly impliment BaseVM?
I never dealt with class inheriting same interface twice and not sure what to do.
this is only an example less than half of the VMs use those I have a few hundred properties, many shared over dozens of screens. i need a more elegant solution than sticking all on thos into the BaseViewModel

You cannot have an implementation in your interface definition. This means that your IOKandCancelButtonsVM definition is incorrect.
would it be a bad idea to have IOKandCancelButtonsVM impliment BaseVM
Yes it would be a very bad idea - impossible in fact - interfaces cannot implement or extend classes.
Since you asked for opinion on how to structure your code, I will also throw this out there: remove any reference to 'visibility' from your viewmodel. Do not return a System.Visibility value from your viewmodel.
A viewmodel shouldn't know anything about the view. The semantically correct way to do this is to simply return a flag from the viewmodel, and use a converter to change it to a Visibility value in the binding - there is even a ready made converter in the framework for doing this: BooleanToVisibilityConverter. Try to avoid any mention of UI related terms in your VM even if it is returning a bool - it is a good practice which leads to tighter and more disciplined code, using those names willy nilly will eventually lead to smelly code.
I have a blog post which illustrates a nice approach to property change notifications: Streamlining property notifications in MVVM.
Just to make it clear, I am advising that you get rid of any ideas you have about IOKandCancelButtonsVM interfaces, by all means include simple boolean properties on a base viewmodel that will be extended by many other viewmodels that will be bound to dialogs with OK/Cancel buttons.
To diagram this in text it would look like this:
YourBaseVm <-- BaseVmUsedByDialogs <-- SpecificDialogVm
(note the italicising which indicates the class is abstract)

It seems you already have a base viewmodel class. Just add the two properties there. You might want to create a second base inheriting from the first, which you use when those two properties are required, so in case their not, there is no overhead.

Why not to go for virtual properties in your base class BaseVM with default functionality implemented in it. In case other derived classes want to extend it they can always override it as per funcitonality required.
Make sure your BaseVM is implementing INotifyPropertyChanged.

I'd just create an abstract base class, and have the ViewModels that need those properties inherit from it. Keep it simple.
abstract class BaseDialogVM : BaseVM
{
private Visibility _OkButtonVisibility;
public Visibility OkButtonVisibility {
get { return _OkButtonVisibility; }
set {
_OkButtonVisibility = value;
RaisePropertyChanged("OkButtonVisibility");
}
}
private Visibility _CancelButtonVisibility;
public Visibility CancelButtonVisibility {
get { return _CancelButtonVisibility; }
set {
_CancelButtonVisibility = value;
RaisePropertyChanged("CancelButtonVisibility");
}
}
}
class VM1 : BaseDialogVM { /*...*/ }

Related

How to implement MVVM with the WPF treeview?

I haven't worked with WPF or the MVVM pattern before.
However I want to create a simple document management system and would like to do so using the aforementioned technologies.
I've modeled a hierarchical file system in my Database and want to display it in a treeview.
EER-Diagramm
As you can see each directory can have multiple sub-directories and multiple files in it.
I've read some tutorials on the topic and if I understood them correctly then I should create model classes for directory and file in which the data from the database is stored directly.
Example:
public class Directory
{
private int id;
public int Id
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private int parent;
public int Parent
{
get { return parent; }
set { parent = value; }
}
private DateTime dateCreatedOn;
public DateTime DateCreatedOn
{
get { return dateCreatedOn; }
set { dateCreatedOn = value; }
}
}
Then each model class should have an associated view-model class which implements additional properties which are only relevant for describing the UI element to which objects of this class will be bound.
In this case the view-model class should have the isExpanded and isSelected Property of the treeviewitem.
Then I would need another view-model class for the entire treeview which would contain the collection of directorys and files which should be displayed.
My questions are:
Have I understood the mvvm concept correctly?
Which class, the model or the view-model, of directory should implement the iNotifyPropertyChanged interface?
Should the view-model class of directory contain the same properties as the model class or is a reference to a model-object in the view-model class sufficient?
If the view-model class should contain the same properties of the model class again, then whats the best way to make sure that model-objects and the associated view-model objects always stay synchronized?
I hope this question is understandable and thanks for all help.
Andahari
answer 1) yes.
answer 2) view-model should have the iNotifyPropertyChanged.
answer 3) yes. and they should be explicitly mapped. i.e.:
this.property1 = model.property1
answer 4) use the same names, and see answer 3.
If you use a private-public property pair in the view-model, use iNotifyPropertyChanged in the view-Model, and map the properties of the model to the corresponding properties in the view-model, you should be set.
Model also can implement the iNotifyPropertyChanged, you no need to repeat the properties in View Model again.
https://msdn.microsoft.com/en-us/library/gg405484(PandP.40).aspx
"The model may also support data validation and error reporting through the IDataErrorInfo (or INotifyDataErrorInfo) interfaces. The IDataErrorInfo and INotifyDataErrorInfo interfaces allow WPF data binding to be notified when values change so that the UI can be updated. They also enable support for data validation and error reporting in the UI layer."

With an MVVM Pattern (Specifically Using MVVM Light), How To Implement Model With More Than Just Primitives?

I am just getting started with the MVVM pattern, and have settled on using the MVVM Light toolkit for my Windows Phone app.
My question is this:
I am having trouble producing a view model that correctly binds a view to a model with properties that are more than just primitive types---what is a functioning way of structuring a model and accompanying view model such that a view will bind to the model through the view model, and properly update when values in the model change?
As in, how do I correctly reference the values of the model from the view model?
An example of this sort of model would be a class Foo, which has a property, b, that is a primitive, and another property, a, that is of type Bar, with its own properties---primitives or otherwise.
Foo:
public class Foo : ObservableObject
{
public Foo()
{
a = new Bar();
}
public const string aPropertyName = "a";
private Bar _a;
public Bar a
{
get
{
return _a;
}
set
{
Set(aPropertyName, ref _a, value);
}
}
public const string bPropertyName = "b";
private bool _b;
public bool b
{
get
{
return _b;
}
set
{
Set(bPropertyName, ref _b, value);
}
}
}
Bar:
public class Bar : ObservableObject
{
public const string cPropertyName = "c";
private bool _c;
public bool c
{
get
{
return _c;
}
set
{
Set(cPropertyName, ref _c, value);
}
}
}
Edit: To clarify, when setting up the properties in the view model, should I be doing something like:
public const string cPropertyName = "c";
public bool c
{
get
{
return model.a.c;
}
set
{
model.a.c = value;
RaisePropertyChanged(cPropertyName);
}
}
or something different?
I think the question you are asking is Nested vs Flat view model. Both are correct approaches depending on the situation [though I prefer Nested View models].
I can't suggest you what you use, but in case of Foo-Bar example, wrapping up Bar's property with a property in Foo will make more sense [Flat View model approach]. So what u did by creating property c is right.
Below is my bit on both approaches
Advantage of Nested View Model
That's what object oriented is all about.
If you use LINQ to SQL or Entities, or an ORM, you can simply pass the ORM objects and not have to pass all kinds of properties.
You can pass other views, so you can create separate models for partial views, and if that view uses a partial, you can pass the partial view model class as a property of the view model class.
Advantage of Flat View Model
Keeps things simple and more readable.
In the last two WPF-applications we developed in our company, we used MVVM with Caliburn.Micro.
For the most of ViewModels we didn't create Models, because you should create a Model not because otherwise you will violate some OOP-rules, but because you need it.
When you should create a separated Model?
In two cases, in my opinion:
when you can reuse a Model in the other application;
when a ViewModel becomes complicated and you start to realize, that you want to simplify it by separating of concerns. Almost always, extracting a Model from a ViewModel is simple, if not trivial.
There is no sense to always create a Model for every ViewModel. Going this way, you overcomplicate a system, when you can avoid complications.
As to binding to a non-primitive type. Well, there is no any problems to add the support of notifying directly to the type.
It really depends on your usage of ViewModel.
If you only need one or two properties of your complex type (Bar in your example), you can flatten it in your ViewModel. If you know you always/mostly need all of your complex properties, then it may make sense to create an own ViewModel for your complex model and expose your ViewModel instead of the model.
public class Foo : ObservableObject
{
public BarViewModel A
{
public const string aPropertyName = "a";
private Bar _a;
get
{
return _a;
}
set
{
Set(aPropertyName, ref _a, value);
}
}
}
Last but not least:
Does your complex model needs two way binding? If no, you could just implement a property for your model.
But be warned! Binding objects that do not implement INotifyPropertyChanged may result in memory leaks! See this answer

"Simple MVVM Toolkit" child Model classes in C# WPF

I'm using "Simple MVVM Toolkit" (MVVM noob here) to develop a C# WPF app.
I have a model class called A:
public class A : ModelBase<A>
{
//properties, constructors, methods..
}
..and another model class called B which inherits from A but exposes a property which A doesn't have:
public class B : A
{
private string additionalProperty;
public string AdditionalProperty
{
get { return additionalProperty; }
set
{
additionalProperty = value;
//NotifyPropertyChanged(m => m.AdditionalProperty); <-- problem here
}
}
}
Problem comes with the commented line above: the lambda in NotifyPropertyChanged won't work because m.AdditionalProperty doesn't exist, since m is of type A, not B. What happens in this case? I should note that NotifyPropertyChanged comes with the toolkit and is not a custom implementation.
EDIT: Here is the IntelliSense description for NotifyPropertyChanged in B:
void ModelBaseCore<A>.NotifyPropertyChanged<TResult>(System.Linq.Expressions.Expression<Func<A,TResult>> property)
Allows you to specify a lambda for notify property changed
The problem is in how they implemented the ModelBase. They obviously didn't feel that someone would be subclassing a model that subclasses from ModelBase, which I'm not sure why they'd think that.
In any case, the issue is that you're telling the ModelBase what type to use to do its resolution when you specify the generic: ModelBase<A>. To get around this, you have to do some rather convoluted generic play that looks pretty goofy:
public class A<T> : ModelBase<T> where T : A<T>
{
//properties, constructors, methods..
}
public class B : A<B>
{
private string additionalProperty;
public string AdditionalProperty
{
get { return additionalProperty; }
set
{
additionalProperty = value;
NotifyPropertyChanged(m => m.AdditionalProperty);
}
}
}
Note that A now inherits from ModelBase<T> not ModelBase<A>, and you constrain T to be A<T>. Then you have B inherit from A and specify its generic as B (which implements A<T>).
This is rather convoluted, and I'm not sure why they did it this way - possibly because there's some cross-platform things that require them to do this. If you don't need this for cross-platform work, or possibly they didn't do this for that reason, I would instead recommend you use something like MVVM Light for your MVVM needs. It has a different implementation for the NotifyPropertyChanged that doesn't depend on specifying its own type, and reduces the need for this over-use of generics.
You're not limited to the properties on the parameter passed into the lambda. You can also use properties on any object that's referable within the parent set of curly braces(in your case the setter). Including "this".
Instead of:
NotifyPropertyChanged(m => m.AdditionalProperty);
Try:
NotifyPropertyChanged(m => this.AdditionalProperty);
If you dig through the source, the string value of the property that is passed in is derived from the Expression parameter itself. Aside from using the object to get it's property it's not used at all. It could come from "this", some other object entirely, etc.

Should I use a private field of a public property inside a class where I declare that property?

Let say I have a class like this:
public class A
{
private BaseSettings fieldA;
public ISettings PropertyA
{
get {return fieldA;}
set {fieldA= value as BaseSettings;}
}
}
where BaseSettings implements ISettings. Inside class A, if I want to access BaseSettings' property called PropertyB, which of this is a good practice:
fieldA.PropertyB;
or
((BaseSettings)PropertyA).PropertyB;
One may say the first approach may hide the hint to when a property changed. For example, a code may listen to PropertyChangedEvent and then the value for property changed without raising the event.
Another one may say the second approach may expose a risk that when a person who is not familiar with current code modify it, he may cast the PropertyA to different type that implements ISettings.
Both approaches have its downside. In a good programming practice, which one should be more preferable?
EDIT:
Added based on the comments belows:
I agree that setting the backing-field as ISettings makes absolute sense. But what should I do to make sure that the PropertyA is always type of BaseSettings. That will raise a question: "Then why don't you set both property and backing-field to BaseSettings?".
The reason behind why property and its backing field are different is that class A also implement an interface like this
public interface IControlWithSettings
{
ISettings OwnerSettings
{
get;
set;
}
ISettings Settings
{
get;
set;
}
}
So the actual classA would look like this
public class BaseForm: Form, IControlWithSettings
{
private BaseFormSettings settings;
public ISettings Settings
{
get {return settings;}
set {settings= value as BaseFormSettings;}
}
}
And I have another class B would also implement IControlWithSettings
public class BaseUserControl: UserControl, IControlWithSettings
{
private BaseUserControlSettings settings;
public ISettings Settings
{
get {return settings;}
set {settings= value as BaseUserControlSettings ;}
}
}
Both BaseFormSettings : ISettings and BaseUserControlSettings : ISettings . This is actual ISettings interface
public interface ISettings
{
Dictionary<string, ISettings> Children { get; set; }
}
the 'as' casting is a side effect I put into the setter so that it will ignore and return null if the setting is set to wrong one. I read somewhere saying I shouldn't throw exception in a setter. So making it null is my way to inform there is something wrong has been done.
So what is the better approach. Did I design it wrong?
As you stated, both approaches have their downsides, and it also depends on whether the property setter may contain some additional logic (e.g. validation), and you may use or circumvent this additional logic from inside the class.
If there's nothing that speaks against it, I'll use direct access to the field. It's neater and it avoids all this typecasting stuff.
But generally: Why would you back your property with the derived type, while the property itself has the interface type? This doesn't make much sense. Why not just:
public class A
{
public ISettings PropertyA { get; set; }
}
This would be much cleaner, and your question wouldn't even arise.
Edit (based on the answer's edit)
In case of the 'double use' of the backing field the typecasting makes sense. But I don't think (and never heard that before) that it's a bad thing to throw an exception from a property setter. On the contrary: Validating a value and throwing an exception if it doesn't pass is a very common pattern.
So, in your concrete case, I would validate the value for the correct type, throw if it's not correct, and use the backing field internally to bypass this type check.

How to prevent modification of inherited properties?

I added some extra stuff to the standard wpf combobox. In the constructor I set two properties:
public SmartComboBox()
: base()
{
this.IsEditable = true;
this.IsTextSearchEnabled = false;
...
}
The two properties are inherited from System.Windows.Controls.ComboBox.
How do I prevent the modification of these two properties after I set their values in the constructor?
Short answer: you can't, as that properties modifiers can not be changed by you.
If you want to hide an implementation, just encapsulate ComboBox class inside your class.
public class SmartComboBox {
private ComboBox _uiCombo = ....
}
And also in addition another thing yet:
In your example, in the code presented, there is no any reason of explicitly calling base() on ctor, as it will be called by CLR
You can't fully prevent it, the closest you can come is re-declaring the properties as new
public SmartComboBox()
{
base.IsEditable = true;
base.IsTextSearchEnabled = false;
...
}
public new bool IsEditable { get { return base.IsEditable; } }
public new bool IsTextSearchEnabled { get { return base.IsTextSearchEnabled; } }
The downside to this is that new is not an override, if the object is cast as its parent then the property can be set.
The other option is to wrap the class as Tigran mentioned, however the pita with that is exposing all the other properties you need.
What if you override the metadata for the IsEditableProperty and play with PropertyChangedCallBack and CorceValueCallBack? http://msdn.microsoft.com/en-us/library/ms597491.aspx
If IsEditable is marked as virtual, it should be trivial to just do
bool iseditableSet=false;
override bool IsEditable
{
get;
set
{
if(!iseditableSet){
iseditableSet=true;
base.IsEditable=value;
}else{
throw Exception...
}
}
If it's not marked as virtual, it's harder, but you can use "hiding" to prevent at least your own code from modifying the property without a very explict base. directive.. Of course, this is physically impossible to do though if you are dealing with a function that takes Combobox and it could possibly modify those properties. Just take it as a lesson why properties should almost always be virtual

Categories