1

I want to simplify the property declarations in my classes. The problem is the getter and setter definition. I am doing exactly the same for hundreds of properties. All properties are created like this, where the method "LogPropertyChanged" also RaisePropertyChange.

public class PCS_MA_V1_ALARMSTAT : ViewModelBase
{
    private Boolean _ActionAlarmHighHigh;
    public Boolean ActionAlarmHighHigh
    {
        get
        {
            return _ActionAlarmHighHigh;
        }
        set
        {
            if(value!= _ActionAlarmHighHigh)
            {
                _ActionAlarmHighHigh = value;
                LogpropertyChanged("ActionAlarmHighHigh", oldVal, newVal);
            }

        }
    }
    private Boolean _ActionAlarmLowLow;
    public Boolean ActionAlarmLowLow
    {
        get
        {
            return _ActionAlarmLowLow;
        }
        set
        {
            if(value!= _ActionAlarmLowLow)
            {
                _ActionAlarmLowLow = value;
                LogpropertyChanged("ActionAlarmLowLow", oldVal, newVal);
            }

        }
    }
}

Now i think this syntax is much to complex, and a huge hasle to work with. Is there a way where i could create the class like this:

public class PCS_MA_V1_ALARMSTAT: ViewModelBase
{
    public Boolean ActionAlarmHighHigh { get; set; }
    public Boolean ActionAlarmLowLow { get; set; }
}

And then monitor the instance. If a property has changed i run LogPropertyChanged on that particular property. Is this possible?

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
jsandv
  • 276
  • 4
  • 20
  • 2
    You're the second one to ask that question today. The answer is "no" for you, too. What people *do* do here is write a `SetProperty(ref T propertyField, [CallerMemberName] String propName = null)` method that sets the field and raises `PropertyChanged` if the value changed, and it could log as well. BTW I would at the very least rename `LogpropertyChanged` to something that doesn't imply that it MERELY does logging. Not a bad idea for a method, but very misleading name. – 15ee8f99-57ff-4f92-890c-b56153 Sep 09 '16 at 19:39
  • And then [write a snippet](https://swissarmycrowbar.wordpress.com/2016/07/19/viewmodel-property-snippets-c6/) to create the property definitions, if you're using Visual Studio. – 15ee8f99-57ff-4f92-890c-b56153 Sep 09 '16 at 19:40
  • @EdPlunkett I have allready created a program which generates these classes. It creates thousands of lines. The problem is that now i have to maintain that application as well... ;) If you have the time i would much appriciate your answer in code. Im not sure how to implement it with you approach. – jsandv Sep 09 '16 at 19:45
  • [Here's an example](http://www.codeproject.com/Articles/38865/INotifyPropertyChanged-auto-wiring-or-how-to-get-r.aspx) how you could use Aspect Oriented Programming to refactor the redundancy into simple attributes. Though, if you're not familiar with attributes and AOP, I think it may be hard to pick up. As far as I know, there aren't libraries that include these attributes. – Swimburger Sep 09 '16 at 19:46

1 Answers1

0

You can't override the default behavior of get and set, unfortunately.

What you can do is write a ViewModelBase like this. It's a common idiom. My code below is mostly stolen from this answer, and Prism's BindableBase has a similar SetProperty<T> method, but I didn't go looking for their implementation. There can't be all that much to it.

using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace HollowEarth.MVVM
{
    public class ViewModelBase : INotifyPropertyChanged
    {
        #region SetProperty
        protected virtual bool SetProperty<T>(ref T backingField, 
            T newValue, 
            [CallerMemberName] String propName = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingField, newValue))
            {
#if DEBUG
                System.Diagnostics.Trace.WriteLine(
                    $"No change in {propName} == {backingField}");
#endif
                return false;
            }

#if DEBUG
            System.Diagnostics.Trace.WriteLine(
                $"Changing {propName} from {backingField} to {newValue}");
#endif

            backingField = newValue;
            OnPropertyChanged(propName);

            return true;
        }
        #endregion SetProperty

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(
            [CallerMemberName] String propName = null)
        {
            PropertyChanged?.Invoke(this, 
                new PropertyChangedEventArgs(propName));
        }
        #endregion INotifyPropertyChanged
    }
}

And use it like so:

public class MyViewModel : ViewModelBase
{
    #region Whenever Property
    private DateTime? _whenever = default(DateTime?);
    public DateTime? Whenever
    {
        get { return _whenever; }
        set { SetProperty(ref _whenever, value); }
    }
    #endregion Whenever Property
}

I write Visual Studio snippets to generate properties. You said that you're generating all this stuff programmatically so snippets aren't an immediate requirement, but it's something to keep in mind.

Another possibility, if maintainability of generated code is a concern, to use partial classes. Put the generated code in separate files that are never edited by hand (much like Form1.Designer.cs/Form1.resx in winforms), and maintain the input files that are used to generate those files. Set up your generator as a build action for whatever your input files are.

For a meta-level witticism on the subject of maintainability, write the partial class generator in Perl.

Community
  • 1
  • 1