Windows 7 Upgrade boot configuration issue solved

I have already done a couple of Windows 7 upgrades over the past two weeks. I have found it to be the best upgrade Microsoft has ever produced. The upgraded computers run as fast (my perception) as if I had done a fresh installation. So I tackled my third upgrade this evening (a 32-bit Vista Ultimate on my daughters laptop), and ran into a glitch during the Setting and Programs copying stage. The Windows 7 installer stopped and reported that it could not continue because of a boot configuration problem as shown below.

clip_image002

At first, I thought it might be because I had selected a selective startup using msconfig as shown below.

image

I reset it to Normal startup and started the upgrade again. It stopped with the same issue. So I brought up System Properties, clicked the Startup and Recovery Settings button, and found there was no operating system to select in the dropdown! That can’t be good. So I did some research and found this article telling me how to run the bootrec tool from the Recovery Console to rebuild my Boot Configuration Data (BCD) store. But I didn’t even need to go that far. Right after booted my original Vista 32-bit DVD, and selected ‘Repair this computer’ from the initial preboot environment, I was offered the option to rebuild and restart. I did that, and once booted back into Vista, I found the OS listed in the System Properties, Startup and Recovery dialog. I don’t know how the computer got to that state in the first place, but the Windows 7 upgrade finished without further issues. Hope this helps.

Bob Baker

Technorati Tags: ,,

Two Collection Extensions for Unit Testing

Last week, an associate asked me a question about unit testing and mock business objects. She was writing unit tests against some rather complicated business entities with a deep object tree, and wanted to know if it was possible for her to get access to one of the lower level objects in a collection inside a parent object? She only wanted to create one mocked parent-level entity.

So, at the same time, I was perusing the Microsoft Composite Application (Prism) source code, and saw the CollectionExtensions class. Hmm, I love extension methods. What if I could write an extension to a generic collection that would find an object based on a passed-in property of the particular object she was looking for? Think of it as a FindByID kind of functionality for collections.

So I quickly wrote this (I know. I should have written the Unit Test first):

    /// <summary>
    /// Find an object in a collection.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="collection">The collection to search.</param>
    /// <param name="isMatch">The Predicate to test to find the collection item.</param>
    /// <returns>The collection item.</returns>
    public static T GetItem<T>(this ICollection<T> collection,
                               Predicate<T> isMatch)
    {
        foreach (var item in collection)
        {
            if (isMatch(item))
                return item;
        }
        return null;
    }

And then I wrote a unit test to see how I did.

    [TestMethod]
    public void CanGetItemfromCollection()
    {
        var col = new Collection<string> {"Hello", "World"};
        var testItem = col.GetItem(c => c.Equals("World"));
        Assert.IsNotNull(testItem);
        Assert.AreEqual(testItem, "World");
    }

Nice. It passed. Now, I should extend this to support a more real-world example, say a person.

    /// <summary>
    /// Person class for simple mocking
    /// </summary>
    public class Person
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

So, I wrote another a unit test for the more complicated example:

    [TestMethod]
    public void CanGetItemfromCollectionByProperty()
    {
        var col = new Collection<Person>
    {
        new Person {ID = 1, Name = "Bob"},
        new Person {ID = 1, Name = "Jim"}
    };
        var testItem = col.GetItem(c => c.ID.Equals(2));
        Assert.AreEqual(testItem.Name, "Jim");
    }

Oh, the evils of copy and paste (a true Anti-Pattern)! This test failed with a NullReferenceException in the GetItem extension method. Do you see why? How fortunate for me that I accidently left two objects with the same ID. For without that, there would be no blog post today. Still, I corrected the typo and ran a successful test.

I could certainly do an Assert.IsNotNull on the return value, but then if it was null, I couldn't proceed in the test without seeing the failed test notes detailing the NullReferenceException in the called method. It did not break the running test; it only failed the test, and that's not really a bad thing at all, considering that a typo caused it.

If I threw a NullReferenceException myself in the extension method, that could be safer/saner for the developer depending on your point of view. That version as shown below still failed the test, but did not break it.

    /// <summary>
    /// Find an object in a collection.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="collection">The collection to search.</param>
    /// <param name="isMatch">The Predicate to test to find the collection item.</param>
    /// <returns>The collection item.</returns>
    public static T GetItem<T>(this ICollection<T> collection, Predicate<T> isMatch)
    {
        foreach (var item in collection)
        {
            if (isMatch(item))
                return item;
        }
        throw new NullReferenceException("Collection object of type " + typeof(T) + 
                " not found for predicate provided and therefore, not initialized");
    }

Here's an edited version of what showed up in the Test Results:

Test method CanGetItemfromCollectionByProperty threw exception: System.NullReferenceException: Collection object of type CollectionExtensionsFixture+Person not found for predicate provided, and therefore, is not initialized.

So, a typo could break an app using the extension method at runtime versus the more desired compile time break. So, I tried to just return default(T) in the extension method instead of throwing an exception, and add Assert.IsNotNull(testItem) in the test method. I could do this safely and get a clean failure with or without the typo:

It would be good to figure out a way to new up a class<T> in the extension method if one isn't found with the provided predicate.

So, I walked down the hall to my neighborhood C# guru, and asked about the issue with the return value in my extension method. He quickly pointed out that I might need to consider writing specialized methods for value and reference types, and off I went to seek extension method nirvana.

At first, I tried to just add a where T : class to the basic GetItem extension method, but that made no difference; I was still getting a null reference back. I could fudge the Unit Test with an Assert.IsNotNull and then some if testing, but that's not the right way to go about it. Here's the 'abomination':

    [TestMethod]
    public void CanGetItemfromCollectionByProperty()
    {
        var col = new Collection<Person>
        {
            new Person {ID = 1, Name = "Bob"},
            new Person {ID = 2, Name = "Jim"}
        };
        var testItem = col.GetItem(c => c.ID.Equals(2));
        Assert.IsNotNull(testItem);
        if (testItem != null)
            Assert.AreEqual(testItem.Name, "Jim");
    }

Code smell, right? So I tried where T : new() in the extension method, but quickly got a compiler error, because in my basic single string test method, the extension method cannot handle the fact that the string object has no empty constructor. So, it looks like my guru was correct. Here's the answer:

    /// <summary>
    /// Find a value type object in a value-type collection.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="collection">The collection to search.</param>
    /// <param name="isMatch">The Predicate to test to find the collection item.</param>
    /// <returns>The collection item.</returns>
    public static T GetValueItem<T>(this ICollection<T> collection, Predicate<T> isMatch)
    {
        foreach (var item in collection)
        {
            if (isMatch(item))
                return item;
        }
        return default(T);
    }

    /// <summary>
    /// Find a reference type object in a collection of reference types.
    /// </summary>
    /// <typeparam name="T">Type of collection.</typeparam>
    /// <param name="collection">The collection to search.</param>
    /// <param name="isMatch">The Predicate to test to find the collection item.</param>
    /// <returns>The collection item.</returns>
    public static T GetReferenceItem<T>(this ICollection<T> collection, Predicate<T> isMatch) 
where T : class, new() { foreach (var item in collection) { if (isMatch(item)) return item; } return new T(); }

For a value type, we simply return the default value of a new object (e.g., String.Empty, etc.). For a reference type, we simply return a new empty object. As long as there are no constraints preventing an empty new object, we'll be fine.

Testing now becomes straight-forward and gracefully supports typo's (and resulting nulls or empty objects) in either value type or reference type scenarios. Here are the revised test methods:

    [TestMethod]
    public void CanGetValueItemfromCollection()
    {
        var col = new Collection<string> { "Hello", "World" };
        var testItem = col.GetValueItem(c => c.Equals("World"));
        Assert.AreEqual(testItem, "World");
    }

    [TestMethod]
    public void CanGetReferenceItemfromCollectionByProperty()
    {
        var col = new Collection<Person>
        {
            new Person {ID = 1, Name = "Bob"},
            new Person {ID = 2, Name = "Jim"}
        };
        // known good by ID
        var testItem = col.GetReferenceItem(c => c.ID.Equals(2));
        Assert.AreEqual(testItem.Name, "Jim");
        // known does not exist
        testItem = col.GetReferenceItem(c => c.ID.Equals(3));
        Assert.IsNull(testItem.Name);
        // known good by Name
        testItem = col.GetReferenceItem(c => c.Name.Equals("Bob"));
        Assert.AreEqual(testItem.ID, 1);
    }

    /// <summary>
    /// Person class for simple mocking
    /// </summary>
    public class Person
    {
        /// <summary>
        /// ID
        /// </summary>
        public int ID { get; set; }
        /// <summary>
        /// Name
        /// </summary>
        public string Name { get; set; }
    }

