简体   繁体   中英

MVVM pattern for raising dependent property RaisePropertyChanged events

I have some read-only properties that return a value based on sibling properties within the view-model. In order to bind them to the XAML I need to add extra RaisePropertyChanged events to the sibling properties. This feels a little inelegant.

A simplified example:

public bool IsPurchased
{
    get
    {
        return _IsPurchased;
    }
    set
    {
        if (_IsPurchased == value) return;
        _IsPurchased = value;
        RaisePropertyChanged("IsPurchased");
        RaisePropertyChanged("IsAvailableToUse");
    }
}
private bool _IsPurchased = false;

public bool IsDownloaded
{
    get
    {
        return _IsDownloaded;
    }
    set
    {
        if (_IsDownloaded == value) return;
        _IsDownloaded = value;
        RaisePropertyChanged("IsDownloaded");
        RaisePropertyChanged("IsAvailableToUse");
    }
}
private bool _IsDownloaded = false;

public bool IsAvailableToUse
{
    get
    {
        return IsPurchased && IsDownloaded;
    }
}

Does anyone have a nice pattern that will do away with the extra RaisePropertyChanged("IsAvailableToUse") 's within the contributing properties themselves and make such scenarios easier to manage? Perhaps adding these sorts of mappings in a centralized place within the view-model.

As far as I know that pattern is fairly common in MVVM. If you want to group all the properties together you could override your implementation of RaisePropertyChanged to handle grouped cases in the following way.

   protected override void RaisePropertyChanged(string propertyName = null)
    {
        PropertyChangedEventHandler handler = this.PropertyChangedHandler;
        switch (propertyName)
        {
            case "IsDownloaded":
            case "IsAvailableToUse":
            case "IsPurchased":
                if (handler != null) handler(this, new PropertyChangedEventArgs("IsDownloaded"));
                if (handler != null) handler(this, new PropertyChangedEventArgs("IsAvailableToUse"));
                if (handler != null) handler(this, new PropertyChangedEventArgs("IsPurchased"));

                break;
            default:
                if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
                break;
        }
    }

On an unrelated note, I noticed one of your properties is named "IsAvailableToUse" and seems like that property may be a switch for a command binding. If you're enabling/disabling a button based on this boolean value then I'd recommend declaring an ICommand and CanExecute. It can be more elegant since buttons have this useful and elegant feature built in by the framework.

Have a look at this https://github.com/steinborge/ProxyTypeHelper . It would do your MVVM/WPF and automatically wire up propertychangedevents. So your example would like this:

    public bool IsDownloaded {get;set;}
    public bool IsPurchased { get; set; }

    [LinkToProperty("IsDownloaded")]
    [LinkToProperty("IsPurchased")]
    public bool IsAvailableToUse
    {
        get
        {
            return IsPurchased && IsDownloaded;
        }
    }

    [LinkToCommand("PurchaseCommand")]
    private void btnPurchase()
    {
    }

    [LinkToCommand("DownloadCommand")]
    private void btnDownload()
    {
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM