Wednesday, April 4, 2012

DataGrid Frustration

I'm Back
First a brief explanation regarding my lack of posting over the past couple of years.  In the Spring of 2010 I was laid off from the company I had worked at for almost 10 years.  I managed to get a job fairly quickly, but it didn't involve any C#.NET.  Now a prototype application I have been designing using Excel and VBA has outgrown that platform and I'm porting it to C#.NET.  I hauled my library of C#, WPF and Entity Framework books out of storage and dusted the cobwebs off my understanding.  I have to say this blog proved invaluable to me in retracing my educational steps (sort if like a dear-diary  for my brain) and getting me back in gear.  So I'm going to continue to chronicle my frustrations, discoveries and missteps out of a renewed sense of selfishness and Amnesiphobia.

A Default-Sorted DataGrid
Using T4 code templates I have implemented a method for all of my EF Entities that delivers a CollectionView with a default SortDescription that I define as a Static property in each entity's partial class file (outside of the T4 template).  This works great for ListBox controls, but when it came to the DataGrid it started giving me issues with regards to sorting.

The DataGrid worked fine on the initial ItemSource binding but as soon as you changed it (by navigating to another parent object) the default sorting disappeared.  Turns out the DataGrid implements the following method:


This method (for whatever reason) strips off your CollectionView's SortDescriptions.  Arrgh!  This post shows a workaround involving defining your own DataGrid class that inherits from the DataGrid and simply overrides this Dependency Property callback.  Now my default sorts work perfectly.  Here's the workaround:





Tuesday, April 6, 2010

Entity Framework and Database Generated Keys

Still learning the ins and outs of the Entity Framework and ran into a snag.  I added a record to a table and saved without problem.  The second record threw an error and when I drilled into the inner exception I found a problem with the table's primary key constraint.  Looking at the table I noticed that the first added record had a GUID of  0.  Whoops!

What's going on?  After a little investigating I discovered that none of the Primary key fields were set up properly by Visual Studio when it created them from the database.  Since I am letting the database generate the GUID's these fields need to have the StoreGeneratedPattern property set to "Identity," but VS had set them all to "None."  Once I made this change, all was good.  Now excuse me while I make this change to every entity in my model...

Wednesday, March 31, 2010

AutoRefreshCollectionViewSource Tweaks

A few posts back, I listed the AutoRefreshCollectionViewSource class that extends the CollectionViewSource class by causing its sort to automatically refresh when needed (i.e., a sorted on property is changed).  After implementing it I discovered the need for a tweak to allow the controls to call ScrollIntoView in response to a Refresh (otherwise the SelectedItem might get pushed up or down the ListBox and out of view!).  At first I tried to call ScrollIntoView from various other control events, but I found that these events fired before Binding caused the underlying objects to be updated and the CollectionViewSource was refreshed.  The solution that I came up with was to add a custom event to the AutoRefreshCollectionViewSource object:

public delegate void RefreshEventHandler();
public event RefreshEventHandler RefreshEvent;
...
private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
...
    if (refresh)
    {
      View.Refresh();
      RefreshEvent();
    }
...

I then added an overload to the WPFCollection<T>.GetCollectionView() method that would handle setting up an event listener:


public ListCollectionView GetCollectionView(AutoRefreshCollectionViewSource arcvs, AutoRefreshCollectionViewSource.RefreshEventHandler handler)
{
  arcvs.RefreshEvent += new AutoRefreshCollectionViewSource.RefreshEventHandler(handler);
  return GetCollectionView(arcvs);
}


The handler simply calls the ListBox.ScrollIntoView on the currently SelectedItem.  Seems to solve the problem.

Friday, March 12, 2010

Entity Framework Code Generation Template

Well, I should probably have waited until I understand it better, but I was so excited when I found out how easy it was that I had to post it right away.  What am I babbling about?  It is Visual Studio 2010's support for "T4" code generation templates.  At first I was pretty intimidated by this topic (especially since they named it after one of the Terminator models...shudder), but it turns out there is nothing to fear but fear itself.  So here goes...

Adding a T4 Template to Your EF Project
A couple of posts ago I discussed what, in my opinion, is a big hole in EF binding and change notification.  Specifically, no PropertyChanged/ing events get fired when changing an association with another entity in the model.  For example, if a Trip entity has a reference to a Destination entity in a property called "Destination" and you change which Destination instance that property is pointing to no PropertyChanged/ing events are fired. None whatsoever.  In my post I mentioned that this could probably be solved with a code generation template.  I can now cross out the word "probably." The first step is to add such a template to your EF project (i.e., a project that already has a *.edmx file). Right-click on your project and from the context menu select Add/New Item...


Choose the "ADO.NET EntityObject Generator" from the Code node.  Rename this to whatever you want (I chose the same name as my *.edmx file).  This will add a *.tt file to your project.  The bad news is that VS 2010 does not appear to offer any code coloring or intellisense for these files so they can look a little intimidating at first.  If you want to make big changes then you need to find another blog.  We're starting slow here.

Oh, Great a New Syntax to Learn.  Yippee.
So what you will see as you are browsing the *.tt file is a lot of C# code sprinkled liberally with some additional syntax and a few comments.  As your eyes adjust you might be pleasantly surprised to find that, in fact, 90% of what you see looks like C# code.  Then you notice that some of the C# code seems to be bracketed by "<#" and "#>".  This appears to be what separates the code-generation C# from the actual generated-code C#.  Basically, anything on the inside of a <# ... #> is the logic that governs the code generation process and code not enclosed in these delimiters is the actual code that will be in the resulting *.cs file.

Enough gawking. Search for the place in the file that has string "Reference" (including the quotes).  The section immediately above this word should be as follows with the exception of the highlighted parts, which need to be added by you.

    <#=code.SpaceAfter(NewModifier(navProperty))#><#=Accessibility.ForPro...;
    {
        <#=code.SpaceAfter(Accessibility.ForGetter(navProperty))#>get
        {
            return ((IEntityWithRelationships)this).RelationshipManager.GetRelatedRefe...;
        }
        <#=code.SpaceAfter(Accessibility.ForSetter(navProperty))#>set
        {
            OnPropertyChanging("<#=navProperty.Name#>"); 
             ((IEntityWithRelationships)this).RelationshipManager.GetRelatedRefer...;
            OnPropertyChanged("<#=navProperty.Name#>");
        }
    }


After adding these two lines, save the file.  You will notice two things that you have a generated *.cs file underneath your *.tt file.  If you try to view your old *.designer.cs file that was under the *.edmx file you will get a warning message and the file will be empty.  That is because your new *.cs file has taken it's place.  If you open it and look at the navigation properties, you will notice that the setters now fire the PropertyChanged/ing events.  No more need for the old work-around.  If you have any of the old code from the previous post, delete or comment it out and run your project.  Binding updates due to EntityReference changes should happen now without the work-around code.  Cool.

Visual Studio Just Got More Complex!

Still working my way through Julia Lerman's book Programming Entity Framework.  In chapter 12 she discusses several customizations that can be done to a EF Model, some of which will "break" the Visual Studio 2008 Designer, meaning you have to resort to looking at the XML of the *.edmx file instead of the nice visual layout.  One of these customizations is adding Complex types to an Entity.  I have been going through these examples using the Visual Studio 2010 Release Candidate and I'm happy to report that Microsoft has added full support for Complex types to the Designer!


Adding a Complex Type to Your Model
Adding a Complex type to your model is quite easy.  In the Designer, select the Model Browser (if you don't see this tab anywhere it can be access from the menus View/Other Windows/Entity Data Model Browser). In the Model Browser, expand the model node and you will see a Complex Types node.  Right-clicking on this node will add a new Complex type to your model
Rename the type to whatever you want and then right-click on the new type to start adding properties.  Each property has several settings that you can access through Visual Studio's Properties pane.  I would recommend changing the Nullable property to "True" as it will default to "False." Once you have finished building your type, you can add it to any of the entities in your model by right-clicking (sensing a pattern yet?) on the Entity and selecting Add/Complex Type from the context menu.


Mapping Complex Types to Your Model
Mapping these types is just as easy in VS 2010.  Just select the entity with the type and in the Mapping Details pane use the Value/Property drop-downs to establish the appropriate mappings from your table(s).

Binding Tips for Complex Types
Julia's book states correctly on page 339 that "Complex types are not Entity Objects." This is still correct in .NET 4.0, Complex types are based on ComplexObjects.  ComplexObject shares a common abstract sub-class with EntityObject called StructuralObject which implements the INotifyPropertyChanged interface.  This allows it to be change tracked by the EF and persisted to the database.  One problem, however is that introducing a ComplexObject into your model allows for a slight binding disconnect which you have to address manually if you want everything to work as you would expect.  Take for example the following setup:

In this instance if we assign the Detail property of an Address instance to an instance of the AddressDetail Complex type our Address entity will fire the PropertyChanged event to alert any bindings that they will need to update.  That's great, but if you edit a property of the Detail instance the PropertyChanged event will not fire for the Detail property (it does fire inside the ComplexObject, it just doesn't bubble up to the object that has the Complex type as a property (in this case the Address entity).  This may not be a problem for your particular binding implementation, but it was for mine.  In my setup, I defined a CollectionViewSource that sorted the Address entities on the Detail property:

<tns:AutoRefreshCollectionViewSource x:Key="AddressSource"  >
  <tns:AutoRefreshCollectionViewSource.SortDescriptions>
    <scm:SortDescription PropertyName="Detail" Direction="Ascending"/>
  </tns:AutoRefreshCollectionViewSource.SortDescriptions>
</tns:AutoRefreshCollectionViewSource>

Here I used the AutoRefreshCollectionViewSource class from my previous post. In order to sort on the AddressDetail type I needed to implement the IComparable interface.  In addition, I have added a "FullAddress" string property and overriden ToString() to return this value.


public partial class AddressDetail: ComplexObject, IComparable
{
  public String FullAddress
  {
    get
    {
      return (Street1 ?? "Null").Trim() +
              ", " + (City ?? "Null").Trim() +
              ", " + (StateProvince ?? "Null").Trim() +
              " " + (PostalCode ?? "Null").Trim();
    }
  }
 
  public override string ToString()
  {
    return this.FullAddress;
  }

  #region IComparable Members

  public int CompareTo(object obj)
  {
    AddressDetail otherCust = obj as AddressDetail;
    if (otherCust != null)
      return this.FullAddress.CompareTo(otherCust.FullAddress);
    else
      throw new ArgumentException("Object is not a AddressDetail");
  }

  #endregion
}

Since I overrode the ToString() method I can assign DisplayMemberPath for my ListBox directly to the Detail property of Address.  When I used this implementation it worked great until I edited on the AddressDetail classes properties and figured out that the bound ListBox would not update to reflect the new value of FullAddress.  This is because, as far as the Address entity is concerned, Detail has not changed (it is still the same object instance!).  One possible work-around for this is to add the following code to the Address partial class:


public partial class Address: EntityObject
{

  partial void OnDetailChanging(AddressDetail newDetail)
  {
    if (newDetail != null)
    {
      newDetail.PropertyChanged += new PropertyChangedEventHandler(AddressDetailChanged);
    }
  }
  
  public override string ToString()
  {
    return this.Detail.ToString();
  }

  public void AddressDetailChanged(object sender, PropertyChangedEventArgs e)
  {
    OnPropertyChanged("Detail");
  }

}

This code attaches a listener to the PropertyChanged event of the Addresses Detail object.  This listener will then fire the PropertyChanged event for the Address entity.  In this way the bound ListBox will update in response to changes in the properties of the Detail complex object.  There might be a better place to set up the listener method, but this seems to work for now.

Tuesday, March 9, 2010

Sorting Out EntityReference Binding

Okay, in my last post on the Entity Framework (EF), I posted code for a custom class that inherits from ObservableCollection<T> called "WPFCollection" and I promised to post some work-around code for the fact that the setter method of an EntityObject's EntityReference properties doesn't fire the EntityObject's INotifyPropertyChanged events (i.e., PropertyChanged/PropertyChanging).  This seems like a big hole to me and I was hoping that it would be plugged in .NET 4.0.  Unfortunately, that doesn't seem to be the case so this post will walk through the work-arounds that I have managed to cull from the web along with some of my own modifications.


EntityReferences and INotifyPropertyChanged
EntityReferences are added to EntityObjects by the Object Relational Designer (ORD) to represent the "1" end of an Association.  These Reference properties are not visible in the *.edmx file as they are basically represented by the Association lines (see the picture to the right).  They do show up in code, and in any class diagram (*.cd) that you might create (see the second picture to the right.

For example, the Trips database table might have a DestinationID field that is a foreign key belonging to a record in a Destinations table.  When the ORD creates the Trip EntityObject, it will automatically add a new property called "DestinationReference." DestinationReference inherits from the EntityReference class and is in addition to the Destination property that is a pointer to an actual Destination EntityObject.  The DestinationReference provides functionality that is useful for navigating the object graph (map) and such.  As mentioned above, the ORD does not place code in the setter methods of EntityReferences to fire the INotifyPropertyChanged events.  This is a big bummer for binding since a binding will have no way of knowing that it needs to update itself.

There are two work-arounds for this situation:
  1. Add some code to the EntityObject that will raise the event, 
  2. Create a custom code generator for ORD that will put the proper INotifyPropertyChanged method calls in the EntityReference setter methods.  
Of these two, the only one I currently know how to accomplish is the first.   It is not an ideal solution because it requires some canned code to be added to EVERY EntityObject class in your model with EntityReferences that you intend to bind.  You need to add a constructor method and then a method that will raise the INotifyPropertyChanged events (note: this code is NOT in the *.designer.cs file, but in a separate partial class file, e.g. "Trip.cs"):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Objects.DataClasses;
using System.ComponentModel;

namespace MyEntityNamespace
{
  partial class Trip : EntityObject
  {
    public Trip()
    {
      foreach (IRelatedEnd relatedEnd in ((IEntityWithRelationships)this).RelationshipManager.GetAllRelatedEnds())
      {
        RelatedEnd association = (RelatedEnd)relatedEnd;
        association.AssociationChanged += new CollectionChangeEventHandler(myAssociationChanged);
      }
    }

    ///<summary>
    /// Fires the PropertyChanged Event for any reassigned EntityReference objects
    ///</summary>
    ///<remarks>
    ///EntityReference objects do not have built in PropertyChanging
    ///and PropertyChanged events in the property

    ///setter.  This method can be assigned to
    ///the AssociationChanged event (usually in the
    ///Constructor) and it will fire the PropertyChanging/ed event.
    ///</remarks>
    private void myAssociationChanged(object sender, CollectionChangeEventArgs e)
    {

      //EntityReferences are changed by first removing the old one and then adding the new one
      if (e.Element != null)
      {
        if (e.Action == CollectionChangeAction.Remove)
          OnPropertyChanging(e.Element.GetType().Name);
        else
          OnPropertyChanged(e.Element.GetType().Name);
      }
    }
  }
}

This code takes advantage of the AssociateChanged event that is fired by an EntityReference when it is added or deleted.  When you reassign and EntityReference, the existing association is first removed and then the new one is added.  The AssociationChanged event is not monitored by bound controls, so this code tacks a listener onto the event that fires the appropriate INotifyPropertyChanged event.  The basis for this code came from an MSDN forum post.

Keeping Things Sorted
I tested out the above code in an example from Julia Lerman's Programming Entity Framework.  In this example, Julia has you build a master-detail form using a ListBox of Trip EntityObjects as the "master."  Trips are differentiated by Destination.DestinationName and StartDate.  Placing my Trips in a WPFCollection<Trip> ObservableCollection and using the code above allows the ListBox to be notified when a Trip's Destination changes so it can update the displayed list.

Side note here for anyone following this example in Julia's book: on page 201 Julia has you define two ComboBox elements, but Julia binds these incorrectly.  Take the Destination one for example.  She binds the ComboBox's SelectedValue property to Destination.DestinationID, however this will not produce proper change notification when changing a Trip Object's Destination (DestinationID for Destination doesn't change!).  If we instead bind SelectedItem to the Destination property (along with the code modifications of the above section), we get proper change notification.  Below is the proper XAML for the Destination ComboBox (also notice the use of a DataContext in the Grid element to simplify the Binding statement):


<Grid DataContext="{Binding ElementName=lbxTrips, Path=SelectedItem}">
...
  <ComboBox Name="cbxDestination"  Grid.Row="1" Grid.Column="3"
            DisplayMemberPath="DestinationName"
            SelectedValuePath="DestinationID"
            SelectedItem="{Binding Destination, Mode=TwoWay}"
            SelectionChanged="cbxDestination_SelectionChanged" />

Okay, back to sorting. The regular CollectionViewSource control does the sorting for you, but it doesn't automatically re-sort when the properties you are sorting on are changed.  I picked up the following code for an AutoRefreshCollectionViewSource class from another forum post, and modified it slightly so that it will play nice with WPFCollection<T>.  Just put the following code in a new Class file called "AutoRefreshCollectionViewSource.cs" (see the new tweaks to this class in this post):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Data;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Collections;

namespace WPFApp
{
  public class AutoRefreshCollectionViewSource : CollectionViewSource
  {

    protected override void OnSourceChanged(object oldSource, object newSource)
    {
      if (oldSource != null)
      {
        SubscribeSourceEvents(oldSource, true);
      }

      if (newSource != null)
      {
        SubscribeSourceEvents(newSource, false);
      }
      base.OnSourceChanged(oldSource, newSource);
    }


    private void Item_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      //Refresh not allowed while in a Transaction
      if (!((ListCollectionView)this.View).IsAddingNew)
      {
        bool refresh = false;
        foreach (SortDescription sort in SortDescriptions)
        {
          if (sort.PropertyName == e.PropertyName)
          {
            refresh = true;
            break;
          }
        }

        if (!refresh)
        {
          foreach (GroupDescription group in GroupDescriptions)
          {
            PropertyGroupDescription propertyGroup = group as PropertyGroupDescription;
            if (propertyGroup != null && propertyGroup.PropertyName == e.PropertyName)
            {
              refresh = true;
              break;
            }
          }
        }

        if (refresh)
        {
          View.Refresh();
         
        }
      }

    }

    private void Source_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
      if (e.Action == NotifyCollectionChangedAction.Add)
      {
        SubscribeItemsEvents(e.NewItems, false);
       
      }
      else if (e.Action == NotifyCollectionChangedAction.Remove)
      {
        SubscribeItemsEvents(e.OldItems, true);
      }
      else
      {
        // TODO: Support this
        Debug.Assert(false);
      }
    }
   
    private void SubscribeItemEvents(object item, bool remove)
    {
      INotifyPropertyChanged notify = item as INotifyPropertyChanged;
      if (notify != null)
      {
        if (remove)
        {
          notify.PropertyChanged -= Item_PropertyChanged;
        }
        else
        {
          notify.PropertyChanged += Item_PropertyChanged;
        }
      }
    }

    private void SubscribeItemsEvents(IEnumerable items, bool remove)
    {
      foreach (object item in items)
      {
        SubscribeItemEvents(item, remove);
      }
    }

    private void SubscribeSourceEvents(object source, bool remove)
    {
      INotifyCollectionChanged notify = source as INotifyCollectionChanged;
      if (notify != null)
      {
        if (remove)
        {
          notify.CollectionChanged -= Source_CollectionChanged;
        }
        else
        {
          notify.CollectionChanged += Source_CollectionChanged;
        }
      }
      SubscribeItemsEvents((IEnumerable)source, remove);
    }
  }
}



