What Was I Thinking?

Follies & Foils of .NET Development

  Home  |   Contact  |   Syndication    |   Login
  41 Posts | 0 Stories | 97 Comments | 0 Trackbacks

News

Archives

Post Categories

Check These Out

Gurus

Wednesday, November 18, 2009 #

Keynote:

 

HOLY SMOKES!!  Now this is why I came to PDC!  Announced today:  Silverlight 4 Beta.  Printing?  Yep.  Access to Local File System?  Yep.  Want to share your assemblies between SL and native .NET assemblies?  No Problem.  Want access to the clipboard?  COM Interop?  Web Cam & Micrphone?  Done and Done.

 

SketchFlow.. Wha!?!?!  OMG thats a cool prototyping tool.

Sharepoint 2010 is looking like a tour de force.  The ease of development, integration and deployment.  Debugging and sandbox support.  Solutions can be deployed and tested on client OS machines.  Client toolkits uses REST or a Client SDK make it all so attractive.  NICE JOB SHAREPOINT.. NICE JOB.

 

oh yeah.. and then there was this:  Microsoft gives free laptop to PDC 2009 attendees.  Some days its great to be a GEEK.

 

On to Windows Identity Foundation overview. 

Windows Identity Foundation Overview:

Covered the basics of WIF:  Stand up an STS (custom or ADFS), configure your application (RP) to be defended by the tokens issued from your new STS.  Configure the claims to fetch, etc.  WIF Wizards take care of the client configuration, and the WIF http modules will map the incoming token to an Identity, Principal,  and a set of claims.  Optionally you can control authorization logic based on the incoming claims either directly in code or by establishing policy articulated in the RP’s configuration file.  WIF supports Active, Passive and Delegated (ACTAS) scenarios.

Nothing new in this session for me, but I still found the validation to be worth while.

Windows Workflow (Overview and Host Deep Dive)

WF (pronounced dub-eff) 4.0 looks like a great improvement over the 3.0 version.  The product looks highly extensible and powerful, but the overview session was anything but.  Presented by Matt Winkler (Mr. WF) presented a 200 level talk to a bunch of people who were asking “What is Workflow?”.  I have some WF 3x experience, and found it difficult to grasp how the pieces fit together.

 

The follow up session was the “under the hood” of the workflow host, which was surprising interesting and insightful. 

The WF presenters needed a session on “How to build, deploy and debug WF 4.0”.  It would have provided attendees with the skills needed to get going with WF.  For a product line still searching for its user base, I think the WF team missed a great opportunity.

Ask The Experts

Pick a topic,  move to the roundtable filled with experts, and dialog with your peers and gurus.  I sat at the WF table for a while, then moved over to C#. Met two members of the C# dev team.  One, DJ Park, was great to talk with, the other (who shall remain nameless) was an arrogant douchebag.  Tomorrow I’m excited to check out the IntelliTrace stuff in VS2010, but now its time to party down, Geek Style.

 

GeekFest

Wall-to-wall geeks having fun the geek way; there was class video games, air hockey tables, pool tables,  on thz,line sessions of Gears of War, and gaggles of geeks competing in a “Puzzle contest”.  Yeah thats right, they were competing over puzzles.  I enjoyed the video games, pool tables, virtual roller coaster, and free chair massages (I really enjoyed that last one).  Plenty of food and drink, and I’m sure somewhere they were hosting a D&D game, but I can’t confirm that.


Tuesday, November 17, 2009 #

My thoughts and observations of this year’s Microsoft PDC conference in LA.

 

Day 1:

Just registered for the conference.  They had many reps available to move attendees through the registration process.  We arrived early, and had to stand in line for 15 minutes, while all the reps stared blankly back at us; “We don’t open until 7.”  Wow.. Great Customer Service.

 

Let me take this moment to comment on the Conference bag this year.  ITS A CHEAP PIECE OF CRAP.  Literally, it looks like a “reusable” grocery shopping bag, except its so thin, I don’t think it will make it through the conference before it rips; something that’s likely to happen at the most inopportunity time, I’m sure.

 

