Why doesn't anyone use the INotifyPropertyChan

2019-01-26 05:46发布

问题:

I know MVVM heavily uses the INotifyPropertyChanged, but I have never seen any usage of the INotifyPropertyChanging. Any reason why?

If I did want to use this, what would be a good way to integrate this into my MVVM Framework? I know you're not supposed to use MessageBox on your ViewModel because then you can't unit test it. So how would one go about throwing up an alert, then continuing on with the PropertyChange if applicable?

回答1:

Something to keep in mind about INotifyPropertyChanging is you can't stop the change from happening. This merely allows you to record that the change occurred.

I use it in a framework of mine for change tracking, but it isn't an appropriate method for halting changes.

You could extend your ViewModelBase with a custom interface/event pair:

delegate void AcceptPendingChangeHandler(
    object sender,
    AcceptPendingChangeEventArgs e);

interface IAcceptPendingChange
{
    AcceptPendingChangeHandler PendingChange;
}

class AcceptPendingChangeEventArgs : EventArgs
{
    public string PropertyName { get; private set; }
    public object NewValue { get; private set; }
    public bool CancelPendingChange { get; set; }
    // flesh this puppy out
}

class ViewModelBase : IAcceptPendingChange, ...
{
    protected virtual bool RaiseAcceptPendingChange(
        string propertyName,
        object newValue)
    {
        var e = new AcceptPendingChangeEventArgs(propertyName, newValue)
        var handler = this.PendingChange;
        if (null != handler)
        {
            handler(this, e);
        }

        return !e.CancelPendingChange;
    }
}

At this point you'd need to add it by convention to your view models:

class SomeViewModel : ViewModelBase
{
     public string Foo
     {
         get { return this.foo; }
         set
         {
             if (this.RaiseAcceptPendingChange("Foo", value))
             {
                 this.RaiseNotifyPropertyChanging("Foo");
                 this.foo = value;
                 this.RaiseNotifyPropretyChanged("Foo");
             }
         }
     }
}


回答2:

INotifyPropertyChanging is an optimization for use with Linq to SQL. When an object implements this interface, it uses the changing event as the signal to cache the old value of the property. If the object doesn't implement this interface, then it will always cache the property values, increasing memory usage. See How does INotifyPropertyChanging interface helps limit memory consumption for more details.



回答3:

To answer the second question, you could always use the Dependency Injection pattern to make your VM rely on an interface (INotifier?) and pass in a concrete implementation which pops up MessageBoxes. This leaves unit-testability intact.

Edit: The first question is probably too subjective for SO. The intent of the interface is clear but when to use it would be for very specific use cases. Dependency properties raise something similar and it can be useful for checking the new value is valid before applying it but if you're using simple properties then you could more simply put this check inside your setter. If a different component needs to check the validity then it would normally be simpler if that component made the change itself (after validating the new value) or was called explicitly to validate the change by the component making the change.



回答4:

INotifyPropertyChanging gets invoked right before a property changes. Important why? So that an external event handler can throw an exception and prevent the change. And why would you want to do that? Someday it might be your only workaround to a bug in someone else's code base, so don't be so quick to remove the escape hatch.



回答5:

You need INotifyPropertyChanged for example if you want to know when any variable will be changed because you can use the PropertyChangedEventHandler. On this way you can reload the gui while running the program if any dependency property which is bound at any gui element.

For the last question i think you can write a log file with your defined messages and if you want to show the user any alert you can use controls like error summary or tooltips. But if you only need this for testing you can keep the alerts under with try and catch blocks.



标签: c# wpf mvvm