"Soft updating" DependencyProperties? - c#

I've got a WPF app that's using INotifyPropertyChanged to signal property updates. What I like about it is that it gives you the ability to signal a property change without invoking all of the setter code. This is handy when you've got two linked fields that update each other or when you've got code that saves changes on every setter and you don't want to trigger the save multiple times for what is essentially one change by the user.
However the obvious weakness of this approach is that a mistake in the property name or on which viewmodel you send the notification to will mess you up and only show up and runtime.
I looked into dependency properties but was unable to find anything that lets you do a "soft update": let the UI know that the property has changed but avoid calling all the code that would normally run when a UI causes a change in the viewmodel.
Is there some way I can get a property system that allows soft updates and catches notification problems at compile-time?

If the underlying problem is mistakes in the property name, there are compile-time solutions, like making the "property name" parameter an expression tree instead of a string.
http://michaelsync.net/2009/04/09/silverlightwpf-implementing-propertychanged-with-expression-tree
The Caliburn.Micro library also includes this approach in its PropertyChangedBase class.

I like Foson's solution for "early binding" vis a vis the property names and eliminating the need to keep a string copy of your property name around. This is the core of the implementation I, personally, use:
public virtual string GetName<T>(Expression<Func<T>> expression)
{
return GetMemberName(expression);
}
/// <summary>Abstraction for actually finding the name of the target of the expression</summary>
private static string GetMemberName<T>(Expression<Func<T>> expression)
{
if (expression != null)
{
var myMemberExpression = expression.Body as MemberExpression;
if (myMemberExpression != null && myMemberExpression.Member != null)
{
return myMemberExpression.Member.Name;
}
}
return string.Empty;
}
This code resides in a class called NameResolver, which my ViewModelBase class wraps with
NotifyChange(Expression<Func<T>> expression)
Then client code looks something like:
private int _myBindable;
public int MyBindable { get { return _myBindable; } set { _myBindable = value; NotifyChange(() => MyBindable); }
As to the notion of separating GUI notification from updating underlying stuff, you can invoke those NotifyChange() methods elsewhere than the property setter when whatever happens in your code that should trigger UI update happens. So, GUI sets your property, which triggers some logic, but you don't raise change notification there -- you raise it from wherever, specifically, you want to inform the UI about something.

Related

Entity Framework adding functionality to Properties

In an old WPF project I have a class with Properties like this:
private string _name = "";
public string Name
{
get { return _name; }
set
{
string cleanName = clsStringManip.CleanText(value, true);
if (cleanName != _name)
{
_name = cleanName;
}
}
}
Where every time the name changes, I ensure that the value is "cleaned". Putting it in the property ensures I never forget to clean the string before setting the property on the object.
Now I am recreating this system using MVC5 and EntityFramework6.1 using DatabaseFirst.
So all the properties are autogenerated by EF. How then can I add the equivalent CleanText function to my properties without editing the autogen code? - as I'll lose these changes next time I change my database and resync.
All I can find via Google is a way add data annotations via MetadataType and partial classes but this doesn't answer my question.
I tried to add the above code into a partial class but get the error:
The type XXX already contains a definition for Name
The only way I can think is to create a bunch of SetProperty() functions but this is dirty and you can never ensure other developers (or myself) will remember to use them.
Disclaimer: I haven't used EF 6 yet.
Let me answer this in two parts. First, I will tell you how to do this. Then I will tell you why I don't think you should do this. :-)
HOW:
As you discovered, you cannot create another Name property. You need to modify the way the EF generates the code, so that it gives you a place to insert your new code. Depending on how you are using the EF, it often generates Validate() method calls or OnPropertyChanged() calls. You may be able to do what you want inside of those methods.
If you can't do this in Validate() or OnPropertyChanged(), you could change the T4 template to generate something like this:
private string _name = "";
public string Name
{
get { return _name; }
set
{
string cleanName = value;
Cleanup_Name(ref cleanName);
if (cleanName != _name)
{
_name = cleanName;
}
}
}
private partial void Cleanup_Name(ref string);
This gives you a partial method that you can then implement as you see fit. So for any property you want to customize, you can now add another file to your project that does this:
public partial class MyEntity {
void Cleanup_Name(ref string name)
{
// Put your logic in here to fixup the name
}
}
If you do not write the above code block, then the partial method is simply a no-op. (Partial methods must return void, hence the use of a ref parameter).
WHY NOT?
The advantage of this method is that it is totally transparent to the developer. The property is just magically changed. But there are several disadvantages:
Some controls expect that if they call name = "123" that if they get the name back, it is "123" and will fail if this happens. Values are changing but no PropertyChanged event fired. If you do fire the PropertyChanged, then they sometimes change the value back. This can cause infinite loops.
There is no feedback to the user. They typed in one thing, and it looked right, but now it says something different. Some controls might show the change and others won't.
There is no feedback to the developer. The watch window will seemingly change values. And it is not obvious where to see the validation rules.
The entity-framework itself uses these methods when it loads data from the database. So if the database already contains values that don't match the cleanup rules, it will clean them when loading from the database. This can make LINQ queries misbehave depending on what logic is run on the SQL server and what logic is run in the C# code. The SQL code will see one value, the C# will see another.
You might also want to look into what the Entity-Framework's change tracking does in this case. If a property set does a cleanup while loading values from the database, does it consider that a change to the entity? Will a .Save() call write it back to the database? Could this cause code that never intended to change the database to suddenly do so?
ALTERNATIVE
Instead of doing this, I suggest creating a Validate() method that looks at each property and returns errors indicating what is wrong. You could also even create a Cleanup() method that fixes the things that are wrong. This means the cleanups are no longer transparent, so the developer must call them explicitly. But that is a good thing: the code isn't changing values without them realizing it. The person writing the business logic or the UI knows at what point the values will change, and can get a list of why.
The only way you can achieve this is by creating a new property you actually use in your application. Perhaps you can hide the original property in the designer. The actual property you use could look like this:
public string ExternalName
{
get { return Name; }
set
{
string cleanName = clsStringManip.CleanText(value, true);
if (cleanName != Name)
{
Name = cleanName;
}
}
}
As an alternative, you can use POCO classes:
If you want to keep using database-first, check this answer
Use code-first for an existing database, see this detailed guide
Add partial to the generated class.
Change the scope of Name in the generated class from public to internal.
Add the following in the same assembly:
public partial class classname
{
[NotMapped]
public string CleanName
{
get { return Name; }
set
{
var cleanName = clsStringManip.CleanText(value, true);
if (cleanName != Name)
Name = cleanName;
}
}
}
Caveat: you'd have to remember to do steps 1-2 every time you regenerated your POCOs ... I'd seriously consider Code First to Existing Database.
EDIT
Optionally:
Rename Name as InternalName in the generated classname; decorate it with [Column("Name")].
Rename CleanName as Name in the partial class under your control.
Caveat in 4 becomes "remember to do steps 1, 2, and 5 every time you regenerate POCOs".
This approach has the added benefit of not having to modify any of your client code (i.e., use of Name remains Name). And I'd still strongly consider Code First to Existing Database.

WPF: property similar to WinForms Modified

In WinForms controls like a TextBox have property Modified that gets value "true" after changing the control's content and may be set to "false" manually. Their WPF analogues seem not to have such property (neither IsModified in new naming style). So do I have to handle their modifying events myself or there's some more convenient way?
For example I have few textboxes and a function, which combines their contents into one document for preview. Opening the preview I want to keep an old content for the document, if none of the textboxes was changed or to call the function to produce new document's content if at least one textbox was edited.
In WPF it's easier to control everything through ViewModel/Model... This might be too much/not what you're looking for. But through experience, I feel that the pattern below pays off in easy usage.
Wrap your simple data class (with all the properties that it is using now/in your question now) in a class/Model that implements IEditableObject, INotifyPropertyChanged and possibly IEquitable. Lets call your class Data.
In a wrapper class create fields:
Data _current;
Data _proposed;
Data _previous;
IEditableObject requires you to implement BeginEdit(), EndEdit() and CancelEdit().
in them you need to control the state _current, proposed, and previous. For example,
public void CancelEdit()
{
_current = _previous;
_proposed = null;
}
public void EndEdit()
{
_previous = _proposed;
}
public void BeginEdit()
{
_proposed = _current;
}
You might need more logic in methods above, so this is just an example. The key of knowing if your object has changes is implementing a flag, lot's of people call it IsDirty:
pubic bool IsDirty { get { return _current != _previous; } }
Now the user of this class can easily check the state. Oh, and on more thing each property would have the following mechanism:
public string Example
{
get { return _current.Example;}}
set
{
if(_current.Example == value) return;
BeginEdit();
_current.Example = value;
RaisePropertyChanged (() -> Example);
}
}
What's nice about implementing IEditableObject, all controls respond to it, DataGrid is a good example and also you can easily return to the original state by cancelling edit.
Anyway, there are lots of samples that you should browse for. I just hope to can get you started onto that path...
P.S. this pattern was used before WPF came out, its super common in WinForms as well
WPF doesn't have that because UI is not Data and therefore your UI is not the right place to store information about whether your data has changed or not.
Crappy dinosaur winforms doesn't allow a clean and true separation between UI and application logic/data and therefore has all sorts of horrible hacks in order to mash together these completely separate concepts.
You must learn to develop correctly, using the MVVM pattern. Then you will realize there's no sense in placing state data on any UI elements.