This new CollectionViewSource class can be added to your Window resources and bound to a ListBox just as you would a normal CollectionViewSource.  For convenience, here is some sample XAML:

<Window x:Class="WPFApp.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
    xmlns:tns="clr-namespace:WPFApp"
    Title="Window1" Height="600" Width="600" Loaded="Window_Loaded">
    <Window.Resources>
      <tns:AutoRefreshCollectionViewSource x:Key="TripSource" >
        <tns:AutoRefreshCollectionViewSource.SortDescriptions>
          <scm:SortDescription PropertyName="Destination" Direction="Ascending"/>
        </tns:AutoRefreshCollectionViewSource.SortDescriptions>
      </tns:AutoRefreshCollectionViewSource>
    </Window.Resources>

This is pretty standard code, but don't forget the two xml namespaces that you need to make this work.  One for the SortDescription element, "scm," (why this is in a different namespace is a mystery!) and the other which simply points to the project where your AutoRefreshCollectionView is (in this case the current project called WPFApp).  This is completed by assigning the ListBox.itemsource in code as follows:

private WPFCollection<Trip> TripData;
private ListCollectionView TripView;
 ...
private void Window_Loaded(object sender, RoutedEventArgs e)
{
  var tripsQuery = context.Trips.Include("Activities");
  this.TripData = new WPFCollection<Trip>(tripsQuery, context);
  this.TripView = this.TripData.GetCollectionView((CollectionViewSource)this.Resources["TripSource"]);
  this.lbxTrips.ItemsSource = this.TripView;
}

This code utilizes the WPFCollection<T> which I showed in my previous post, but with one additional convenience method called GetCollectionView that allows you to more easily set the View.  Below is the C#  for this new method which you can add to the WPFCollection class (see the tweak to this class in this post).


public ListCollectionView GetCollectionView(CollectionViewSource cvs)
{
  cvs.Source = this;
  return (ListCollectionView)cvs.View;
}

Wrap Up
Well, that was pretty much it.  If you're like me you are wondering why the heck do we need all this code just to have a bound ListBox that automatically re-sorts.  There are two possible answers:
  1. I am doing something wrong
  2. Microsoft is doing something wrong
At the moment, my pride and past experience leads me to believe #2.

Tuesday, March 2, 2010

The Entity Framework

Okay, I finally have something worth posting, if only to avoid my own personal amnesia tragedy.  For the last month I have been trying to wrap my head around Entity Framework (EF).  Below is a list of my personal discoveries regarding this technology.

Why should I use EF instead of LINQ to SQL classes?
All of this .NET stuff is fairly new.  LINQ technology was not introduced until .NET 3.0.  LINQ to SQL grew out of the LINQ project and the Object Relational Designer was introduced in Visual Studio 2008.  EF on the other hand, was being created by an entirely separate team at Microsoft called Data Progammability.  Because EF was designed to work with multiple database platforms (not just SQL Server) it became the heir apparent and LINQ to SQL was brought into the Data Programmability team.  As you can guess, that means that LINQ to SQL, although not going away, will not have any shiny new features or abilities.  Like it or not, EF and LINQ to Entities are the future for .NET. (Programming Entitfy Framework, Page 14)

