Wednesday, December 9, 2009

EntitySet Confusion

Okay, from the outset I have been keen on using the LINQ to SQL technology and in my enthusiasm I pressed forward and created LINQ to SQL classes from my SQL database using the handy little designer in Visual Studio.

I mucked around enough to fiqure out what it was doing and use these classes in a form, except one concept has proven a little frustrating: HOW TO USE THE DARNED ENTITYSET COLLECTIONS!  It's not that I couldn't use them, it's just that I didn't find them very useful.  Why?  Because they did not follow the rules of the other collections and I have found it extremely difficult to extract any information from Google on how to deal with them.  Today I made a few discoveries and thought I would post them so you could benefit, if only from a good laugh at my flailing around.

The Problem

When I first attempted to use these EntitySet collections I tried to follow the paradigm for sorting that works for List collections.  That is, in my XAML file:

<Grid>
  <Grid.Resources>
    <CollectionViewSource x:Key="SortedBios" Source="{Binding SelectedItem.CGBiographies, ElementName=cbxManagers, Mode=OneWay}">
      <CollectionViewSource.SortDescriptions>
        <scm:SortDescription PropertyName="Name"/>
      </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
  </Grid.Resources>
  <ListBox Name="lbxBios" DisplayMemberPath="Name" ItemsSource="{Binding Source={StaticResource SortedBios}}"/>
</Grid>

The ListBox populated, but was not sorted.   After searching on the web I found some who suggested to use the EntitSet.ToList() function to return a List object.  So I added a property to my CGManager object:

  public partial class CGManager: InvestBase
  {
    public List BiographyList
    {
      get { return _CGBiographies.ToList(); }
    }
    ...

Then I changed the XAML so that the binding expression in the CollectionViewSource element referenced this property instead of the CGBiographies EntitySet and suddenly my sorting worked!  Only problem is that the List collection does not provide change notification so the ListBox will not automatically update when items are added/removed from the EntitySet.  Defeat was snatched from the jaws of victory. This is a major problem and one that needed to be solved.  Was there a way to sort these frustrating EntitSets?  

The Answer: No.

Okay, "no" for the EntitySet, but that is fortunately not the end of the story.  The EntitySet has a method GetNewBindingList() that returns an IBindingList collection.  As it turns out, this interface provides you with everything you need to not only sort, but to notify your UIElements of changes to the underlying collection.  Here is my new BiographyList property:

  public partial class CGManager: InvestBase
  {
    private BindingList<CGBiography> _BiographyList;
    public BindingList<CGBiography> BiographyList
    {
      get {
        if (_BiographyList == null)
        {
          PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(new CGBiography());
          PropertyDescriptor myProp = properties.Find("Name", true);
          IBindingList bl = (IBindingList)_CGBiographies.GetNewBindingList();
          bl.ApplySort(myProp, ListSortDirection.Ascending);
          _BiographyList = (BindingList<CGBiography>)bl;
        }
        return _BiographyList; }
    }
    ...
After adding this I completely removed the CollectionViewSource element from my XAML and bound the ListBox.ItemSource property directly to the BiographyList property.  Now the sorting happens and if you remove an item from the BiographyList, the ListBox is updated automatically.  This may have some other bumps that I haven't discovered yet, but I have confirmed that the underlying EntitySet is indeed updated through the BindingList.  I haven't spent any time trying to streamline the whole PropertyDescriptor thing, so there is probably a way to get that in a more direct manner, but I'll save that joy for another day.

I have to say, this seems like a lot of code for what should have been a much simpler task, and I am still looking for a better way to do this.  If you have one, please let me know!

PS: ObservableCollection

How about ObservableCollections?  You can create one from an EntitySet using a statement like:

_BiographyList = new ObservableCollection<CGBiography>(CGBiographies);

This results in a collection that can not only be sorted using the above XAML, but will also notify the ListBox of additions and deletions.  Unfortunately, the link between it and the EntitySet is non-existant and so additions and deletions will not be reflected in the EntitySet as they are when using the BindingList.

Friday, December 4, 2009

WPF Book Update and Icons

I'm almost half-way throught the Pro WPF in C# 2008 and I must say that it is well worth every penny.  WPF is not just some add-on to .NET, it is a major organ and this book gives you great insight into its workings.  I especially like the authors frequent use of the, "...you could do it this way, but here's another way and why it's better..."  So much better than just showing you one way to do everything since it gives you a much better picture of the why's and the wherefore's.

First Impressions

In order to cut the boredom while I slog through the reading, I've been playing around with icons.  Now you've probably stumbled across the limited icon editor in Visual Studio and I played around with it a while, but let me just recommend that you don't waste your time with it.  After searching around on the web, I zeroed in on Axialis IconWorkshop.  Yes, it sounds like an erectile dysfunction medication, but this application is just what the doctor ordered for creating and editing your icons.  It even comes with a plug-in for Visual Studio 2008.  There is a 30-day free trial, so you can try before you buy. I've just scratched the surface, but it appears to be top-drawer in most every respect.  First impressions are ever so important, and when it comes to applications your first impression will be the icon.

P.S: Don't try to put a 256x256 size icon in your *.ico file as this seems to make Visual Studio choke...