Nested classes, Dependency Properties, keeping code that logically goes together near each other.

I'm looking at how we currently write WPF MVVM code using bindings, and I'm seeing a problem.

I'm also thinking my attempt at solving this problem is reinventing the wheel. I can't be the first person to encounter this.

(And I'm suspecting that the solution has something to do with Dependency Properties, which I keep hearing about.)

We currently do something like this:
private string myStr;
public string MyStr
{
    get
    {
        return myStr;
    }
    set
    {
        if (myStr != value)
        {
            myStr = value;
            NotifyPropertyChanged();
        }
    }
}

Open in new window

[NotifyPropertyChanged() uses magic to fill in the missing parameter.]

The first problem is our coding standard specifies that all private fields must go at the top of the code file, while all public properties must go in the middle of the code file. So the myStr field gets separated from the corresponding MyStr property in the code. They're in two different places in the code file. I keep scrolling up and down to find them.

I thought, let's try making this a nested class and see what happens. Maybe that way I can keep the myStr field and MyStr property together where they belong.

public class MyClass
{
    public class MyStrClass
    {
        private string myStr;
        public string MyStr
        {
            get
            {
                return myStr;
            }
            set
            {
                if (myStr != value)
                {
                    myStr = value;
                    NotifyPropertyChanged();
                }
            }
        }

        public MyStrClass()
        {
        }
    }

    public MyClass()
    {
        var myStrClass = new MyStrClass();
        myStrClass.MyStr = "Hello World!";
    }
}

Open in new window

Then I think, well I have a half dozen strings I need to define. I don't want to create a separate class for each one, e.g.
MyStr1Class
MyStr2Class
MyStr3Class
...

Open in new window

That's silly. (Though the original code currently has a private field and a public property for each string, so it's kind of like having a separate class for each string.)

So let's make one class which does it all, so I can do:
var myStr1Class = new MyStrClass();
var myStr2Class = new MyStrClass();
var myStr3Class = new MyStrClass();
...

Open in new window

There. Now my only problem is I need each class to give a different notification depending on what string it's holding. Right now all my classes will give the same notification: NotifyPropertyChanged("MyStrClass").

So, how to deal with this. Maybe I can pass in the name of the specific string the class holds as a parameter.

var myStr1Class = new MyStrClass("MyStr1");
var myStr2Class = new MyStrClass("MyStr2");
var myStr3Class = new MyStrClass("MyStr3");
...

Open in new window

Now my code looks something like:
public class MyClass
{
    public class MyStrClass
    {
        private string name;
        private string myStr;
        public string MyStr
        {
            get
            {
                return myStr;
            }
            set
            {
                if (myStr != value)
                {
                    myStr = value;
                    NotifyPropertyChanged(name);
                }
            }
        }

        public MyStrClass(string name)
        {
            this.name = name;
        }
    }

    public MyClass()
    {
        var myStr1Class = new MyStrClass("MyStr1");
        var myStr2Class = new MyStrClass("MyStr2");
        var myStr3Class = new MyStrClass("MyStr3");
        myStr1Class.MyStr = "Hello World!";
        myStr2Class.MyStr = "Goodbye World!";
        myStr3Class.MyStr = "Xyzzy!";
    }
}

Open in new window

Then I think, well, strings are nice, but I also need some integers. So I'll make a separate class for integers, and a separate class for double, and a...

No of course I won't do that. I'll just use a generic <T>

Now my code looks something like (I'm just writing this from memory so the syntax probably isn't quite right. It's close enough):
public class MyClass
{
    public class MyPropertyClass<T>
    {
        private string name;
        private T myVar;
        public T MyVar
        {
            get
            {
                return myVar;
            }
            set
            {
                if (myVar != value)
                {
                    myVar = value;
                    NotifyPropertyChanged(name);
                }
            }
        }

        public MyStrClass(string name)
        {
            this.name = name;
        }
    }

    public MyClass()
    {
        var myStr1Class = new MyPropertyClass<string>();
        var myInt1Class = new MyPropertyClass<int>();
        myStr1Class.MyVar = "Hello World!";
        myInt1Class.MyVar = 42;
    }
}

Open in new window

Next I think about bindings. Someone else will be watching this. Maybe I have an integer in the Model, but I need to display it as a string in the View. Now I need a "integer to string" converter somewhere. (OK this one is trivial. Maybe it's a Farenheit to Celcius converter, or something more romantic.) The converter code kind of goes together with this, but it will probably end up in a separate part of the code file because of our coding standards, unless I can somehow keep it all together.

Now I'm thinking, do I need to pass converter code into my nested class?

And at this point I think, I should really ask some experts on Experts Exchange, rather than continue to reinvent the wheel. There's probably already a simple solution to all this.

My original problem: Code is very verbose, and the fields are separated from the corresponding properties because company coding style dictates fields get grouped together and properties get grouped together. Is there an easier way of doing this? I just need a variable that notifies when it's updated. And I don't want it to be a maintenance headache.
deleydSoftware EngineerAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

it_saigeDeveloperCommented:
The simple solution is to suggest that you utilize a paradigm known as Aspect Oriented Programming.  There are libraries available that do already provide the basic functionality that you are wanting to implement.  One of these is PostSharp (PostSharp does require a license but you can always trial it).  Using PostSharp we can add the NotifyPropertyChanged aspect to your class(es); e.g. -
using PostSharp.Patterns.Model;
using System;
using System.ComponentModel;

namespace EE_Q29074107
{
    class Program
    {
        static void Main(string[] args)
        {
            Person bob = new Person { ID = 1, FirstName = "Bob", LastName = "Smith" };
            ((INotifyPropertyChanged)bob).PropertyChanged += OnPropertyChanged;

            Console.WriteLine("The original bob");
            Console.WriteLine(bob);
            Console.WriteLine();
            Console.WriteLine("Let's change bob's last name.");
            bob.LastName = "Johnson";
            Console.WriteLine("The new bob");
            Console.WriteLine(bob);
            Console.ReadLine();
        }

        static void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            Console.WriteLine($"{sender} is changing a property; {e.PropertyName}");
        }
    }

    [NotifyPropertyChanged]
    class Person
    {
        public int ID { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }

        public override string ToString()
        {
            return string.Format($"{FirstName} {LastName} [{ID}]");
        }
    }
}

Open in new window

Which produces the following output -Capture.PNGYou can read more about PostSharp NotifyPropertyChanged here: http://doc.postsharp.net/inotifypropertychanged-add

-saige-
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
WPF

From novice to tech pro — start learning today.