Of course, your Person class comes from a mocked service or other separate class, right? Now if only I could mooch some of those Christmas cookies from my associate. And I hope your Christmas is joyful, and wish everyone a 2010 that is pronounced correctly.

Comments? Questions? Flames? Send me an email by clicking on my name below.

Bob Baker

Silverlight 3, .Net RIA Services, and common lookup data Redux

Introduction

Back in March, I blogged about this topic here, and while that post provided some sample code as a first draft approach which could lead you to much of the solution, I did not provide a workable sample. So many folks have helped me with Silverlight 3 and the exciting potential it has for quickly developing Line-of-Business (LOB) applications, and this topic appears to be such a frequent question on the Silverlight forums, that I felt I owed it to the community to revisit this topic in a more complete fashion.

So, today, we will dive into a complete end-to-end solution that highlights the following technologies:

  • Silverlight 3
  • .Net RIA Services
  • Databinding of lookup data from separate entities with Foreign Key relationships

Update: This post is based on the Silverlight 3 Beta and the .Net RIA Services May 2009 CTP. Unfortunately, it breaks with the RTM version of Silverlight 3 and the July CTP of RIA Services in the areas of data access and the DataForm control. I promise to update this article as soon as possible, or write an entirely new one.

There will be no coverage of the new Silverlight 3 features supporting navigation, user authentication, out-of-browser (OOB) experience, pixel shaders, video codecs, etc. Instead, we will build a simple application focusing on the unique challenges associated with combo boxes in Silverlight data consuming applications. Nor will I be delving into how to implement this using a Model-View-ViewModel (MVVM) pattern. To keep things simple, we will use the Northwind database in an Entity Framework model (provided in the download). The UI will consist of a DataGrid for selecting Products and a linked DataForm with the selected Product Details. Because the Northwind Products table is related to the Categories and Suppliers tables via declarative foreign keys, we will provide a combo box for each that is bound to the equivalent foreign key on the Categories and Suppliers tables. The key difference is that we will display the human-readable name of the currently selected Category of Supplier in the dropdown, as well as a list of same when in edit mode and selecting a Category or Supplier. We won’t be binding to the actual child entities, but instead to IDictionary (key, value) implementations of them, which we will load immediately and cache on the client for performance.

I must extend a special thanks to Luke Longley of Microsoft and Chris Anderson (the original article from which I got the inspiration for the IDictionary refactoring was posted here), as well as numerous other folks on the Silverlight forums for their kind assistance in helping me understand what needed to be done to solve this UI challenge.

There is a complete sample project here for you to download and experiment with. Of course, you will need the Silverlight 3 Beta, .Net RIA Services 1.0 Beta, and Silverlight 3 Beta Tools for Visual Studio mentioned above. All of these are available here. You should have SQL Server Express 2005 installed at a minimum, but this project will also work with SQL Server 2005 or any version of SQL Server 2008 as well; you’ll just have a little re-configuration to do.

Getting to work

So, to begin, open Visual Studio 2008, and create a new Silverlight 3 Application (I called it SL3ComboBoxDemo). The Northwind database (modified by John Papa for the Entity Framework) is supplied in the Web project’s App_Data directory, so if you want to start with a fresh project instead of opening the sample, simply copy it there. In your Web project, add a new ADO.Net Entity Framework item and point it at your local NorthwindEF database. I named my model NorthwindEF_Model, and selected the Categories, Products and Suppliers tables. I named the connection string NorthwindEF_Entities and finished up.

Again in your Web project, add a new DomainService item. I named mine NorthwindEFService and checked all checkboxes to enable editing and metadata generation on the three entities in the model.

If you’re unfamiliar with the preceding two steps, simply refer to the first several chapters of the Microsoft .Net RIA Services Overview document. I then copied the code out of the automatically generated Test aspx file in the Web project and pasted it over top of the code in Default.aspx starting after the initial Page tag. I then deleted both test files (.aspx and .html).

Your solution (minus the items we’re going to add) should now look something like this:

image

Figure 1. SL3ComboBoxDemo Solution

Note that I have added the ErrorWindow files from the Silverlight Business Application template to our Silverlight 3 client project. We may need this, but hopefully not today <g>. Verify that SL3ComboBoxDemo.Web is your startup project and that Default.aspx is the set as the Start Page.

Open up the NorthwindEFService.metadata.cs file and make some additions in the ProductsMetadata as follows:

    [Include]
    public Categories Categories;
    [Include]
    public Suppliers Suppliers;

Now Build the solution. This generates the RIA data access code on the SL3ComboBoxDemo client.

The User Experience

Let’s add some UI and code-behind. Again, to keep things simple, we’re just going to add our UI and logic to the pages created by the project template: MainPage.xaml and MainPage.xaml.cs. In MainPage.xaml, add the following namespace references:

xmlns:data="clr-namespace:System.Windows.Data;
      assembly=System.Windows.Ria.Controls"
xmlns:dataControls="clr-namespace:System.Windows.Controls;
      assembly=System.Windows.Controls.Data.DataForm"
xmlns:ods="clr-namespace:System.Windows.Controls;
      assembly=System.Windows.Ria.Controls"
xmlns:datagrid="clr-namespace:System.Windows.Controls;
      assembly=System.Windows.Controls.Data" 
xmlns:converter="clr-namespace:SL3ComboBoxDemo.ValueConverters"

I set the width and height of the UserControl to 800 and 390 respectively, and this seemed to work for this application. Replace everything else from the outermost <Grid … declaration to the end of that Grid with this:

<Grid x:Name="LayoutRoot" Background="White" 
    HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
  <Grid.Resources>
    <converter:CurrencyConverter x:Key="CurrencyConverter" />
    <converter:DictionaryConverter x:Key="DictionaryConverter" />
  </Grid.Resources>
  <Border BorderBrush="#AA000000" BorderThickness="2" CornerRadius="5" 
          Margin="5,5,5,5" VerticalAlignment="Stretch" 
HorizontalAlignment="Stretch" > <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center"> <TextBlock Text="Silverlight 3 DataForm Combo Box Binding Demonstration" HorizontalAlignment="Center"/> <StackPanel> <ods:DomainDataSource x:Name="dds" LoadMethodName="LoadProducts" AutoLoad="True" LoadSize="42" LoadedData="dds_LoadedData" LoadingData="dds_LoadingData" SubmittedChanges="dds_SubmittedChanges" DataContext="BusinessManager.Context"> <ods:DomainDataSource.SortDescriptors> <data:SortDescriptor PropertyPath="ProductName" Direction="Ascending" /> </ods:DomainDataSource.SortDescriptors> <ods:DomainDataSource.FilterDescriptors> <data:FilterDescriptorCollection> <data:FilterDescriptor PropertyPath="ProductName" Operator="Contains"> <data:ControlParameter PropertyName="Text" RefreshEventName="TextChanged" ControlName="nameFilterBox"> </data:ControlParameter> </data:FilterDescriptor> </data:FilterDescriptorCollection> </ods:DomainDataSource.FilterDescriptors> </ods:DomainDataSource> <StackPanel Orientation="Horizontal" Margin="7,7,0,0"> <StackPanel VerticalAlignment="Top"> <StackPanel Orientation="Horizontal" Margin="0,0,0,5"
VerticalAlignment="Top"> <TextBlock Text=" Find: " VerticalAlignment="Center"/> <TextBox x:Name="nameFilterBox" Width="234" Height="24" /> </StackPanel> <datagrid:DataGrid x:Name="dataGrid1" Width="270" Height="266" HorizontalAlignment="Left" VerticalAlignment="Top" AutoGenerateColumns="False" IsReadOnly="True" SelectionChanged="dataGrid1_SelectionChanged" ItemsSource ="{Binding Data, ElementName=dds}"> <datagrid:DataGrid.Columns> <datagrid:DataGridTextColumn Header="Product Name" Binding="{Binding ProductName}" CanUserSort="True" /> </datagrid:DataGrid.Columns> </datagrid:DataGrid> <dataControls:DataPager x:Name="pager1" Width="270" PageSize="10" HorizontalAlignment="Left" Source="{Binding Data, ElementName=dds}"> </dataControls:DataPager> </StackPanel> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*" /> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Margin="3,0,0,0"> <dataControls:DataForm x:Name="dataForm1" Margin="5,0,5,0"
MinHeight="280" AutoEdit="False" AutoCommit="False" Width="480" VerticalAlignment="Top" CommandButtonsVisibility="All" Header="Product Details" CurrentItem="{Binding ElementName=dataGrid1, Path=SelectedItem}" DeletingItem="dataForm1_DeletingItem" ItemEditEnded="dataForm1_ItemEditEnded" AddingItem="dataForm1_AddingItem" AutoGenerateFields="False" CanUserAddItems="True"
CanUserDeleteItems="True"> <dataControls:DataForm.Fields> <dataControls:DataFormFieldGroup Orientation="Horizontal" > <dataControls:DataFormTextField FieldLabelPosition="Top" FieldLabelContent="Product Name " Binding="{Binding ProductName, Mode=TwoWay }" /> <dataControls:DataFormTextField FieldLabelPosition="Top" FieldLabelContent="Price " Binding="{Binding UnitPrice, Mode=TwoWay, Converter={StaticResource CurrencyConverter} }" /> </dataControls:DataFormFieldGroup> <dataControls:DataFormFieldGroup Orientation="Horizontal" > <dataControls:DataFormTextField FieldLabelPosition="Top" FieldLabelContent="Units In Stock " Binding="{Binding UnitsInStock, Mode=TwoWay }" /> <dataControls:DataFormTextField FieldLabelPosition="Top" FieldLabelContent="Units On Order " Binding="{Binding UnitsOnOrder, Mode=TwoWay }" /> <dataControls:DataFormTextField FieldLabelPosition="Top" FieldLabelContent="Reorder Level" Binding="{Binding ReorderLevel, Mode=TwoWay }" /> </dataControls:DataFormFieldGroup> <dataControls:DataFormSeparator/> <dataControls:DataFormFieldGroup Orientation="Horizontal"> <dataControls:DataFormComboBoxField x:Name="cboCategories" FieldLabelContent="Category:" DisplayMemberPath="Value" Binding="{Binding CategoryID, Mode=TwoWay, Converter={StaticResource DictionaryConverter}, ConverterParameter='ProductDictionaries.CategoriesLookup' }"/> <dataControls:DataFormComboBoxField x:Name="cboSuppliers" FieldLabelContent="Supplier:" DisplayMemberPath="Value" Binding="{Binding SupplierID, Mode=TwoWay, Converter={StaticResource DictionaryConverter}, ConverterParameter='ProductDictionaries.SuppliersLookup' }" /> </dataControls:DataFormFieldGroup> <dataControls:DataFormFieldGroup Orientation="Horizontal"> <dataControls:DataFormCheckBoxField FieldLabelContent="Discontinued?" FieldLabelPosition="Left" Binding="{Binding Discontinued, Mode=TwoWay}" /> <dataControls:DataFormDateField FieldLabelPosition="Left" FieldLabelContent="Discontinued Date:" Binding="{Binding DiscontinuedDate, Mode=TwoWay}" SelectedDateFormat="Short" /> </dataControls:DataFormFieldGroup> </dataControls:DataForm.Fields> </dataControls:DataForm> </StackPanel> <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,5,0,5"> <Button x:Name="saveButton" Width="100" Height="30" Margin="8,4,0,5" Content="Submit Changes" IsEnabled="False" Click="submitButton_Click" ToolTipService.ToolTip="Submit all changes to the server"/> </StackPanel> </Grid> </StackPanel> </StackPanel> </StackPanel> </Border> </Grid>

If you’ve gone through some of the RIA walk-throughs and samples (highly recommended), there’s not very much new here. So I’ll direct your attention to the binding of the DataFormComboBoxField, cboCategories:

<dataControls:DataFormComboBoxField x:Name="cboCategories" 
              FieldLabelContent="Category:" DisplayMemberPath="Value" 
              Binding="{Binding CategoryID, Mode=TwoWay, 
              Converter={StaticResource DictionaryConverter},
              ConverterParameter='ProductDictionaries.CategoriesLookup' }"/>

What we will be doing here is binding to the CategoryID in the Products entity, and using a Dictionary Converter to manage the relationship between what is in Products and what it points to in Categories. To do this, I created a Dictionary class for all lookup dictionaries associated with Products (the thought being that you might choose to partition different sets of lookup data into difference Dictionaries) as:

public static class DictionaryCache
{
    public static ProductDictionaries ProductDictionaries { get; set; }
}

The actual ProductDictionaries object looks like this:

public class ProductDictionaries
{
    public Dictionary<int, string> CategoriesLookup { get; set; }
    public Dictionary<int, string> SuppliersLookup { get; set; }
}

Now, let’s get our context loaded up. Because I typically have a lot of lookup tables, I decided to implement a singleton Context that the entire application can reference. That looks like this (BusinessManager.cs):

public static class BusinessManager 
{
    private static NorthwindEFContext context = new NorthwindEFContext();

    public static NorthwindEFContext Context
    {
        get
        {
            return context;
        }
    }
}

Now in our code-behind, we can start to get our data loaded and bound. In MainPage.xaml.cs make sure you have the following using statements:

using System.Windows.Controls;
using System.Windows.Ria.Data;
using SL3ComboBoxDemo.Web;
using SL3ComboBoxDemo.Model;
using SL3ComboBoxDemo.Util;

Now, before the constructor, declare our data context and a bool useful for determining if we can skip some code execution once we’ve performed it once (due to the asynchronous nature of Silverlight data access):

private NorthwindEFContext Context = BusinessManager.Context;
private static bool formIsBound = false;

In the constructor, set up the following immediately after the InitializeComponent call:

dds.DomainContext = Context;
dataForm1.ItemEditEnded += 
new EventHandler<DataFormItemEditEndedEventArgs>(dataForm1_ItemEditEnded); pager1.PageIndexChanged +=
new EventHandler<EventArgs>(pager1_PageIndexChanged); this.Loaded += new RoutedEventHandler(MainPage_Loaded);

Down in MainPage_Loaded, we then wire up a Context.Loaded EventHandler and start loading data:

void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    Context.Loaded += new EventHandler<LoadedDataEventArgs>(Context_Loaded);
    LoadFromServer();
}

The reason I used a LoadFromServer() call is in case I wanted to wire up Isolated Storage at some point later (in fact, I do this in a LOB application I am building). LoadFromServer() hits the Context up for only Categories and Suppliers, since the Products are set to AutoLoad in the markup:

private void LoadFromServer()
{
    Context.LoadCategories();
    Context.LoadSuppliers();
}

When Context_Loaded fires, we have to decide what we have and what to do with it. I decided that here is where I wanted to populate my ProductDictionaries if I had all of the data that I needed (since Context_Loaded is fired at least once for each Entity loaded). The way I ensure I have what I need to proceed is to check the counts of all the Entities I am loading.

void Context_Loaded(object sender, System.Windows.Ria.Data.LoadedDataEventArgs e)
{
    if (Context.Products.Count > 0
            && Context.Categories.Count > 0
            && Context.Suppliers.Count > 0)
    {
        if (DictionaryCache.ProductDictionaries == null)
            DictionaryCache.ProductDictionaries = GetProductDictionaries();
        SetupComboBoxes();
    }
}

GetProductDictionaries() does some LinqToSQL magic with our loaded entities on the client side to populate our ProductDictionaries object:

public ProductDictionaries GetProductDictionaries()
{
    var productDictionaries = new ProductDictionaries();

    var categoryQuery =
        from c in Context.Categories
        orderby c.CategoryName
        select c;
    productDictionaries.CategoriesLookup = 
        categoryQuery.ToDictionary(c => c.CategoryID,
                                   c => c.CategoryName);
    var supplierQuery =
        from s in Context.Suppliers
        orderby s.CompanyName
        select s;
    productDictionaries.SuppliersLookup = 
        supplierQuery.ToDictionary(s => s.SupplierID,
                                   s => s.CompanyName);
    return productDictionaries;
}

Now for the final piece of magic. Because the DataFormComboBoxField is not visible to us via normal x:Name identity (even though stubborn me put one on each <g> – more as a note to self), we’ll have to iterate through the controls in the DataForm and find the one bound to the ID we want to find, so that we can set the ItemsSource of each Combo Box correctly. That method is in the Util folder as DataFormBinding.GetFieldByBindingPath(). Back in the MainPage, we return to SetupComboBoxes (here’s where that bool declared in the class comes in handy):

void SetupComboBoxes()
{
    if (!formIsBound)
    {
        if (Context.Categories.Count > 0)
        {
            DataFormComboBoxField cboCategories =
                DataFormBinding.GetFieldByBindingPath(dataForm1, "CategoryID") 
                as DataFormComboBoxField;
            if (cboCategories.ItemsSource == null)
            {
                cboCategories.ItemsSource = 
                    DictionaryCache.ProductDictionaries.CategoriesLookup;
            }
        }
        if (Context.Suppliers.Count > 0)
        {
            DataFormComboBoxField cboSuppliers =
                DataFormBinding.GetFieldByBindingPath(dataForm1, "SupplierID") 
                as DataFormComboBoxField;
            if (cboSuppliers.ItemsSource == null)
            {
                cboSuppliers.ItemsSource = 
                    DictionaryCache.ProductDictionaries.SuppliersLookup;
            }
        }
        if (Context.Products.Count > 0
            && Context.Categories.Count > 0
            && Context.Suppliers.Count > 0)
        {
            formIsBound = true;
SetupDataForm(); } }
else
SetupDataForm(); }

SetupDataForm does the final setting of current item/index setting on the DataGrid and DataForm. I did not use any server activity method to indicate server activity, but you can easily wrap this Activity Control around the DataGrid, and have an indication when the data is being fetched. You can, of course, add any styling or theming that you want. Again, the focus on this post was the data! And here’s what we have built:

image

Figure 2. SL3ComboBoxDemo in action

The first time you load the application, it may take a short while to load the data, as your SQL Server Express User Instance is created, but any sessions thereafter will be fairly fast. I did not implement complete code to allow additions or deletions of Products in order to keep this article as simple as possible, but there is already some plumbing in place in the sample code. And so, I leave that to you as an exercise, dear reader. However, you can certainly edit the Products to your heart’s content.

Wrapping Up

So, there you have it – a quick tour, but now supported by a complete code solution, of how to bind lookup data to combo boxes on Silverlight 3 DataForms. If you look closely into the sample code, you will also find implementations of some other tips I learned on the Silverlight Forums. And finally, if you see any areas where I could improve my approach, please do not hesitate to let me know. I hope this helps you in your Silverlight development efforts.

Bob Baker

P.S. I went to Orlando CodeCamp on March 28, 2009. Did you?

.Net RIA Services and Multi-table Joins

Why are we here?

On the off chance that you are developing a real-world application based on a normalized database that you’d like to develop using Silverlight 3 and .Net RIA Services, I have some good news. After thrashing about for several days trying to get a multiple table join to come back down the wire, I think I have it figured out, and so I wanted to share what I’d learned. This is not going to be one of those seriously abstract articles where the author has come up with something you’re not quite sure where you’d use it. This is (hopefully) going to be about ‘pay your bills’ code. Besides, I’m just not that advanced a developer ;-). So if, like me, you’re slogging along trying to use this fantastic new technology in the real world, perhaps you should read on.

The Model

We have a normalized database model consisting of Clients, Client tasks (called Dockets), Partners, Employees, Appointments, and so on. To support reliable data entry, we eliminate a lot of repetitive typing by using lookup tables to hold relatively static data (like postal codes, states, categories, etc.). Below is a snippet of the Entity Framework model that is relevant to this discussion.

 

image

Figure 1. Entity Framework Model fragment

Getting Data

The recently released Beta 1 of .Net RIA Services is pretty powerful right out of the box. It allows you to use a new syntax to include foreign key relations returning IQueryable or IEnumerable objects right to the client. For example, if we wanted to get Clients and their Contacts, we could write this method in the server-side Domain Data Service class:

public IQueryable<Clients> GetClientsAndContacts()
{
    return this.Context.Clients.Include("ClientContacts").OrderBy(c => c.ClientName);
}

Where this appears to break down is when you have a chain of relations, since the navigation properties not directly associated with the primary object to be fetched are not visible to it, and thus, it is no longer an object of the primary type to be fetched. From the walkthroughs and available documentation, you would think that you could simply chain relationships ad infinitum until your server begged for mercy (usually on its knees). But you can’t. From the model fragment above, you can see that Clients has no direct navigation property called ZipCodes. If, in fact, RIA Services will eventually be united under the umbrella of ADO.Net Data Services (Astoria), I am less confident than I used to be that what I am about to show you will work in that context.

So how do we get, for example, a complete mailing label for each client?

Extending .Net RIA Services Classes

From my participation in the Silverlight.net forums, I learned about extending the base methods that the Visual Studio 2008 Silverlight 3 Domain Service item template provides. So, if we want a new class for our hypothetical mailing label, it might look like this:

public partial class MailingLabel 
{
    [Key]
    public string ClientName { get; set; }
    public string Address1 { get; set; }
    public string Address2 { get; set; }
    public string City { get; set; }
    public string StateAbbrev { get; set; }
    public string ZipCode { get; set; }
    public string ZipPlus4 { get; set; }
}

We would write this class alongside the methods generated for us from the Domain Service item template that we pointed at an Entity Framework model.

It might also be a good idea (although not strictly necessary in this case) to write an equivalent metadata class for our new MailingLabel class, in case we decide later that we need databinding for it (say, to an ItemsControl for a report – hint, hint). Based on the established pattern, that would look like this: 

   // The MetadataTypeAttribute identifies MailingLabelMetadata as the class
    // that carries additional metadata for the MalingLabel class.
    [MetadataTypeAttribute(typeof(MailingLabel.MailingLabelMetadata))]
    public partial class MailingLabel
    {
#pragma warning disable 649 // temporarily disable compiler warnings about unassigned fields
        // This class allows you to attach custom attributes to properties
        // of the MailingLabel class.
        //
        // For example, the following marks the Xyz property as a
        // required field and specifies the format for valid values:
        //    [Required]
        //    [RegularExpression(“[A-Z][A-Za-z0-9]*”)]
        //    [StringLength(32)]
        //    public string Xyz;
        internal sealed class MailingLabelMetadata
        {
            // Metadata classes are not meant to be instantiated.
            private MailingLabelMetadata() {}
            [Bindable(true, BindingDirection.OneTime)]
            public string ClientName;
            public string Address1;
            public string Address2;
            public string City;
            public string StateAbbrev;
            public string ZipCode;
            public string ZipPlus4;
            public EntityState EntityState;
        }
#pragma warning restore 649 // re-enable compiler warnings about unassigned fields
    }

You can add [Include] , [Exclude],  and validation attributes to this class as indicated in the comments to your heart’s content.

To revisit the constraint that got us here, even though we’d love to be able to do something like this:

public IQueryable<Clients> GetMailingLabels()
{
    return this.Context.Clients
.Where(c => c.Label == true)
.Include("ClientContacts")
.Include("ZipCodes")
.Include("States")
.OrderBy(c => c.ClientName); }

we simply can’t. In fact, this method will never return asynchronously. Don’t ask. I thought perhaps I was delving too deep into the hierarchy for Entity Framework to handle, and that it was simply timing out. Strictly speaking, it was not. Essentially, the threads that were spun off in an attempt to perform the fetch gave up and exited. To it’s credit .Net RIA Services, made at least 3-4 attempts, each time with a new thread.

Linq & C# 3.0 to the Rescue