Not Every "Entity" is an EF Entity
For those of us who are new to .NET, it is unfortunate that the .NET landscape is cluttered with so many "Entity" classes from LINQ to SQL (L2S).  If you are making the transition from L2S to EF, you really have to be careful with your terminology.  The best way to keep things straight is to peruse the Designer.cs file generated by the *.edmx and look through all the base class names.  These are the basis for the EF.  Classes you'll need to be familiar with include the following:

EntityObject: The base EF object and corresponds to a record in a specific database table(s).

ObjectSet<TEntity>: This collection represents a database table(or tables). Based on ObjectQuery.

ObjectQuery<TEntity>: Base class for ObjectSet<TEntity> and is the type returned by LINQ to Entity queries.  If you modify an ObjectSet in any way, like using Include() or OrderBy() it will be returned as an ObjectQuery.

EntityCollection<TEntity>:  Represents the *many side of a relationship.  Entity Collections have several methods to help you deal with the relationship.

EntityReference<TEntity>: These objects get paired up with the *one side of relationships.  For example if an Order EntityObject (the many side) has a reference to a Customer EntityObject (the one side) then the Order's Customer property will automatically get paired with a CustomerReference property (an EntityReference object) that provides methods to deal with the one side of the association/relationship.

If you see any other objects with the word "Entity" in their names DO NOT assume that they belong to EF.  If you do, you will probably regret it.

