0

I am trying to write a method that gets all of the ObservableCollections in a viewModel and casts each as an ObservableCollection<object>. Using reflection I've been able to get each ObservableCollection<T> as an object, but I'm having difficulties casting this object to an ObservableCollection<object>. Here is my code thus far:

var props = viewModel.GetType().GetProperties();

Type t = viewModel.GetType();

foreach (var prop in props)
{
    if (prop.PropertyType.Name == "ObservableCollection`1")
    {
        Type type = prop.PropertyType;
        var property = (t.GetProperty(prop.Name)).GetValue(viewModel);

        // cast property as an ObservableCollection<object>
    }
}

Does anyone know how I should proceed?

Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57
fyodorfranz
  • 476
  • 8
  • 25
  • Casting to `ObservableCollection` would not be type safe. Why do you want to do that? Maybe there is another way to achieve your goal. – Mike Zboray Jun 09 '16 at 19:24
  • The main disadvantage of every answer in this thread is that the new collection will not change or send any notifications if the old one changes. And there is no way to overcome this without writing lots of workaround code. Sometimes this limitation or CLR type system is really annoying. – N. Kudryavtsev Sep 20 '19 at 12:52

3 Answers3

2

It is a bad idea to compare type name against a string. In order to assert it is an ObservableCollection, you can use the following :

if (prop.PropertyType.IsGenericType && 
    prop.PropertyType.GetGenericTypeDefinition() == typeof(ObservableCollection<>))

The value can be extracted and transformed as such :

foreach (var prop in viewModel.GetType().GetProperties())
{    
    if (prop.PropertyType.IsGenericType && 
        prop.PropertyType.GetGenericTypeDefinition() == typeof(ObservableCollection<>))
    {
        var values = (IEnumerable)prop.GetValue(viewModel);

        // cast property as an ObservableCollection<object>
        var collection = new ObservableCollection<object>(values.OfType<object>());
    }
}

If you like to have them combined into one collection, you can do this :

var values = viewModel.GetType().GetProperties()
    .Where(p => p.PropertyType.IsGenericType)
    .Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(ObservableCollection<>))
    .Select(p => (IEnumerable)p.GetValue(viewModel))
    .SelectMany(e => e.OfType<object>());
var collection = new ObservableCollection<object>(values);
Xiaoy312
  • 14,292
  • 1
  • 32
  • 44
1

Answer for this question is here : https://stackoverflow.com/a/1198760/3179310

But to make it clear for your case:

if (prop.PropertyType.Name == "ObservableCollection`1")
{
    Type type = prop.PropertyType;
    var property = (t.GetProperty(prop.Name)).GetValue(viewModel);

    // cast property as an ObservableCollection<object>
    var col = new ObservalbeCollection<object>(property);
    // if the example above fails you need to cast the property
    // from 'object' to an ObservableCollection<T> and then execute the code above
    // to make it clear:
    var mecol = new ObservableCollection<object>();
    ICollection obscol = (ICollection)property;
    for(int i = 0; i < obscol.Count; i++)
    {
        mecol.Add((object)obscol[i]);
    }    
    // the example above can throw some exceptions but it should work in most cases
}
Community
  • 1
  • 1
mrogal.ski
  • 5,828
  • 1
  • 21
  • 30
  • Thanks for the suggestions. The first approach generates an error `cannot convert from 'object' to 'System.Collections.Generic.List'`, but the second one worked just fine. – fyodorfranz Jun 09 '16 at 19:30
0

You could use the Cast<T>() extension method, but don't forget, using this method (below) this will create a new instance, so events of the original do not work. If you still want to receive events, you should create a wrapper arround it.

var prop = viewModel.GetType("ObservableCollection`1");

var type = prop.PropertyType;
var propertyValue = (t.GetProperty(prop.Name)).GetValue(viewModel);

// cast property as an ObservableCollection<object>
var myCollection = new ObservableCollection<object>(
                   ((ICollection)propertyValue).Cast<object>());

}
Jeroen van Langen
  • 21,446
  • 3
  • 42
  • 57