What is difference between this.PropertyName and _PropertyName?

as I often let LinqToSql generate partial entity classes, I am wondering if my practice of adding additional properties via code is correct and if there is a better way of doing the same thing? I am also wondering what is the difference between accessing the values of other properties using this.PROPERTY_NAME vs _PROPERTY_NAME?
In my web app I keep using this.PROPERTY_NAME, but I am wondering if that is, as I already said in opening sentence, the proper approach I should be using. Also, What is _PROPERTY_NAME and when do we use it?
Example:
public partial class User
{
public bool IsThisProper {
get{
return this.SomeIntProperty == 10; // I usually use this
}
}
public bool WhenToUseThisApproach {
get{
return _SomeIntProperty == 10; // What is this in comparison to above?
}
}
}
One is the property, and the other is the private backing field in which that property stores it's value. If you want to execute whatever code the property has in it's getter/setter, then use the property, if you don't, then don't. Chances are you want to use the property, not the field, especially with setting (setting it triggers the property changed event, so about the only time to use the property is if you don't want that event raised).

How to catch an exception thrown during a PropertyChanged event

I am using MVC\MVVM and WPF. I have a form that is bound to a model and a controller that is catching the PropertyChanged events and evaluating business rules and validations.
Well, I want to pop-up a message when a validation is false telling the user what is wrong and how to fix it. But I'm not sure the "correct" way from the controller. I'd like to throw an exception that can be caught by the view but I can't figure out how.
I've tried Dispatcher.Invoke() but that just got me an unhandled exception at the application level.
How do I trap exceptions that are generated from the PropertyChanged event handler in the Controller?
EDIT: Specifically I have a combobox that has a list of discounts in it. I can't allow an inappropriate selection, but I have to notify the user why the selection is inappropriate. This is not as obvious as a textbox that has integers in it. I need to tell the user the date the customer filled out a survey. They can't use that discount twice. I don't want to exclude the survey discount from the list since that would just look like an error to the user. I need to show them the discount and tell them the customer has used that discount and cannot use it again.
EDIT 2: I have looked over the ValidationRule class and since I have to use a database lookup I don't see how I'm going to keep everything in the Model and still have the business rules in the Controller. I've looked at IDataErrorInfo but that requires me to wrap my Model in my Controller and bind to the Controller instead, but only for one field. I think the best course of action in this case is to have the Controller call a method on the View and pop-up a message.
You are walking down the wrong path.
A good way to handle validation in MVVM is by implementing IDataErrorInfo and setting ValidatesOnDataErrors to true on your bindings. You will also almost certainly want to enable ValidatesOnExceptions for completeness, and NotifyOnValidationError so that the binding engine triggers the Validation.Error attached event on the control that you have bound the property to.
For more details, see the Validation section on the MSDN documentation for data binding in WPF.
Some tips:
.NET 4.5 introduces INotifyDataErrorInfo and the corresponding ValidatesOnNotifyDataErrors binding property that provide beefed-up validation functionality in comparison to IDataErrorInfo; you might want to look into that.
You do not need to actually do anything meaningful inside IDataErrorInfo.Error because it is used by the Windows Forms infrastructure and is ignored in WPF. You can even have the getter throw NotImplementedException.
There is good reading material illustrating this approach, complete with examples and code, here and here.
Update: clarification and example code
This validation model does not involve implementing a ValidationRule yourself at all; your models (i.e. the binding sources) simply need to implement one of the two interfaces. How to implement the interface is entirely up to you; in a past project I implemented basic async validation with
public interface IDelegatedValidation : IDataErrorInfo
{
/// <summary>
/// Occurs when validation is to be performed.
/// </summary>
event EventHandler<DelegatedValidationEventArgs> ValidationRequested;
}
public class DelegatedValidationEventArgs : EventArgs
{
public DelegatedValidationEventArgs(string propertyName)
{
this.PropertyName = propertyName;
}
public string PropertyName { get; private set; }
public bool Handled { get; set; }
public string ValidationError { get; set; }
}
The model implements IDelegatedValidation by exposing an event and with
string IDataErrorInfo.this[string columnName]
{
get { return this.GetValidationError(columnName); }
}
private string GetValidationError(string propertyName)
{
var args = new DelegatedValidationEventArgs(propertyName);
this.OnValidationRequested(args);
return args.ValidationError;
}
protected virtual void OnValidationRequested(DelegatedValidationEventArgs args)
{
var handler = this.ValidationRequested;
if (handler == null) {
return;
}
foreach (EventHandler<DelegatedValidationEventArgs> target in handler.GetInvocationList()) {
target.Invoke(this, args);
if (args.Handled) {
break;
}
}
}
So the workflow goes like this:
When the model is about to be wrapped by a viewmodel, some appropriate entity that can perform the validation subscribes to its ValidationRequested event.
The view binds to the model; at some point validation is triggered.
The model calls GetValidationError.
Event handlers get invoked one by one; the first handler that produces a validation error sets args.ValidationError and args.Handled to true so that the chain is stopped.
The validation error is returned to the view.
There is an added twist in that if the viewmodel needs to know whether its model is valid or not (e.g. to enable/disable a "save" command) it needs to also tap into this process.
There's really nothing that you cannot do with IDataErrorInfo / INotifyDataErrorInfo because how you implement them is entirely up to you. Definitely have a look at the Silverlight version of the latter's documentation for more examples; there is also a lot of helpful material like this on the internet.

When using MVVM pattern, should code relating to property changes go in the setter or an event?

Looking for guidance on where to place code which is dependent upon changes to a property.
For example, I have a view model which is used to hold state for an applications settings
public SettingsViewModel(ISettingsRepository settings)
{
_settings = settings;
// ...
}
For each change to a settings property we have to persist this change to the repository, and on some properties, other properties are affected, so additional code is required.
I started off just adding this logic to the setter
public ProjectCollection Projects
{
get { return _projects; }
set
{
if (_projects == value) return;
_projects = value;
RaisePropertyChanged("Projects");
// Extra work needed when collection of projects change
_settings.SaveProjects(_projects);
Startable = _projects != null && _projects.Count > 0;
}
}
But then swapped over to wiring up the PropertyChanged event for INotifyPropertyChanged and removed the additional code out of the property setter
public SettingsViewModel(ISettingsRepository settings)
{
_settings = settings;
// ...
PropertyChanged += onPropertyChanged;
}
void onPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "Projects":
_settings.SaveProjects(Projects);
Startable = Projects != null && Projects.Count > 0;
break;
// ...
}
}
public ProjectCollection Projects
{
get { return _projects; }
set
{
if (_projects == value) return;
_projects = value;
RaisePropertyChanged("Projects");
}
}
Having the logic inside the setter means less code to write, less chance of making a mistake wiring up the wrong property name (unit test should pick this up though) and would be slightly faster, although probably insignificant.
Having the logic wired up to an event seems to be a more maintainable approach, so long as the methods are appropriately named it should be easier to follow the code, and means the setter isn't doing other work besides setting the property. I'm guessing it might also provide more flexibility, using the example above, if the requirements changed so that persisting of changes happened from another event e.g. "Save" button click instead property change, then the code should be easier to change.
I appreciate this is a subjective question, but I'm new to the MVVM pattern (although I guess it may hold true for any setter logic?) so am looking for other reasons before I settle on an approach. Thanks!
When deciding what code to put where, remember this: a ViewModel is for presenting the data to the View. It can massage or manipulate the data a little to do so (within reason of course - changing a value to a color could be considered absolutely fine to do). The ViewModel doesn't know anything about the UI, and it doesn't know anything about saving data.
The property setters should be kept as simple as possible, and they should notify if anything relies on them (which mostly will be the case - the VM is used for binding). This means that your second example utilizing the OnPropertyChanged() event handler is a far better option than the first example.
However, it still knows too much for my liking. I would raise events which the Model can subscribe to, and let the Model do the work. The ViewModel should just say "hey, my data has changed, I don't care what you do about it but i've told you so do whatever you like". The Model can then either save instantly, or what till more changes have taken place before persisting the data.

Categories