1

I want to set the listview datacontext equal to an observable collection so that changes to the collection may reflect on my listview. I create the observable collection as:

public static ObservableCollection<T> ToObservableCollection<T>(IEnumerable<T> enumeration)
{
     return new ObservableCollection<T>(enumeration);
}

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{

           Entities.DatabaseModel m = new Entities.DatabaseModel();
           var q = from t in m.TimeSheet                            
                    join emp in m.Employees on t.idEmployee equals emp.id
                    where emp.id == CurrentEmploye.id
                    select new
                    {
                        firstName = emp.firstName,
                        lastName = emp.lastName,
                        position = emp.position,
                        clockInDate = t.clockInDate,
                        clockOutDate = t.clockOutDate,
                    };
           // here I create the observablecollection!!!!!!!!!!!!!!
           listView1.DataContext = ToObservableCollection(q); 
}

now my problem is that if I want to add items to the ObservableCollection how can I do that? If I do listView1.DataContext.Add( that will result on an error.

In other words I have the method

    private void btnClockIn_Click(object sender, RoutedEventArgs e)
    {
         // I will like to add items to the observable collection in here

This is what I have tried and it does not work:

    dynamic collection; 


private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
       // CurrentEmploye some employee
       Entities.DatabaseModel m = new Entities.DatabaseModel();
       var q = from t in m.TimeSheet                            
                join emp in m.Employees on t.idEmployee equals emp.id
                where emp.id == CurrentEmploye.id
                select new
                {
                    firstName = emp.firstName,
                    lastName = emp.lastName,
                    position = emp.position,
                    clockInDate = t.clockInDate,
                    clockOutDate = t.clockOutDate,
                };

       collection = ToObservableCollection(q); 
 }


    private void btnClockIn_Click(object sender, RoutedEventArgs e)
    {

         collection.Add(new
                {
                    firstName = "Antonio",
                    lastName = "Nam",
                    position = "Amin",
                    clockInDate = DateTime.Now,
                    clockOutDate = DateTime.Now
                });
Tono Nam
  • 34,064
  • 78
  • 298
  • 470
  • 1
    do you absolutely need this to be an anonymous type? Will the query ever return different fields than the ones you specified? – Michael Edenfield Apr 02 '12 at 23:49
  • You are right I was just trying to save time because I need this functionality in some other places but I probably ended up wasting more time.. – Tono Nam Apr 03 '12 at 01:23
  • You have some options, using a named type is just the quickest. I'll post an answer with more details. – Michael Edenfield Apr 03 '12 at 01:30
  • possible duplicate of [Accessing C# Anonymous Type Objects](http://stackoverflow.com/questions/713521/accessing-c-sharp-anonymous-type-objects) – nawfal Jun 28 '14 at 08:48

2 Answers2

3

You can 'trick' it by using a similar 'template' anonymous variable...
e.g. code method would be something like...

static ObservableCollection<T> CastToEnumerable<T>(this T template, object value)
{
    return (ObservableCollection<T>)value;
}

...and use it something like this...

var list = new
{
    firstName = "",
    lastName = "",
    position = "",
    clockInDate = DateTime.MinValue,
    clockOutDate = DateTime.MinValue
}.CastToEnumerable(context);
foreach (var value in list)
{ 
}

...it's still recommendable to have a normal named class for your purpose.
You can find more info about similar problem here...
Cast to Anonymous Type
(Basically you cannot return anonymous type - short of tricks like this - 'inferring' of the type is what's behind this).

Community
  • 1
  • 1
NSGaga-mostly-inactive
  • 14,052
  • 3
  • 41
  • 51
1

Using anonymous types in places where you cannot use type inference is not possible, so you cannot, for example, declare a class field or property of an anonymous type. However, there are non-obvious was to use type inference that lets you share anonymous objects across methods.

As I mentioned in my comment, your easiest option is to just use a named type; this will allow you to define the ObservableCollection<> as a class-level variable, or typecast your DataContext elsewhere in your class.

Depending on how frequently you need to use this code, there is a second option that involves typecasting object to your anonymous type. This requires you to know, in each place where you want to use your anonymous type, what fields it has in what order. It also requires that every use of the anonymous type exist in the same assembly -- this guarantees that the compiler unifies the anonymous types into a single underlying type.

If that matches your requirement, you can use a "trick" like this:

ObservableCollection<T> Cast<T>(object obj, T typedobj)
{
  return (ObservableCollection<T>)obj;
}

private void btnClockIn_Click(object sender, RoutedEventArgs e)
{
  var temp = new 
  { 
    firstName = string.Empty, 
    lastName = string.Empty, 
    position = string.Empty, 
    clockInDate = DateTime.Min, 
    clockOutDate = DateTime.Now 
  };

  var collection = Cast(lstView1.DataContext, temp);
  collection.Add(...);
}

Let me repeat, this is a somewhat messy "trick" that takes advantage of an obscure detail of how C# implements anonymous types. It's not a "hack" per-se, since the behavior is guaranteed by the spec, but there severe limitation to how far this works. If you only have one or two such collections, I would definitely lean towards giving your types names.

Michael Edenfield
  • 28,070
  • 4
  • 86
  • 117
  • the method: `ObservableCollection Cast(object obj, T typedobj)` gives me a compilation error saying: `Cannot convert type 'T' to 'System.Collections.ObjectModel.ObservableCollection` – Tono Nam Apr 03 '12 at 17:06
  • yeah, typo in my answer, sorry. typecast the wrong parameter. fixed now. – Michael Edenfield Apr 03 '12 at 17:55
  • though I like the extension method version a tiny bit better :) – Michael Edenfield Apr 03 '12 at 17:57
  • just a matter of style:) (I wouldn't have posted my answer just for that, but we posted almost at the same time) - this is still a 'hack' no matter how we put it, more of a fun coding – NSGaga-mostly-inactive Apr 03 '12 at 18:18
  • I dunno; the fact that the C# spec explicitly makes a guarantee that this will work makes me more likely to use it than, say, relying on the implementation of GetHashCode() – Michael Edenfield Apr 03 '12 at 21:43