So I fired up LinqPad, and started writing standard Linq against my database until I got what I wanted:

from c in db.Clients
   where c.Label == true
orderby c.ClientName join cc in db.ClientContacts.Distinct() on c.ClientID equals cc.ClientID join z in db.ZipCodes on cc.ZipCodeID equals z.ZipCodeID join s in db.States on z.StateID equals s.StateID select new { c.ClientName, cc.Address1, cc.Address2, z.City, s.StateAbbrev, z.ZipCode, cc.ZipPlus4 };

It almost looks like pure traditional SQL, and it ran really fast through over 500+ clients with multiple contacts, and of course 50 states, as well as almost 50,000 zip codes. And hats off to the recent Linq Deep Dive series in ASP.Net Pro magazine alerting me to the huge performance variation in Linq queries without proper ordering of the various clauses.

So the central question remains of how to get this data into the MailingLabel class so that it can be brought over the wire to my Silverlight client, when it’s really returning an Anonymous Type? It turns out that C# 3.0’s Class Initializer feature is just what I needed. After a lot of questions on the forum and experimentation, here is the solution:

public List<MailingLabel> GetMailingLabels()
{
    var query =
        (from c in Context.Clients
         orderby (c.ClientName)
         where c.Label == true
         join cc in Context.ClientContacts.Distinct()
         on c.ClientID equals cc.Clients.ClientID
         join z in Context.ZipCodes
         on cc.ZipCodes.ZipCodeID equals z.ZipCodeID
         join s in Context.States
         on z.States.StateID equals s.StateID
         select new MailingLabel 
{ ClientName=c.ClientName, Address1=cc.Address1, Address2=cc.Address2, City=z.City, StateAbbrev=s.StateAbbrev, ZipCode=z.ZipCode, ZipPlus4=cc.ZipPlus4 }).ToList(); return query; }

Notice that I had to insert navigation properties at several points in the relation chain (e.g., cc.ZipCodes.ZipCodeID equals z.ZipCodeID). I believe that’s an artifact of using EF, but don’t know for sure. You may also be wondering why I did not return an IQueryable or an IEnumerable. It turned out to be just too hard to force the compiler to agree with me, so after an hour of trying to coerce it, I gave in to the reliable List<T>. And I was able to coerce the Anonymous Type returned by the query into my MailingLabel class by using a C# 3.0 Initializer. Very handy, that.

The Payoff

Back on the client, we can now fire off a call to our context’s LoadMailingLabels() method, and in the Loaded event handler, we can do the wonderful things we’d like to do with any strongly typed object – iteration and databinding! The only down side to extending .Net RIA Service classes using EF like this is that if we ever need to make any schema changes, we will need to make a back-up of our modified files and break out our dusty diff tool to re-insert all of our modifications. They tell me that either Oleg or one of his T4 cohorts are looking at tooling for this problem, since IdeaBlade already supports non-destructive schema changes in their products.

I am just beginning to consider all the possibilities for projection, aggregates, and other reporting-required rowsets that a line of business application would normally require, and that I can now bring across the wire as strongly typed objects with this simple coding pattern. If I can write it in Linq, I can have it on the (Silverlight 3) client! Remember how hard remoting was? Stay tuned.

Hope this helps.

Bob Baker

P.S. I went to Orlando CodeCamp on March 28, 2009. Did you?

Silverlight 3 DataForm and DomainDataSource Binding

Because all Silverlight data access is Asynchronous, care must be taken to be sure that all of your data has come down the pipe before letting a user loose on the presentation and manipulation of that data. I am currently building a medium sized Line of Business (LOB) application on spec based on the Silverlight 3 Beta and the new .Net RIA Services. These new releases from Microsoft have some rather amazing features that have allowed me to prototype this application in a matter of days over the last several weeks since CTP 9 was released to those of us fortunate to be under NDA for early releases.

There are several lookup tables that I use in my application to reduce the amount of typing a user must do when filling in the details of the primary domain entities in this application (see my last post for details on one solution to the lookup ComboBox data binding issue). IN my application, each of these lookup entities gets a DataForm to allow maintenance by an individual with the proper credentials. In building my DataForms for each entity, I noticed that often, the navigation elements (see screen caps below) were not enabled once the form had rendered. What? I had set an event to handle the Loaded event for both my page and also for my DomainDataSource’s DataContext, or at least I thought I had.

image

What I was seeing…

image

The way it’s supposed to look…

When I would fire up one of these forms, I would see that the navigation elements were grayed out, and sometimes no data would appear in the form’s entry elements. I played with the various DataForm properties, and the binding syntax and/or markup, etc. to no avail.

It turns out that since I was using the markup approach for my DomainDataSource (with x:Name of ‘dds’), I was not handling the LoadedData event for that object. Furthermore, because that handler is responding to an Asynchronous event, I realized that I had to use the built-in Dispatcher.BeginInvoke to properly update the UI. And lastly, based on a response to a question I had on the now-defunct Alexandria forum at the Silverlight site, I knew that a DataForm’s CurrentIndex is usually –1 (no data) when it is rendered, so that was the key setting I had to make in my handler. Note that I’m using a Lambda expression for my anonymous delegate in that handler. Here’s some code that I hope will save you several hours of scratching your head.

XAML Markup snippet:

<ods:DomainDataSource x:Name="dds" 
          LoadMethodName="LoadBusinessCategories"
          AutoLoad="True"
          LoadSize="20">
    <ods:DomainDataSource.DomainContext>
            <ds:MyBusiness/>
    </ods:DomainDataSource.DomainContext>
</ods:DomainDataSource>
<dataControls:DataForm x:Name="dataForm1"  Margin="5,5,5,0" Width="400" Height="150"                          
                         AutoEdit="False" AutoCommit="True"    
                         VerticalAlignment="Top"       
                         CommandButtonsVisibility="All"
                         Header="Business Categories"        
                         ScrollViewer.VerticalScrollBarVisibility="Auto" 
                         CanUserAddItems="True" CanUserDeleteItems="True"
                         AutoGenerateFields="False" 
                         IsEnabled="True" IsReadOnly="False" IsHitTestVisible="True">
     <dataControls:DataForm.ItemsSource>
         <Binding ElementName="dds" Path="Data"/>
      </dataControls:DataForm.ItemsSource>
      <dataControls:DataForm.Fields>
            <dataControls:DataFormTextField FieldLabelContent="Short Name: " 
                                    Binding="{Binding ShortName, Mode=TwoWay }" />
            <dataControls:DataFormTextField FieldLabelContent="Description: " 
                                    Binding="{Binding Description, Mode=TwoWay }" />
      </dataControls:DataForm.Fields>
</dataControls:DataForm>

Code-behind snippet:

public partial class BusinessCategories : Page
{
    public BusinessCategories()
    {
        InitializeComponent();
        dds.LoadedData += 
            new EventHandler<System.Windows.Ria.Data.LoadedDataEventArgs>(dds_LoadedData);
        dds.SubmittedChanges += 
            new EventHandler<SubmittedChangesEventArgs>(dds_SubmittedChanges);
    }

    void dds_LoadedData(object sender, LoadedDataEventArgs e)
    {
        if (!dds.DataView.IsEmpty)
        {
            Dispatcher.BeginInvoke(() =>
            {
                dataForm1.CurrentIndex = 0;
            }
            );
        }
        else
            dds.Load();
    }

    void dds_SubmittedChanges(object sender, SubmittedChangesEventArgs e)
    {
        if (e.Error != null)
        {
            DisplayError(e);
        }
    }

    // Executes when the user navigates to this page.
    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
    }

    private void submitButton_Click(object sender, RoutedEventArgs e)
    {
        if (dds.HasChanges)
        {
            dataForm1.CommitItemEdit();
            dds.SubmitChanges();
        }
    }

    private void DisplayError(System.Windows.Ria.Data.SubmittedChangesEventArgs e)
    {
        ChildWindow ErrorWin = new ErrorWindow(e.Error);
        ErrorWin.Show();
        ErrorWin.Focus();
    }
}

Hope this helps.

Bob Baker

P.S. I went to Orlando CodeCamp on March 28, 2009. Did you?

