4

I'm converting a Silverlight app to WPF. The following piece of code didn't compile but it does in Silverlight:

XAML:

<Grid x:Name="Table">
</Grid>

Code behind:

foreach (var uiElement in Table.Children
            .Where(x => Grid.GetColumn((Border)x) == Table.ColumnDefinitions.Count() - 1))
{
   //do something
}

At Where it says

'UIElementCollection' does not contain a definition for 'Where' and no extension method 'Where' accepting a first argument of type 'UIElementCollection' could be found (are you missing a using directive or an assembly reference?)

System.Linq namespace is added.

If I cast UIElementCollection to an IList<object> then it works, but I receive a warning:

it's a suspicious cast

What am I doing wrong?

Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
Ozkan
  • 3,880
  • 9
  • 47
  • 78
  • 3
    @dasblinkenlight marked as duplicate?! My question is better explained. Do you expect me to first find that question? No way! The questions have a complete different context... And also, people who search on Google will find this question easily than the other one. – Ozkan Oct 09 '17 at 13:36
  • 2
    To me, if both questions ran into the same problem, and both questions have exactly the same solution, then one is a duplicate of the other. A quick search for `UIElementCollection` with `[linq]` tag turns up the other question within the top five hits, so it wasn't too hard to. Some duplicates are better worded than their earlier counterparts. That's why SO keeps many duplicates around - it makes solutions easier to find if you come from an outside search engine. That's why I upvoted the question and an answer that I think works best. – Sergey Kalinichenko Oct 09 '17 at 13:50

3 Answers3

8

In Silverlight, the UIElementCollection implements IEnumerable<T>, but the UIElementCollection in WPF implements IEnumerable, not IEnumerable<T>. If you want to use LINQ here, you can use OfType<UIElement>() as an option:

foreach (var uiElement in Table.Children.OfType<UIElement>()
           .Where(x => Grid.GetColumn((Border)x) == Table.ColumnDefinitions.Count() - 1))
{
    //do something
}
Salah Akbari
  • 39,330
  • 10
  • 79
  • 109
5

The problem is that UIElementCollection does not implement the generic IEnumerable<T> :

public class UIElementCollection : IList, ICollection, IEnumerable

While the Enumerable.Where extension method requires the generic version:

public static IEnumerable<TSource> Where<TSource>(
    this IEnumerable<TSource> source,
    Func<TSource, int, bool> predicate
)

So, the solution is to cast the elements first:

foreach (var uiElement in Table.Children.OfType<UIElement>().Where(x => Grid.GetColumn((Border)x) == Table.ColumnDefinitions.Count() - 1))
{
}
Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
3

Your code doesn't compile because UIElementCollection implements the non-generic collection interfaces, and Linq requires the generic collection interfaces.

You can use the Cast<T>() method to get an instance of IEnumerable<T> and then use Linq:

var children = Table.Children.Cast<UIElement>();
foreach (var uiElement in children .Where(x => Grid.GetColumn((Border)x) == Table.ColumnDefinitions.Count() - 1))
{
   //do something
}
Andy
  • 30,088
  • 6
  • 78
  • 89