INotifyPropertyChanged
This is the interface that allows objects to notify their bound controls that things have changed and should be updated.  All the EntityObjects created by the Object Relational Designer (ORD) implement this interface and do a good job of sending notifications from their property setter methods.  Unfortunately, Microsoft has not implemented this feature for Associations.  Below is the property setter for a "primitive" property from an EntityObject:

public global::System.String ActivityName
{
    get...
    set
    {
        OnActivityNameChanging(value);
        ReportPropertyChanging("ActivityName");
        _ActivityName = StructuralObject.SetValidValue(value, true);
        ReportPropertyChanged("ActivityName");
        OnActivityNameChanged();
    }
}

Here you can see that there is more than a little notification going on.  But the association setter has nothing:

public EntityReference<Reservation> ReservationReference
{
    get...
    set
    {
        if ((value != null))
        {
            ((IEntityWithRelationships)this).RelationshipManager...
        }
    }
}

Even in .NET 4.0 the oversight has not been corrected.  I will post the workaround for this along with automatically refreshed sorting that I culled from the web in my next post.

EntityCollections and ObjectQueries and ObjectSets, Oh My!
Even if you fix the missing notification stuff above you may not find things working as you would expect.  Some of this comes from the differences between the different collections of EntityObjects that EF delivers to your code.  A decent summary of the state of affairs can be found here, although it is a tad out of date.  What is important is the distinction between these three binding issues:


Binding Works?
EntityCollection
ObjectQuery
ObjectSet
Primitives (e.g., strings or numbers)
Yes
Yes
Yes
Entity Deletions
Yes
Yes
Yes
Entity Additions
Yes
Nope
Yes
Supports Sorting
Nope
.OrderBy()
Nope

This makes sense since EF has no way of knowing if an added object should be in an already executed query.  The lack of sorting means that (for me) these are pretty much worthless for binding so now we need to find a sortable, bindable list/collection class.  This brings up another point: Why the dizzying collection of collections?  Should you be using ListViewCollection, BindingList, ObservableCollection or BindingListCollectionView?  It feels like I need a four year degree in collection science!!  Or at least a weekend seminar.  I can't say that I have any kind of a grasp of the differences, so I won't try to confuse anyone here with my ignorance.  What I can say, is that I see a lot of votes for ObservableCollection<T>.  For example:
"But ideally your source collection derives from ObservableCollection<T>, the mother of all collections in the eyes of data binding, since it provides several extra goodies such as property and collection change notifications."   - from Bea Stolnitz' Blog post (FYI, when reading this post "Avalon" was the old name for WPF)
Clearly I have a lot of learning to do on this whole topic.  Hopefully I will have something more definitive to post at a later date.  I will probably throw my lot in with ObservableCollection<T> and hope for the best.  To that end, below is a custom ObservableCollection<T> that works with EntityObjects in an ObjectQuery to provide proper change notification for additions and deletions.  It has been cobbled together from a posting by Beth Massi which I converted to C# and added generic support.  I also borrowed some code for the GetEntitySetName<T> extension method listed at the bottom from Martin Robins' comments at the bottom of another blog post.