Silverlight 3, .Net RIA Services, and common lookup data

One of the first things I learned in developing User Interfaces (UI) over the last 30 years was to eliminate as much user typing as possible. One way to do that is to have common elements available as selections from lists (combo boxes, radio buttons, etc.). Many of these lists should also be maintainable on the user system, so as needs change, the items can be updated.

I have been working with the new Silverlight 3 Community Technology Preview (CTP) bits since late last year, and have struggled with implementing the link between a parent database table and it’s related  items stored either in one or more lookup tables, or in in-memory collections and lists.

Here’s a simple example. Imagine there is a database table containing Clients or customers of a professional services firm. Each of the Partners ‘owns’ one or more clients, in that the Partner probably brought that Client into the firm, and manages the relationship with that Client. So, in a line-of-business (LOB) application dealing with these Clients, one would like to have a combo box containing a list of the Partners, and connecting them to each Client by their unique database table identifier, but displaying the Partner human-readable name to the user. This was unbelievably easy in Microsoft Access, and relatively easy in Visual Basic 6 and .Net Windows Forms. It is not as easy in Windows Presentation Foundation (WPF) or it’s sibling Silverlight frameworks. One of the real benefits of Silverlight is the rich UI that can be developed to present data, but the deployment story is fantastic.

I spent some time on the Microsoft Silverlight.net Forums, and decided to pose a question about this UI pattern.After several days, a few folks piped in with their suggestions, but one approach in particular looked promising. I have to give a lot of credit to Luke Longley here for much of this work, but our back and forth dialog effectively solved the problem, and within a few days, it was the number one active thread on the private forum dedicated to what was then called the Alexandria framework. Luke doesn’t currently have a blog, so we agreed that I would post this when the Non-Disclosure Agreement (NDA) we both had with Microsoft was lifted. With the release to the web of Silverlight 3 Beta at MIX 2009 on Tuesday, that NDA is no longer in effect, and as thousands of people start to play with the bits (and that private Alexandria forum is now closed), I can now share what I/we learned. There won’t be a complete solution provided here (because I simply do not have the time to build one), but the code and markup examples provided here should prove adequate if you’ve worked at all with the walkthroughs provided with the beta bits. If you need to know what you need to get started with Silverlight 3, go to the Silverlight 3 link above.

So to set the stage: we have started a new Silverlight Navigation Project in Visual Studio 2008, we have added a Microsoft Entity Framework item to the server project created by this template that points to the database we are using, and that contains Client and Partner tables. So we now have Clients and Partners entities in our model. We add a DataGrid, a DataForm and a DomainDataSource to a Silverlight Page. The Xaml markup might look like this (I’ll assume you can discern where you need to add your own namespace references, etc.):

<StackPanel>
    <StackPanel>
        <ods:DomainDataSource x:Name="dds" 
              LoadMethodName="LoadClients"
              AutoLoad="True"
              LoadSize="64">
            <ods:DomainDataSource.DomainContext>
            <ds:DocketsBusiness/>
            </ods:DomainDataSource.DomainContext>
        </ods:DomainDataSource>
        <StackPanel Orientation="Horizontal" Margin="7,7,0,0">
            <StackPanel>
                <datagrid:DataGrid x:Name="dataGrid1" Width="315" Height="410" HorizontalAlignment="Left"
AutoGenerateColumns="False"> <datagrid:DataGrid.ItemsSource> <Binding ElementName="dds" Path="Data"/> </datagrid:DataGrid.ItemsSource> <datagrid:DataGrid.Columns> <datagrid:DataGridTextColumn Header="Client Name" Binding="{Binding ClientName}" /> </datagrid:DataGrid.Columns> </datagrid:DataGrid> <dataControls:DataPager x:Name="pager1" Width="315" HorizontalAlignment="Left" PageSize="16"> <dataControls:DataPager.Source> <Binding ElementName="dds" Path="Data"/> </dataControls:DataPager.Source> </dataControls:DataPager> </StackPanel> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*" /> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel Grid.Row="0" Margin="3,1,0,0"> <dataControls:DataForm x:Name="dataForm1" Margin="5,0,0,0" Width="480" MinHeight="390" AutoEdit="False" AutoCommit="True" VerticalAlignment="Top" CommandButtonsVisibility="All" Header="Client Details" ScrollViewer.VerticalScrollBarVisibility="Visible" CurrentItem="{Binding ElementName=dataGrid1, Path=SelectedItem}" AutoGenerateFields="False" CanUserAddItems="True" CanUserDeleteItems="True"> <dataControls:DataForm.Fields> <dataControls:DataFormFieldGroup Orientation="Vertical" > <dataControls:DataFormTextField FieldLabelContent="Client Name: "
Binding="{Binding ClientName, Mode=TwoWay }" /> <dataControls:DataFormTextField FieldLabelContent="Nick Name: "
Binding="{Binding Nickname, Mode=TwoWay }" /> </dataControls:DataFormFieldGroup> <dataControls:DataFormSeparator/> <dataControls:DataFormFieldGroup Orientation="Horizontal"> <dataControls:DataFormComboBoxField x:Name="cboPartners"
FieldLabelContent="Partner:" DisplayMemberPath="Description"
Binding="{Binding PartnerID, Mode=TwoWay }"/> <dataControls:DataFormComboBoxField x:Name="cboForms"
FieldLabelContent="Main Tax Form:" DisplayMemberPath="Description"
Binding="{Binding MainFormID, Mode=TwoWay }"/> </dataControls:DataFormFieldGroup> </dataControls:DataForm.Fields> </dataControls:DataForm> </StackPanel> <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0,12,0,0"> <Button x:Name="saveButton" Width="100" Height="30" Margin="14,0,0,0"
Content="Submit Changes" Click="submitButton_Click" Visibility="Collapsed"/> </StackPanel> </Grid> </StackPanel> </StackPanel> </StackPanel>

I have removed a number of fields from this form, but from the few I have left, you may notice a second DataFormComboBoxField. The pattern I am presenting here is exactly the same. Because of a Dependency Property bug in Silverlight, the UI elements inside a DataForm are not visible as identifiable objects in the Framework (i.e., x:Name is not a Dependency Property!). There are other properties we can check, and you should be able to see the resulting code smell, but it works! We will basically iterate through the FrameworkElements in the UI tree, and find our combo boxes so that we may bind them properly (i.e., set their ItemsSource). The below C# code is what Luke Longley came up with. Simple save this as a separate class in your Silverlight project and reference it in your code-behind (or ViewModel if you’ve gotten that far). 

public static class DataFormBinding
{
    public static DataFormBoundField GetFieldByBindingPath(DataForm dataForm, string bindingPath)
    {
        Stack<DataFormField> fieldStack = new Stack<DataFormField>();
        foreach (DataFormField field in dataForm.Fields)
        {
            fieldStack.Push(field);
        }
        while (fieldStack.Count > 0)
        {
            DataFormField curField = fieldStack.Pop();
            DataFormBoundField boundField = curField as DataFormBoundField;

            if (boundField != null &&
                boundField.Binding != null &&
                boundField.Binding.Path != null &&
                boundField.Binding.Path.Path == bindingPath)
            {
                return boundField;
            }
            else
            {
                DataFormFieldGroup fieldGroup = curField as DataFormFieldGroup;

                if (fieldGroup != null)
                {
                    foreach (DataFormField field in fieldGroup.Fields)
                    {
                        fieldStack.Push(field);
                    }
                }
            }
        }
        return null;
    }
}

Of course, you’ll need to add all the appropriate namespaces (including your server project’s namespace, etc.) to the code above. Another of the side-effect we’ll need to account for is the connection between the Foreign Keys. For this, we will need some Value Converters for our Unique Identifiers. I am currently using one Value Converter pair for each Combo Box/Lookup table. There is obviously some refactoring to be done with Generics here for sure. Here is an example for the Partners Entity Combo Box binding:

public class IDToPartnerConverter : IValueConverter
{
    public IEnumerable PartnerList
    {
        get;
        set;
    }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null)
        {
            int id = (int)value;
            foreach (Partners partner in this.PartnerList)
            {
                if (id == partner.PartnerID)
                {
                    return partner;
                }
            }
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        Partners partner = value as Partners;
        if (partner != null)
        {
            return partner.PartnerID;
        }
        return null;
    }
}

