tags:

views:

78

answers:

5

I have the following structure.

public class ToolSettings
{
  public string Extension { get; set; }
  public ObservableCollection<Tool> Tools { get; set; }
}

public class Tool
{
  public string Name { get; set; }
  public string Command { get set; }
}

// Within app code
public ObservableCollection<ToolSettings> settings { get; set; }

I'd like to grab the Tools collection from the settings collection where the Extension equals a certain string.

Below is my LINQ code, but I'm only getting one item in my collection when I know there's more. It looks like it produces a collection of a collection, which is why there's only one item.

myListBox.ItemsSource = from i in settings 
                        where i.Extension == myExtension 
                        select i.Tools;

EDIT:

Thanks for all the good (and quick) answers. It turns out I only need the first item, but I know that the SelectMany method will come in handy in the future. So, thanks for all the heads up. Here is the full solution I used.

myListBox.ItemsSource = (from i in settings 
                         where i.Extension == myExtension 
                         select i.Tools).First();
+5  A: 
myListBox.ItemsSource = settings.Where(s => s.Extension == myExtension)
                                .SelectMany(s => s.Tools);

Or, if you prefer query syntax to the fluent syntax:

myListBox.ItemsSource = from s in settings
                        where (s.Extension == myExtension)
                        from t in s.Tools
                        select t;
LukeH
you need to flip the order of the method calls.
Shlomo
SelectMany should be renamed to something more intuitive, it's one of the most useful pieces of linq that so many people have difficulty finding, there's someone asking how to do this like 5 times a day.. Maybe like SelectFlatten or SelectRecursive would get people to pull it out of intellisense quicker for this purpose..
Jimmy Hoffa
A: 

You can use .SelectMany(), but that's only really useful if you want to take multiple ToolSettings and select all of their Tools as a single collection. If Extension is unique, use .Single() to reduce the collection of a single collection to just the single collection.

Ian Henry
A: 

The question is a little vague. You are right, you are getting a collection of a collection, in that there might only be one ToolSettings instance where Extension satisfies your criteria and because of that, since you are selecting Tools, you are getting a sequence of ObservableCollection<Tool> instances.

What it sounds like you really want is to get the sequence of all Tool instances where the condition is met. In that case, you want to use the SelectMany extension method on the Enumerable class:

myListBox.ItemsSource = settings.Where(i => i.Extension == myExtension).
    SelectMany(i => i.Tools);

Or, if you prefer query syntax, you can do the following:

myListBox.ItemsSource = 
    from i in settings
    where i.Extension == myExtension
    from t in i.Tools
    select t;

Which will translate to a call to SelectMany when the compiler gets done with it.

casperOne
+1  A: 

That will give you an IEnumerable<ObservableCollection<Tool>>. It willprobably only have one item in it, but that item will be a ObservableCollection. If you want that collection itself, tack .First() (or .FirstOrDefault()) at the end.

If i.Extension == myExtension could find several ToolsSettings in the collection (I'm guessing not), then you will need to use .SelectMany()

James Curran
+1  A: 

Try this:

myListBox.ItemsSource = (from i in settings 
                         where i.Extension == myExtension
                         from t in i.Tools
                         select t);
Johan Leino