views:

126

answers:

3

So I've got a whole bunch of options, every different page/tab can have their own local options. We'll have maybe 10-15 pages tabs open tops. I need to implement a way to show the global defaults, weather the all the tabs have consistent values. I'm working on the model/viewmodel portion of a WPF app.

I'd love to find a way that is more elegant since I'm having to cut and past roughly the same code 20+ times and just change property names. Maybe this is the problem Dynamics solve, but right now this feels both wrong and painful.

Here is an example of my current solution:

public class Foo
{
    private bool fooVar1;
    private bool fooVar2;
    //lots of these
    private decimal fooVar23;

    public Foo()
    {
    }

    public bool FooVar1
    {
        get;
        set;
    }

    //you get the picture...
}

public class FooMonitor
{
    private Foo defaultFoo;
    private List<Foo> allFoos;

    public FooMonitor(Foo DefaultFoo)
    {
        defaultFoo = DefaultFoo;
    }

    public void AddFoo(Foo newFoo)
    {
        allFoos.Add(newFoo);
    }

    public void AddFoo(Foo oldFoo)
    {
        allFoos.Remove(oldFoo);
    }

    public bool IsFooVar1Consistent
    {
        get
        {
            Foo[] tempFoos = allFoos.ToArray();
            foreach (Foo tempFoo in tempFoos)
            {
                if (tempFoo.FooVar1 != defaultFoo.FooVar1) return false;
            }
            return true;
        }
    }
}

Or am I approaching this problem entirely incorrectly. As I'm writing this question (After about 2000 lines of code) I'm thinking of how I read that WPF itself implements Dictionary look ups that crawl up to the parent to see if a Property is present and what the value should be.

+3  A: 

Well, for a start you are defining both backing fields which will never be used and automatic properties. This is enough for a simple bool property:

public bool FooVar1 { get; set; }

No need for the private field. This greatly reduces the number of lines in your example.

David M
+1 for teaching me something.
George
+2  A: 

I'm not quite sure what the question is, but if you're looking for some way to unify the IsFoorVarXConsistent code, you could do it using reflection or by passing in an expression:

public bool IsConsistent(Func<Foo, bool> property)
{
  foreach (Foo tempFoo in allFoos)
  {
    if (property(tempFoo) != property(defaultFoo))
      return false;
  }
  return true;
}

Called like this:

bool is1Consistent = IsConsistent(f => f.FooVar1);

As shown this will only work for boolean properties. To extend it to other types, we can make it generic in the property type. However, in this case we cannot use != to test for inequality because not all types define a != operator. Instead we can use the .Equals method and the ! operator:

public bool IsConsistent<T>(Func<Foo, T> property)
  where T : struct
{
  foreach (Foo tempFoo in allFoos)
  {
    if (!property(tempFoo).Equals(property(defaultFoo)))
      return false;
  }
  return true;
}

The where T : struct clause restricts this to value types like int, bool and decimal. In particular it will not work on strings. Removing the where constraint allows it to work on strings and other reference types, but creates the possibility of property(tempFoo) being null, which would cause a NullReferenceException when we called .Equals on it. So if you remove the value types constraint then you will need to add error handling for this scenario.

itowlson
This could work, I have defined a == on every object that is not value type.
Joel Barsotti
+2  A: 

I'd love to find a way that is more elegant since I'm having to cut and past roughly the same code 20+ times and just change property names.

Code generators exist for exactly this purpose. But if you don't want to go that route, you can shorten your code to this:

return allFoos.All(foo => foo.FooVar1 == defaultFoo.FooVar1);
Juliet
I think this exactly what I'm looking for short of redoing the whole code for a different pattern.
Joel Barsotti