views:

233

answers:

4

I have run into a problem w/ my model for databinding in WPF. I have an object which has a collection of objects (Variable), and each in turn has yet another collection of objects (VariableCode).

What I need to be able to do is somehow expose a single collection from the highest level object - which is a fusing of the lowest level collections (VariableCode) where each member object meets a condition. So that I can bind that collection to a ListBox, which should display VariableCodes that belong to 1 or more variables.

So the code looks something like this:

public class CrossTab
{
  public VariableList Variables{get; set;}
}
public class Variable
{
  public VariableCodeList VariableCodes{get; set;}
}
public class VariableCode
{
  public bool IsShown{get; set;}
}

What I'd really like to do is expose a property on CrossTab (preferably an ObservableCollection<VariableCode>) which is a view on all the contained VariableCodes where IsShown == true. Currently, they're separate collections - each contained in their own Variable object.

public class CrossTab
{
  public ObservableCollection<VariableCode> ShownCodes
  {
    get
    {
      //This is where I could picture some brute force looping
      //  and building of a new collection - but that's not really
      //  what I'm after.  What I want is a live view on the data
      //  that's in there
    }
  }
}

The brute force code that I was toying with which returns the correct data - just not as a live view, but rather as a static collection.

ObservableCollection<VariableCode> output = new ...();
Variables.ForEach(v =>
    v.VariableCodes.Where(vc => vc.IsShown)
    .ForEach(vc => output.Add(vc))
  );
return output;

Thoughts? Is such a thing possible?

+1  A: 

Have you considered using a LINQ query to get the result you need from your data structure rather than adding more properties to it?

jerryjvl
+3  A: 

I think SelectMany (LINQ) is what you are looking for.
See if this helps.

Trying to use the above link for your example & writing it in SO (without compiler).
I will be amazed, if this works ;)

var allTeams = 
from v in Variables.SelectMany( v => v.VariableCodes ).SelectMany(vc)
where vc.IsShown == true;
select vc;
shahkalpesh
Also correct. Thanks.
Paul Prewett
A: 

I think overriding the index operator would be a good idea. The following code is an example of how you can do this. This code is fully tested and even detects "IndexOutOfRange" exceptions.

class Collection
   {
   //                                   [0]    [1]
   static String[] a1 = new String[] { "one", "two" };
   //                                   [2]      [3]
   static String[] a2 = new String[] { "three", "four" };
   //                                   [4]     [5]
   static String[] a3 = new String[] { "five", "six" };

   static Object[] collections = new Object[] { a1, a2, a3 };

   public String this[int i]
      {
      get
         {
         int add_to_index = 0;
         int collection_num = 0;

         int calculated_index = i - add_to_index;

         for ( String[] pointer = (String[])collections[collection_num];
            1 == 1;
            pointer = (String[])collections[++collection_num],
            calculated_index = i - add_to_index)
            {
            if (calculated_index < pointer.Length)
               return pointer[calculated_index];
            else if (collection_num == (collections.Length - 1))
               throw new IndexOutOfRangeException();
            add_to_index += pointer.Length;
            }

         throw new IndexOutOfRangeException();
         }
      set { throw new NotImplementedException(); }
      }

   }
Nippysaurus
+1  A: 

You can use the SelectMany Linq method to achieve this, as follows:

public class CrossTab
{
    public VariableList Variables { get; set; }

    public ObservableCollection<VariableCode> ShownCodes
    {
        get
        {
            return new ObservableCollection<VariableCode>(
                Variables
                    .SelectMany(variable => variable.VariableCodes)
                    .Where(code => code.IsShown)
                );
        }
    }
}
Nathan Baulch
Nicely put into context.
Paul Prewett