1

I'm on my second WPF project and ran into a uncomfortable situation. This is my model:

public class Layout
{
    public string Name { get; set; }
    public Motor Motor { get; set; }
}

public class Motor
{
    public string Property1 { get; set; }
    ...
    public string Property150 { get; set; }
}

This is my MainViewModel:

public class MainViewModel : ViewModelBase
{
    public Motor Motor {get; set;}
    ...
}

Ok, I have bound all 150 properties of the motor class to textboxes:

<TextBox Text="{Binding Layout.Motor.Property1}"/>

Problem 1) if I want to trigger an action whenever a user changes one of these, will I have to implement this 150 times??

    private string property1 { get; set; }
    public string Property1
    {
        get { return property1; }
        set
        {
            property1 = value;
            RaisePropertyChanged(() => Property1);
        }
    }

Problem 2) will I have to implement this in the MainViewModel, in the model "Motor" or would I need a "MotorViewModel"? Any of these would mean a lot of copy&paste and totally useless coding..

Thank you for any help and feedback!

peter
  • 2,103
  • 7
  • 25
  • 51

2 Answers2

2

First off, RaisePropertyChanged is really for the UI, to notify it when code changes the item. Of course, you can manually listen for it as well, but you usually don't.

You also usually don't use an auto-property as the backing field, but that may be due to your PropertyChanged implementation.

Now that that's out of the way:

Yes, you would need to implement that, or something similar that allowed PropertyChanged to be raised the 150 times. Now, one wonders why on earth you have 150 properties on an object, so you may want to reconsider that design first. But if you really do need them, then yes, copy-paste is in your future. Consider writing a code snippet to make it go faster.

To answer your other question, you could easily put it in the "model" object as long as that object can serve as a DTO. In other words, it isn't actually tied to the model in some way (say, with model functionality) but can float between layers. You can even put INPC on data contracts, it doesn't hurt anything.

One other thing to consider, if you only want to notify the UI when the motor changes as opposed to its individual properties, you can just notify on the Motor property and all the bindings will update.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • No, he doesn't have to do that. There are many different ways to handle this situation. You can use PropertyDescriptors, dynamic features of the framework, etc. You're probably right that this is smelly. –  Apr 09 '15 at 21:13
  • @Will All of that is effectively just hiding the same exact code (except for the dynamic one). Sure, its cleaner, but its still very much the same thing. Edited to indicate that there are ways to make it cleaner – BradleyDotNET Apr 09 '15 at 21:15
  • 1
    It isn't the same at all, as your description of what a PITA it is to write these INPC properties over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over and over again illustrates. –  Apr 09 '15 at 21:17
  • 1
    @Will I'm not sure you actually got that 150 times ;) – BradleyDotNET Apr 09 '15 at 21:18
1

Dynamic to the rescue!

public class DynamicDictionary : DynamicObject, INotifyPropertyChanged
{
    private readonly Dictionary<string, object> dictionary;

    public DynamicDictionary(Dictionary<string, object> dictionary)
    {
        this.dictionary = dictionary;
    }

    public override bool TryGetMember(
        GetMemberBinder binder, out object result)
    {
        return dictionary.TryGetValue(binder.Name, out result);
    }

    public override bool TrySetMember(
        SetMemberBinder binder, object value)
    {
        dictionary[binder.Name] = value;
        // magic!
        OnPropertyChanged(binder.Name);
        return true;
    }

    #region INPC implementation
    // SNIP!  I ain't writing all that junk out
    #endregion
}

(Most of this code ganked from this answer)

Bindings recognize types that implement IDynamicMetaObjectProvider, as DynamicObject does, and knows how to use them. Try it and see.

Community
  • 1
  • 1
  • Ugh... dynamic. Compared to 150 full property definitions though, I guess I would seriously consider it if I were writing it. – BradleyDotNET Apr 09 '15 at 21:11