Now let’s do some binding! In the code-behind for the above page, we need to set up a Page.Loaded event, and then Load all of our entities, and set a Loaded event on our DomainDataSource (in my case, _DocketsBusiness), so that we can then bind the results to the various UI elements.

Add something like this in the ctor for the page:

this.Loaded += new RoutedEventHandler(ClientsPage_Loaded);

Add the ClientsPage_Loaded handler:

void ClientsPage_Loaded(object sender, RoutedEventArgs e)
{            
    LoadFromServer();
    _DocketsBusiness.Loaded += new EventHandler<System.Windows.Ria.Data.LoadedDataEventArgs>(_DocketsBusiness_Loaded);
}

Add the LoadFromServer() method:

private void LoadFromServer()
{
    _DocketsBusiness.LoadPartners();
    // other lookup entities removed for brevity
}

Finally, add the DomainDataSource Loaded handler:

void _DocketsBusiness_Loaded(object sender, System.Windows.Ria.Data.LoadedDataEventArgs e)
{
  if (_DocketsBusiness.Partners.Count > 0)
  {
      // who cut the cheese? 
DataFormComboBoxField cboPartners = DataFormBinding.GetFieldByBindingPath(dataForm1, "PartnerID")
as DataFormComboBoxField; if (cboPartners.ItemsSource == null) { IDToPartnerConverter converter = new IDToPartnerConverter(); converter.PartnerList = _DocketsBusiness.Partners; cboPartners.Binding = new Binding("PartnerID") { Mode = BindingMode.TwoWay, Converter = converter }; cboPartners.ItemsSource = _DocketsBusiness.Partners; } } }

And, like magic, we have bound lookup data! Here’s a little screen shot showing the Partner assigned to 3DTek Information Systems in a ComboBox:

SL3Lookup

I’ll be working on some refactoring as well as performance improvements as I understand more about Silverlight 3 and .Net RIA Services. Some of my lookup tables have a lot of items, but load time is not significant, and UI Combo Box dropdown time is immediate. I am sure there are limits (think ALL US Zip Codes <g>).

Again, I apologize for not providing a complete solution to play with. Drop me an email if you get stuck, and I’ll see what I can do.

 

Bob Baker

P.S. I’m going to Orlando CodeCamp on March 28, 2009. Are you?

It’s great to finally solve a Blue Screen of Death (BSOD)

I've been using VMWare Workstation for over 8 years, and I love how it allows me to setup different operating systems on my workstation for evaluation, test, special connectivity, or software installation and operational testing without any risk to my base OS installation. I am currently running Vista Ultimate x64 with VMWare Workstation 6.5.

Recently, after upgrading to the latest build of VMWare Workstation, I started experiencing computer freezes when I would turn on the monitor in the morning. I would have to reset my workstation, and 9 times out of 10, one of my RAID 0 arrays would need rebuilding, which required me to boot into Safe Mode, allow the rebuild to complete, and then reboot normally. This time lost was starting to mount, and I was getting extremely tired of it. Late last week, upon re-booting, I got a so-called Blue Screen of Death (BSOD) indicating an INTERNAL_POWER_ERROR (0xA0).  And I couldn’t even boot into Safe Mode, despite repeated tries with some intervening reversions to BIOS defaults. I wasn’t able to find a lot of good information (via a web search) on this BSOD, until I happened on an article on Scott Hanselman’s Blog. Hmm, he says VMWare might be to blame. And it turns out it’s a power transition issue with the USB connection that Bluetooth wireless keyboards and/or mice use via their dongle. I have a Microsoft Bluetooth Wireless Elite Keyboard & Mouse, and with unplugging the Bluetooth dongle or uninstalling VMWare being the only workarounds, I was in a bind. Heck, I couldn’t even find the supposed offending driver, VMKbd.sys on my system! After a lot of searching and testing, I think I found a solution buried deep down in one of the VMWare Community forums postings. Here’s the essential part of that forum post located in the middle of this page:

1. Open Regedit.

2. Navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class{4D36E96B-E325-11CE-BFC1-08002BE10318}.

Here you will find an "UpperFilters" param of type REG_MULTI_SZ with a value like: "kbdclass vmkbd". If you open it up to modify it, you will see one driver name per line; notice that vmkbd by default is the last in the list. Edit (Cut and Paste) that parameter by putting the vmkbd entry to be the first in the list.

Note that in some cases "vmkbd" can be named differently: vmkbd2, vmkbd3 - it does not matter. It is probably because you have installed a newer version of VMWare over the old one or something like that, and the previous driver was not able to be delete it from the registry. Remember to re-check this registry entry the next time you upgrade VMWare.

3. Reboot and you should no longer have any BSOD’s related to this issue.

I’ve had no problems re-booting after a critical out-of-band security patch and some Windows Updates, no freezes have greeted me upon arising, and I’ve had the chance to actually get some work done this week. Hope this helps.

Bob Baker

iPod Envy? Cook your Windows Mobile 6.1!

I've been using Windows Mobile phones for a few years on the Cingular and AT&T networks. I currently own an AT&T Tilt, which is actually an HTC 8925 (or TyTN II, or Kaiser) for those of you who care about such things. It was loaded with a second release of Windows Mobile 6 when I got it last March. My previous phone was a Cingular 8525 (which became AT&T overnight it seemed), and it came loaded with Windows Mobile 5. Since I'm the curious sort, I soon discovered that the XDA Developer Community was THE place to find out everything about PDA's and SmartPhones -- from where to get the best carrying case or audio adapter, to more esoteric subjects, like how these devices actually work at the hardware level. There are sections for every single PDA/SmartPhone you've ever heard of, with active participation by developers and power users of each.

After a lot of reading on XDA's Forum and Wiki sites, I learned that these devices run on a firmware image, called a ROM (or Read-Only Memory), that is developed by the manufacturer (in this case, in partnership with Microsoft) and loaded by the carrier, and that the carrier's own special programs are loaded from another area, called the Extended ROM. I also learned about the special firmware that allows these devices to actually communicate, called the Radio, about the bootloader, and a ton of other tips about customizing your phone to the way you work. I guess I became a tweak addict. Hello, my name is Bob, and...

It wasn't long before I discovered that many people were unsatisfied with the pre-loaded operating system and features delivered on their phone, and were customizing their phones with not only new features developed by, and offered for free to, the XDA community, but were also making entirely new ROM images, and flashing them -- tech speak for updating your phone with new firmware.There are some very bright people in this world, and I suspect a large percentage of them are in the electronic engineering field. I was simply amazed at the abilities of some of these folks, with handles like CusTel, kypher, and pof, who were simply brilliant in their ability to reverse engineer devices, extract or decompose ROM images, and understand and explain firmware code. They did this to make tools that could be used to 'cook' new ROMs -- tech speak for building a new ROM image from component parts -- as well as allow new Radio's to be loaded as the manufacturer's developed them. The frequency with which new ROMs and Radios appeared on the site made me start to suspect that the sources these folks were using were being seeded to the community by the manufacturers and carriers as a sort of Alpha test cycle, or that some participants in the community actually silently worked for the manufacturers or carriers. That said, please note that there is no pirated software, or warez, available at XDA-Developers. In fact, posting any can get you permanently banned from the site.

As I sat there with my Windows Mobile 5 8525 long after Microsoft had released Windows Mobile 6, and waiting for AT&T to get around to releasing an update, I started to think, "Why wait for AT&T? I think I can flash my phone with one of the WM6 ROMs being cooked at XDA specifically for the 8525." And, even though I eventually waited for AT&T to release their own update, I ended up flashing my phone with a different ROM -- one that was a later build of Windows Mobile 6, did not have any of the additional software that AT&T preloads (and that I simply did not find useful), and as it turned out, one that fit the way I use my phone to a 'T'.