ok.. I’m on to the “Big Hall” to hear the opening key note.  More to come.

 

Pre-Keynote update:  Having just wandered through miles of hallway, I’m thinking that adding a BUILDING MAP to the updated session list would have been a great idea.   Just a thought.

 

Key Note: Yep, its all about Azure.  Ray Ozzie announced the beta of MS PinPoint, a discovery and procurement site for azure hosted, 3rd Party developed applications (Think AppleStore for your services that you want to sell to others).  Included is an offering, code named “Dallas”.  Dallas is a PinPoint channel that’s all about data.  Want to get access to the US Census data?  Go to The Dallas channel on pinpoint and subscribe to it.  Data is available as data feeds, Restful services, and can even be consumed through ODBC connections.  Any publically available data can be offered through the Dallas channel, and includes the ability for trail and full subscriptions.

other big announcements; VS 2010 has some pretty great debugging and tracing tools. They have included some of the productivity features included in ReSharper, and have a new tool IntelliTrace.  More about this later.

Want to develop Azure services, but run it all locally?  Next year, MS will announce Windows Server 2008 AppFabric.  That’s the ticket. (If they include the .NET services in the fabric, where does that leave the current on-premises solutions like the Biztalk ESB???)

The other big Azure announcement, is a connectivity kit that allows your Azure hosted services to reach into your local premises data stores (using IPv6 and IPSEC tunneling).  NICE!!!

 

More to come.

 

What’s New with C# 4.0 (and some interesting vaporware)…

VB & CS Teams will now synchronize their feature sets (am I the only one who sees a problem with this?)

Dynamic Typing, Declarative programming and Parallel execution, all locked into 4.0 CLR.  You can download the beta bits now.  I must admit I’ve been staying away from Parallel extensions, but they look REALLY interesting and I plan on digging into them a bit. 

and then we saw a demo of some interesting stuff that they “might-possibly-some-day-release-in-a-future-version—but-maybe-not”.

Opening the compiler.  Lets you write your own custom extensions for the compiler and use compiler native types.  This might be good for Tool developers, and opens up the possibility for some interesting aspect oriented stuff, but I don’t think there will be much mainstream interest here.

Simplifying Parallel asynchronous operations.  Using the 4.0 code base its possible to control when threads are returned to the pool during a parallel execution, but its not easy.  They demo’d some simple extension methods which make it OH SO NICE.  I’m hoping this makes it into the 4.x feature set.

I’d write more, but I’ve got to rush off to

 

Lessons Learned Migrating Applications To Windows Azure

This was a panel of companies that had migrated some of their systems to the cloud.  They included B-2-C solutions (like Domino’s Pizza), B-2-B solutions, and Enterprise-only solutions.  The common thread across these early adopters was the desire to support peak loads without having to invest in a self-hosted infrastructure.   All the companies had significant hand-holding from Microsoft, and as of the PDC, none of them had yet gone live.  I didn’t view this as a slam against Azure, but rather the tale of companies cautiously embracing the bleeding edge technologies.

 

Overview of Sharepoint 2010 Programmability:

Having no sharepoint development experience, I thought this might be an interesting presentation for me.  I was right.  Two big take-aways from this presentation.  Number one; if you developed any sharepoint parts, or integration components for earlier versions of sharepoint, you were either insane or foolish.  Sharepoint 2010 takes a big step forward in the development tooling and extensibility.  Sharepoint can now give and receive data from any number of sources.  Want to expose your SQL Server data as a sharepoint list?  No problem.  Want to use your Sharepoint documents as data sources in your .NET application?  No problem.  Need a restful interface to view your Sharepoint data?  No Problem.  Integration isn’t limited to data however, as they demonstrated Silverlight UI’s sitting in front of Sharepoint.  Apparently you can even host sharepoint in the cloud (although that might be a session for tomorrow).

Point #2) If you ever have to make an hour-long presentation of highly technical data, it might be wise not to drink a six-pack of red bull immediately before hand.  The  presenter was so wired, and went so quickly, that even when I wasn’t getting creeped out by him, I didn’t have time to internalize the words coming out of his mouth.  I think at one point he shouted out “I Am Cornholio!” but maybe I just thought I heard that.