using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Metadata.Edm;
using System.Data.Objects;
using System.Data.Objects.DataClasses;
using System.Linq;
using System.Text;
using BAGA;

namespace WPFApp
{
  public class WPFCollection<T> : ObservableCollection<T> where T: EntityObject
  {
    private ObjectContext _context;
    public ObjectContext Context;
    {
      get { return _context; }
    }

    private EntityCollection _baseCollection;
    public EntityCollection BaseCollection;
    {
      get { return _baseCollection; }
    }

    public WPFCollection(ObjectQuery<T> items, BAEntities context)
      :base(items);
    {
      _context = context;
      _baseCollection = null;
    }

    public WPFCollection(EntityCollection<T> items, BAEntities context);
      : base(items);
    {
      _context = context;
      _baseCollection = items;
    }

    protected override void InsertItem(int index, T item)
    {
      if (_baseCollection != null)
      {
        _baseCollection.Add(item);
      }      else
      {
        String ESName = _context.GetEntitySetName<T>();
        _context.AddObject(ESName, item);
      }
      base.InsertItem(index, item);
    }

    protected override void RemoveItem(int index)
    {
      if (_baseCollection != null)
      {
        _baseCollection.Remove(this[index]);
      }   
      else
      {

        this.Context.DeleteObject(this[index]);
      }
      base.RemoveItem(index);
    }

  }

  //This extension method allows an ObjectContext to get the name of the EntitySet that an EntityObject belongs to;
  static class EFExtensions
  {
    public static string GetEntitySetName<T>(this ObjectContext ctx) where T : EntityObject;
    {

      EdmEntityTypeAttribute attribute = ((EdmEntityTypeAttribute[])typeof(T).GetCustomAttributes(typeof(EdmEntityTypeAttribute), true)).Single();

      EntityContainer container = ctx.MetadataWorkspace.GetEntityContainer(ctx.DefaultContainerName, DataSpace.CSpace);

      return container.BaseEntitySets.Single(es => es.ElementType.Name == attribute.Name).Name;

    }

  }
}

I will use this class in my next post dealing with change notification for entity associations.

Beware the Silo Experts
In order to begin exploring EF, I have been going through the book that I menthioned above: Programming Entity Framework, by Julia Lerman.  I have been enjoying it and it seems to be well written, however it is NOT well edited as there are numerous minor mistakes in the code.  Part of this is undoubtably due to the fact that Julia's native language is VB and she has used a code conversion tool to covert all of her VB examples to C#.  Although this is mildly annoying, it is accompanied by the fact that Julia doesn't know much about WPF and so her examples contain not only bad practices, but misstatements regarding the capabilities of WPF.  I would still recommend Julia's book, just be aware of her weaknesses and take her C# code and statements regarding WPF with very large grain of salt.

This is the general problem with the whole .NET enterprise.  There are too many experts on this or that framework and very few with an holistic knowledge of the vast .NET landscape.  For example, I emailed a Microsoft employee who was an all-star EF guy and he had to defer my relatively simple question on binding to ObjectQuery/ObjectSet objects to someone in the WPF department. Seems like they should ship all of these guys to a summer-camp where they force them to create an application with all of this stuff so they can understand all of the gaping holes that exist between their frameworks.