After nearly two years of rough and tumble service, that phone woke up one morning last March with a white screen. I could get to it remotely while docked with a great product I bought, called SOTI Pocket Controller, but its display was finished. Using Pocket Controller, I was able to run some backup software, and otherwise get my phone ready for a warranty return to HTC. I was told that would take 3-6 weeks, and if you're like me, your cell phone is like a lifeline. So, off I went to the AT&T store, thinking I was going to get a throwaway flip phone to tide me over. But at the store, I met the Tilt, and, it was love at first site. This phone has a 400MHz processor, 256MB of ROM, 128MB of RAM, 65K of colors on a QVGA screen, takes micro xHD storage cards, has a 3 megapixel camera, wireless-G, Bluetooth, and a GPS, and when you slide the screen away to reveal the QWERTY keyboard, the screen tilts up at a readable angle (the 8525 screen just slid out). It also came with Windows Mobile 6 loaded, and with the promise that Windows Mobile 6.1 would be available "any day now". Where have I heard that before? But I was given upgrade/renewal pricing, and that was that.

So I got my new Tilt home, and immediately did a hard reset to clear it to factory state. This time, I did a soft reset just after completing the initial screen alignment. This bypassed the AT&T custom software load, and gave me a basic WM6 phone with the essentials (Office Mobile 6 being one of them). Of course, I learned that I could do this at XDA.

I immediately switched my preferences at XDA from the 8525 to the 8925, and as I read the wiki and forum topics for it, I discovered that some challenges lay ahead. The display driver had problems (with a Class Action law suit to boot), there was no Flash for the camera, and flashing this phone with a new ROM or Radio was a little more complicated than it was for the 8525. So I continued to read the XDA Kaiser wiki and forums (highly recommended), and gather my courage.

A few weeks ago, my Tilt's battery died evidently in the middle of an important registry write, because it started to act very strangely and would not boot correctly. Suspecting a corrupted registry, and coincidently, the day the new AT&T WM6.1 upgrade was released, I downloaded a few tools and the AT&T ROM, went through a few very important preliminary steps, and flashed my Tilt. I did the soft reset thing, and played with this ROM for a day or so. Not being overly impressed, I ventured into custom ROMs for the Kaiser, and after trying several different ROMs and Radios, I finally found a combination of ROM, Radio, applications, and skinning that is just a joy to use. Again, due to the sheer genius of the members of the XDA community, the HTC Diamond User Interface, called TouchFlo 3D, was extracted and configured to run on the Kaiser as a 2D variation, called Manilla 2D. It is cooked into the ROM I am currently using, called HyperDragon III Pro. Here are a couple of screenshots of my current setup, grabbed using Pocket Controller.

Home Weather Program Launcher Start Menu

You simply drag your finger over the items along the bottom bar, the Icon appears with the background dimmed, and when you release your finger or stylus, you're on that screen. There is a nice Home tab with the clock, alarms, call history, and next calendar appointment. There are also tabs for Contacts (with pictures of your fave's right from your mobile contacts), Messaging, Mail, Internet, Photos and Video, Music, Weather, Map Search, Settings, and a Program Launcher. The soft menus change contextually for each tab, and the Start Menu has large MRU icons at the top of a large-sized menu. I have skinned the basic Manilla 2D interface with a skin called Feng Shui, and added a custom Weather tab skin. It is extremely fast. Note that at the time of this writing, Manilla 2D has only been ported for HTC devices.

If you like using your Windows Mobile phone, but want it to work better, check out XDA Developers.

Bob Baker

Technorati Tags: ,,,

Some projects are just plain fun...

Back in January when I started work in earnest on the web site project I have just completed for On-the-Go Foodservice Magazine, I had to build a special development box to use because the Ektron CMS400.Net Content Management System (CMS) we had selected for this project would not install properly on Windows Vista. That's all I run here on the real hardware. It was a bit of a frustrating start in some ways. But it proved to be a minor annoyance, as I was able to satisfy every single Phase I Launch Requirement (and then some) with this CMS, ASP.Net, the afore-mentioned development workstation, and a few creative moments by your's truly. I also had more of a supporting cast of characters than I usually do contributing to the success of this project in both the graphics and web designer (CSS) fields. Special thanks must go out to Ingo Chao, an extremely gifted CSS designer, who seems to know every browser strength and weakness off the top of his head. As a result of his contribution, the site renders almost exactly the same in every CSS 2 browser in the wild. We even have print and mobile device support. I also have to thank a few special folks at Ektron (you know who you are) who back-door accelerated my requests for support on certain key 'features', knowing that we were trying to push the envelope with their product, and that the site would have some real visibility after launch.

The site launched last week (3.19.08 in the EDT afternoon to be exact) with the fewest hiccups I've ever experienced with a site launch. While there were the usual last minute panic attacks, and anxiety over things possibly forgotten or yet-to-do, I have to say it went off pretty much without a hitch. It even involved a domain transfer of the existing placeholder home page, and that only took a few hours to propagate.

What was more interesting to me was that in my 15 years of building dynamic web sites (yes, you read correctly: 15 years) on a number of different platforms, I had never hosted any of my project sites with a hosting provider on a shared server. Enter ServerSide. They came recommended from Ektron, and proved to be more than competent in working out the various configuration changes that had to be made remotely to allow the site to come up in their environment. This included helping me understand the dreaded 'Medium Trust' environment, which had a potential showstopper impact because I used the popular and awesome SubSonic OR/M for some data access I needed to do outside of the CMS. MSDN articles didn't hurt either. Anyway, ServerSide is relatively small in the world of hosting providers, but their pipe is huge and they have experience with CMS400.Net. What that also means is that the person on the other end of the support line is almost always the same person, and so you can count on not having to recite all of the background information each time you send that support request email.

But where was I? What was the subject of this post? Oh yeah, fun. Sometimes you're working along slogging through requirements and getting nowhere, and you wish you were in the Bahamas. Sometimes, on-time payment is an issue (but that's the subject of another, future post). But sometimes, you manage to work on a project that you just check off one requirement after another, the client is fully engaged and happy to have you on the team, money is not an issue (although our budget was very tight), and it all just comes together. This was one such project. For a small team of 2 full-time (customer and me) and 5 part-time (other principals, graphics, web design, etc.), I am simply in awe of what we were able to accomplish in a little over two months of intense effort. So, where's the fun in all of this you may ask? All I can say is, if you don't 'get it', you might want to consider a line of work different from web software development. If my ramblings have been too obscure, perhaps this will enlighten: the fun is in the designing, the building, the launch, and the results, all produced with the help of a great team. Check it out: On-the-Go Foodservice Magazine.

Bob Baker

Internet Explorer 8 (thank goodness it's only) Beta 1

Microsoft has released Beta 1 of Internet Explorer 8, and tonight I installed it on a VMWare Virtual Machine to test it. If you've at all attempted to conform to W3C standards, as well as achieve some Search Engine Optimization by employing Cascading Style Sheets (CSS), and especially CSS Level 2) instead of good old HTML tables, you may either be a) pleasantly surprised, or b) unpleasantly staring at the prospect of many hours of hand-editing CSS to repair to your site(s). I develop sites for a living, and I prefer a). Fortunately, Visual Studio 2008 has Intellisense for CSS style sheets.

But it turns out that there is a quick (or temporary) fix. If you have all those special CSS selectors living in your iefixes.css file (or whatever you call it!), you can continue to use them by employing a single meta tag in all of your pages (this is especially nice if you use just a few master pages for a site, and can thus place the this tag in just a few places). At any rate, add this meta tag to your <head> section:

<meta http-equiv="X-UA-Compatible" content="IE=7" />

May your time be spent productively.

Update: Here are some additional results of testing. One of my more complex layouts totally broke with the above meta tag in place. So I tried the IE8 Internet Explorer 7 Emulation button, and after restarting IE8, the site came up like it does in IE7 (and other browsers). Fine, but how am I going to convince users to hit that button? There's a built-in user training issue for Microsoft! OK, what about complete IE8 standards mode? So I set the above meta tag to IE=8, and only two elements in my complex layout broke, and not catastrophically at that. So, maybe this new world won't be so bad. But I can also see the possibility of some more conditional style sheet loading, i.e., <!--[if gte IE 8]>. Sheesh, when will it ever end? As one respected observer noted, "Hardcoding a reference to a specific browser as a necessary part of the page’s markup feels plain dirty."

Bob Baker