EF 4.0 and Beyond (or as I like to call it, Entity Framework 4: STFU)

The theme of the session seemed to be “We introduced Entity Framework, you all said it sucked.  We asked what we needed to do to make it not suck.  You told us.  We did those things, now you need to stop telling us it sucks.”  Adversarial?  Yeah, but hey, at least we’re getting a better product out of it.  They demoed Entity First Design, Support for automatic lazy loading, template generation using T4,  POCO support, offlined objects with dirty tracking, improved control over saving entities and eventing, and FK references.  They also previewed a code only EF model, that generated a data context without a EDMX file, and provided a strongly typed API for controlling model and context behaviors.

 

Connecting applications with the BizTalk enterprise service bus

The first session of PDC 2009 that I walked out of.  Not because the session didn’t sound interesting, or because the featured product was bad.  The presentation was divided between two presenters; the first presenter spoke to the architecture of the service bus and the extensions and providers of the Biztalk ESB toolkit. So far, so good. The problem was the second presenter.  He was so poor he alienated most of the attendees.  Multiple people left the session soon after he began to speak.  It sounded as if he hadn’t planned out his presentation, and his accent made it impossible to discern anything useful.  At one point I think he said something about a Zebra.  I’m not kidding.  For a $2,000 registration fee, Microsoft should ensure their presenters know how to present.   I joined the parade of fellow developers making an early exit.

Partner Expo Reception

The evening’s social event featured an open bar, tasty eats in the vendor expo.  Good Food, Cheap SWAG, and all the technical jargon I could grok.  Geek-On, Baby!


Thursday, November 05, 2009 #

Looks like I’m heading to LA.  I’m really excited to be attending the PDC this year.  I went to the PDC in 03 (where they announced WCF, WF, WPF) and it turned my brain to mush by the middle of day two.  ANyone else going?  Anyone like to share a RSVP promo code to save me some $$$?  I’ll buy you a drink or two!

 

Hope to see you all there!


Friday, October 30, 2009 #

I’ve been spending a lot of time lately debugging through some web-hosted applications.  Some of these applications are hosted by Visual Studio’s own internal web server (Cassini), and others are hosted by my local instance of IIS.

 

Web projects hosted locally get automatic attached to the VS debugger when you press F5.  Projects hosted under IIS do not.  In order to debug IIS hosted projects, you must attach the Visual Studio debugger to the IIS worker process (aspnet_wp.exe or w3wp.exe) manually. 

 

Traditionally, you attach by selecting Attach To Process from the Debug menu, scrolling the list of processes until you find the worker process and then clicking “Attach”.

 

Thanks to this handy macro I found by HologramX at snipplr.com, I’m able to attach with a single keystroke:

To add this macro to your environment,  Tools > Macro IDE > Add new item to MyMacros > Select Module, Name 'AttachToWebServer' > Copy/paste code.

Imports System
Imports EnvDTE80
Imports System.Diagnostics

Public Module AttachToWebServer

Public Sub AttachToWebServer()

Dim AspNetWp As String = "aspnet_wp.exe"
Dim W3WP As String = "w3wp.exe"

If Not (AttachToProcess(AspNetWp)) Then
If Not AttachToProcess(W3WP) Then
System.Windows.Forms.MessageBox.Show(String.Format("Process {0} or {1} Cannot Be Found", AspNetWp, W3WP), "Attach To Web Server Macro")
End If
End If

End Sub

Public Function AttachToProcess(ByVal ProcessName As String) As Boolean

Dim Processes As EnvDTE.Processes = DTE.Debugger.LocalProcesses
Dim Process As EnvDTE.Process
Dim ProcessFound As Boolean = False

For Each Process In Processes
If (Process.Name.Substring(Process.Name.LastIndexOf("\") + 1) = ProcessName) Then
Process.Attach()
ProcessFound = True
End If
Next

AttachToProcess = ProcessFound

End Function

End Module

 

To set as a keyboard shortcut go to Tools > Options > Keyboard, and search for the name of the macro (AttachToWebServer) and then assign a keyboard shortcut.

IIS-Attached Debugging is now one keystroke away.


Monday, October 19, 2009 #

When adding an item to a dictionary, I always thought you had to use the Add() method, like this:

string key = "MyKey";
int value = 20;
var myDictionary = new Dictionary<string, int>();
myDictionary.Add(key, value);

Apparently, you can directly reference it in the collection, and if the key doesn’t exist, its auto-added to the collection

string key = "MyKey";
int value = 20;
var myDictionary = new Dictionary<string, int>();
myDictionary[key] = value;

most likely you already knew this.  I did not.  Its the little things I guess.


Monday, October 12, 2009 #

I’m a big fan of Resharper.  Its loaded with refactoring and best practice guidance that makes me a better developer.  I’ve also started working with .NET RIA services.  The verdict is still out on RIA services, but I think I like them. Unfortunately RIA has an interesting approach to code sharing between the web and Silverlight project that's incompatible with Resharper.  It used generated code that is technically excluded from the project.   As a result, any code in my Silverlight project that references any of the shared classes won’t resolve for Resharper and valid code ends up looking like this:

 

image

 

This is likely to be addressed in a future version of Resharper (if RIA services takes hold), until then you can still get Resharper to resolve your shared code by:

  1. Select your Silverlight project in the Solution Explorer
  2. Select the Show All Files option from the Solution Explorer toolbar.
  3. Right-Click on the Generated Code folder and select Include In Project

As part of the project, Resharper will pick up the generated shared code and resolve your shared classes appropriately.  During compilation you may receive an warning about modifying a project file during compilation.  Just continue with the warning (in my case, I simply suppress the warning dialog so I’m not bothered with it).

 

With Generated Code include in my project, Resharper is back in full effect.

image


Sunday, October 11, 2009 #

Silverlight bundles its executables into a single file with a XAP extension.  This is really just a zip file.  You can open the XAP and modify the contents just as you would any ZIP file.  By default windows explorer doesn’t know how to open XAP files.

 

The following reg file adds the metadata to tell Explorer to treat XAP files like compressed folders.  I found this file somewhere on the internet, my apologies for not being able to site the source.

 

Windows Registry Editor Version 5.00 

[HKEY_CLASSES_ROOT\.xap]
"PerceivedType"="compressed"
"Content Type"="application/x-silverlight-app"
@="CompressedFolder"

[HKEY_CLASSES_ROOT\.xap\CompressedFolder]

[HKEY_CLASSES_ROOT\.xap\OpenWithProgids]
"CompressedFolder"=""

[HKEY_CLASSES_ROOT\.xap\PersistentHandler]
@="{098f2470-bae0-11cd-b579-08002b30bfeb}"

The file is available for download here

After apply the registry changes, you’ll be able to open XAP files directly in Windows Explorer.


Saturday, October 10, 2009 #

Recently I had the need to implement support for Dynamic Linq queries in my framework project.  For the uninitiated, Dynamic Linq allows me to write statements like this:

var query =
               db.Customers.Where("City == @0 and Orders.Count >= @1", "London", 10).
               OrderBy("CompanyName").
               Select("New(CompanyName as Name, Phone)");

where I can specify the predicates and selectors as string values.   Microsoft has published a helper class that enables DynamicLinq support here -->C# Dynamic Query Library (included in the -LinqSamples-DynamicQuery directory).

 

Buried in this code is a class Called Dynamic.cs.  Include this code file into your project and you’ll have Dyanmic Linq support, Unless…

 

Unless, you’re developing a silverlight application.  The dynamic class makes use of a ReaderWriterLock class that isn’t available in the Silverlight implementation of System.Threading.

Using Reflector, I extracted the disassembled code for ReaderWriterLock and made a version that will compile and run under silverlight.  The only adjustment was commenting out the HostProtection attribute since it wasn’t available due to its protection level.  In my testing I haven’t run into any problems as the result of removing this attribute.

Here’s the code you’ll want to add to your silverlight libraries in order to allow the compilation of Dynamic.cs and support Dynamic Linq in your silverlight project:

 

ReaderWriterLock.cs

using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using System.Runtime.ConstrainedExecution;
using System.Security.Permissions;
using System;
//[ComVisible(true), HostProtection(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
[ComVisible(true)]
public sealed class ReaderWriterLock : CriticalFinalizerObject
{
    // Fields
    private int _dwLLockID;
    private int _dwState;
    private int _dwULockID;
    private int _dwWriterID;
    private int _dwWriterSeqNum;
    private IntPtr _hObjectHandle;
    private IntPtr _hReaderEvent;
    private IntPtr _hWriterEvent;
    private short _wWriterLevel;
 
    // Methods
    public ReaderWriterLock()
    {
        this.PrivateInitialize();
    }
 
    public void AcquireReaderLock(int millisecondsTimeout)
    {
        this.AcquireReaderLockInternal(millisecondsTimeout);
    }
 
    public void AcquireReaderLock(TimeSpan timeout)
    {
        long totalMilliseconds = (long)timeout.TotalMilliseconds;
        if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
        {
            throw new ArgumentOutOfRangeException("timeout", "ArgumentOutOfRange_NeedNonNegOrNegative1");
        }
        this.AcquireReaderLockInternal((int)totalMilliseconds);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void AcquireReaderLockInternal(int millisecondsTimeout);
    public void AcquireWriterLock(int millisecondsTimeout)
    {
        this.AcquireWriterLockInternal(millisecondsTimeout);
    }
 
    public void AcquireWriterLock(TimeSpan timeout)
    {
        long totalMilliseconds = (long)timeout.TotalMilliseconds;
        if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
        {
            throw new ArgumentOutOfRangeException("timeout", "ArgumentOutOfRange_NeedNonNegOrNegative1");
        }
        this.AcquireWriterLockInternal((int)totalMilliseconds);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void AcquireWriterLockInternal(int millisecondsTimeout);
    [MethodImpl(MethodImplOptions.InternalCall)]
    public extern bool AnyWritersSince(int seqNum);
    public void DowngradeFromWriterLock(ref LockCookie lockCookie)
    {
        this.DowngradeFromWriterLockInternal(ref lockCookie);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void DowngradeFromWriterLockInternal(ref LockCookie lockCookie);
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void FCallReleaseLock(ref LockCookie result);
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void FCallUpgradeToWriterLock(ref LockCookie result, int millisecondsTimeout);
    ~ReaderWriterLock()
    {
        this.PrivateDestruct();
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void PrivateDestruct();
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern bool PrivateGetIsReaderLockHeld();
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern bool PrivateGetIsWriterLockHeld();
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern int PrivateGetWriterSeqNum();
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void PrivateInitialize();
    public LockCookie ReleaseLock()
    {
        LockCookie result = new LockCookie();
        this.FCallReleaseLock(ref result);
        return result;
    }
 
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    public void ReleaseReaderLock()
    {
        this.ReleaseReaderLockInternal();
    }
 
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern void ReleaseReaderLockInternal();
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    public void ReleaseWriterLock()
    {
        this.ReleaseWriterLockInternal();
    }
 
    [MethodImpl(MethodImplOptions.InternalCall), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    private extern void ReleaseWriterLockInternal();
    public void RestoreLock(ref LockCookie lockCookie)
    {
        this.RestoreLockInternal(ref lockCookie);
    }
 
    [MethodImpl(MethodImplOptions.InternalCall)]
    private extern void RestoreLockInternal(ref LockCookie lockCookie);
    public LockCookie UpgradeToWriterLock(int millisecondsTimeout)
    {
        LockCookie result = new LockCookie();
        this.FCallUpgradeToWriterLock(ref result, millisecondsTimeout);
        return result;
    }
 
    public LockCookie UpgradeToWriterLock(TimeSpan timeout)
    {
        long totalMilliseconds = (long)timeout.TotalMilliseconds;
        if ((totalMilliseconds < -1L) || (totalMilliseconds > 0x7fffffffL))
        {
            throw new ArgumentOutOfRangeException("timeout","ArgumentOutOfRange_NeedNonNegOrNegative1");
        }
        return this.UpgradeToWriterLock((int)totalMilliseconds);
    }
 
    // Properties
    public bool IsReaderLockHeld
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        get
        {
            return this.PrivateGetIsReaderLockHeld();
        }
    }
 
    public bool IsWriterLockHeld
    {
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        get
        {
            return this.PrivateGetIsWriterLockHeld();
        }
    }
 
    public int WriterSeqNum
    {
        get
        {
            return this.PrivateGetWriterSeqNum();
        }
    }
}
 

and LockCookie.cs

using System.Runtime.InteropServices;
[StructLayout(LayoutKind.Sequential), ComVisible(true)]
public struct LockCookie
{
    private int _dwFlags;
    private int _dwWriterSeqNum;
    private int _wReaderAndWriterLevel;
    private int _dwThreadID;
    public override int GetHashCode()
    {
        return (((this._dwFlags + this._dwWriterSeqNum) + this._wReaderAndWriterLevel) + this._dwThreadID);
    }
 
    public override bool Equals(object obj)
    {
        return ((obj is LockCookie) && this.Equals((LockCookie)obj));
    }
 
    public bool Equals(LockCookie obj)
    {
        return ((((obj._dwFlags == this._dwFlags) && (obj._dwWriterSeqNum == this._dwWriterSeqNum)) && (obj._wReaderAndWriterLevel == this._wReaderAndWriterLevel)) && (obj._dwThreadID == this._dwThreadID));
    }
 
    public static bool operator ==(LockCookie a, LockCookie b)
    {
        return a.Equals(b);
    }
 
    public static bool operator !=(LockCookie a, LockCookie b)
    {
        return !(a == b);
    }
}
 
 

 

and ReliabilityContract.cs

using System;
[AttributeUsage(AttributeTargets.Interface | AttributeTargets.Method | AttributeTargets.Constructor | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Assembly, Inherited = false)]
public sealed class ReliabilityContractAttribute : Attribute
{
// Fields
private Cer _cer;
private Consistency _consistency;

// Methods
public ReliabilityContractAttribute(Consistency consistencyGuarantee, Cer cer)
{
this._consistency = consistencyGuarantee;
this._cer = cer;
}

// Properties
public Cer Cer
{
get
{
return this._cer;
}
}

public Consistency ConsistencyGuarantee
{
get
{
return this._consistency;
}
}
}
public enum Consistency
{
MayCorruptProcess,
MayCorruptAppDomain,
MayCorruptInstance,
WillNotCorruptState
}


public enum Cer
{
None,
MayFail,
Success
}












Thursday, October 01, 2009 #

Manish Dalal wrote an excellent post on how to effectively data bind a silverlight combobox for foreign key scenarios.  Using his approach, you create a ListProvider class that receives a DomainContext, internally loads the data into the context, and exposes the loaded data through an easily bound property.

Having written a few of these, I’ve refactored the list provider functionality to a generic base class.  The heavy lifting is done via reflection and it should be noted that my code assumes you take the default naming convention of the entities and entity collections in the DomainContext class.

 

Defining the class

Here’s my base class:

public abstract class ListProviderBase<T, DC> : INotifyPropertyChanged where T : Entity, new()where DC : DomainContext
  {
      protected DC context;
      readonly Type itemType = typeof(T);
      public event Action<LoadOperation<T>> PickListLoadingComplete;
      public DC DomainContext
      {
          set
          {
              context = value;
       
              // Get the query object for the specified item Type
              MethodInfo queryMI = context.GetType().GetMethod("Get" + itemType.Name + "Query");
              EntityQuery<T> query = (EntityQuery<T>) queryMI.Invoke(context, null);

              // Load the data into the context, upon completion, call back to PickListDataLoad_Complete
              context.Load<T>(query, PickListDataLoad_Complete, itemType);
              onPropertyChanged("DomainContext");
          }
          get
          {
              return context;
          }
      }

      /// <summary>
      /// call back that fires when the data list loading is complete
      /// </summary>
      /// <param name="obj"></param>
      private void PickListDataLoad_Complete(LoadOperation<T> obj)
      {

          string msg = String.Format(((Type)obj.UserState).Name + " Pick List loaded with {0} Entries",
                                     obj.Entities.Count());
          Debug.WriteLine(msg);
          if (PickListLoadingComplete != null)
              PickListLoadingComplete(obj);
          onPropertyChanged("PickList");
      }

      /// <summary>
      /// The list of entities to appear in the list.  Bind to this element.
      /// </summary>
      public EntityList<T> PickList
      {
          get
          {
              // return the corresponding EntityList property.
              // Note:  This assumes the ItemList uses the default naming convention 
              //        in the domain context (ie the list of customer objects is accessed via the Customers property)
              return (EntityList<T>)readProperty(itemType.Name+"s", context);
          }
      }

      /// <summary>
      /// using reflection, reads the specified property from the specified object
      /// </summary>
      /// <param name="propertyName"></param>
      /// <param name="obj"></param>
      /// <returns></returns>
      private static object readProperty(string propertyName, object obj)
      {
          PropertyInfo propInfo = obj.GetType().GetProperty(propertyName);
          object propValue = propInfo.GetValue(obj, null);
          return propValue;
      }

      private void onPropertyChanged(string propertyName)
      {
          if (PropertyChanged != null)
              PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
      public event PropertyChangedEventHandler PropertyChanged;
  }

Within my application, I sub class the base class and specify my application’s DomainContext.

public abstract class NBOListProviderBase<T> :ListProviderBase<T,NBODomainContext> where T:Entity,new(){}

when I want to populate a combo with a list of related departments, its a single line of code to create the ListProvider;

public class DepartmentListProvider : NBOListProviderBase<Department> { }

Defining the Control

Add the definition as static resource in my XAML
   <Grid.Resources>
       <app:DepartmentListProvider x:Name="departmentListProvider" />
   </Grid.Resources>
 and define the combo box as follows:
                            <ComboBox  ItemsSource="{Binding PickList, Source={StaticResource departmentTypeListProvider}}"
                                       SelectedItem="{Binding Department, Mode=TwoWay}"
                                       DisplayMemberPath="DepartmentName"  />

This binds the control’s source to the PickList property of the instance of the DepartmentTypeListProvider object, instructs the combobox to show the DepartmentName values as the list content, and store the selected item in the Department property of the data context.

Loading the Data

In the Loaded event of the form hosting the combobox, be sure to set the DomainContext property of the list provider.  This will populate the data into the combobox and expose it via the PickList property.  I’ve written a helper method (again using some reflection) to make this easier.

 

public static class ViewHelper
   {
       public static void SetListProviderContext(FrameworkElement ResourceContainer, string ListProviderResourceName, DomainContext Context)
       {
           var listProvider = ResourceContainer.Resources[ListProviderResourceName];
           var propInfo = listProvider.GetType().GetProperty("DomainContext");
           propInfo.SetValue(listProvider, Context, null);
       }
   }

 To Load our combobox data, place the following code in the loaded event of the form that hosts the combobox:

 

ViewHelper.SetListProviderContext(LayoutRoot, "departmentListProvider", this.dds.DomainContext);

When the form renders, the combobox list will be loaded.  See Manish’s comments on overriding the equality operator to ensure the correct value is automatically selected editing existing data.


Monday, September 07, 2009 #

It appears Microsoft has removed the designer for XAML files from the latest release of Silverlight 3 Tools.  The designer isn’t really gone, its just moved to the bottom of the editor and is hidden by default.

 

To restore the designer view:

1. Open your .xaml file in the default vs editor.

2. Move your cursor to the bottom of the edit window (right underneath the horizontal scroll) and it should change to a split-style cursor

3. Click and drag up to reveal a pane that looks like the following:

image

4. Click on the “Resume Loading the Designer” link.  The designer should now be present

 

image

I haven’t found a way to tell VS to remember this layout preference, and to auto-load the designer yet, but I’ll keep looking.

Its my understanding Microsoft will be replacing it with a better designer when VS 2010 ships.