My Lack of Responsive Web Design

My Lack of Responsive Web Design by rasx
My Lack of Responsive Web Design, a photo by rasx on Flickr.

I took this last week at the Apple Store in Century City. This is my homie’s site I’m designing, megafunk.com, running on the latest Apple iPad. You can see that I’m not yet using CSS media queries and other Responsive Web Design techniques.

My Three WCF Paths to Silverlight Data Access

Flippantly, here they are:

  • One: Silverlight-enabled WCF Service (backing View Model collections with ObservableCollection<T> by default)
  • Two: WCF Data Service (OData, backing View Model collections with DataServiceCollection<T>)
  • Three: Domain Service Class (RIA Services, backing View Model collections with LoadOperation<T>)

ServiceReferences.ClientConfig Is Useless in a XAP That Is Loaded by Another XAP.

My Songhay.Silverlight.ApplicationLoader compiles into an 8KB XAP file and is designed to load a bigger XAP file—which in turn uses MEF to load even bigger XAP files. One of these MEF-composed XAP files may contain a Service Reference, which, by default, generates ServiceReferences.ClientConfig. This file is designed to be used by the initial XAP declared in the HTML markup used to call Silverlight. My initial XAP is only 8KB and has no room for one or more Service Reference entries.

My way around this issue is to replicate the ServiceReferences.ClientConfig declarations imperatively. I have written an extension method to System.Windows.Application that accomplishes this:

public static BasicHttpBinaryBinding GetServiceClientBinding(this Application app)
{
    var mode = app.Host.Source.Scheme.Equals("https",
        StringComparison.InvariantCultureIgnoreCase) ?
        BasicHttpSecurityMode.Transport : BasicHttpSecurityMode.None;
    var binding = new BasicHttpBinaryBinding(mode);
    binding.MaxReceivedMessageSize = int.MaxValue;
    binding.MaxBufferSize = int.MaxValue;
    return binding;
}

For more details, see “Silverlight ServiceReferences.ClientConfig Alternatives” by Manish Dalal. Notice the my extension method returns a binary HTTP binding—Silverlight requires this more payload-efficient binding, which is the chief characteristic of a Silverlight-enabled WCF service.

IEditableObject Moves CRUD Eventing into the View Model

Controls like the DataForm use IEditableObject by convention, defining three methods BeginEdit, CancelEdit and EndEdit. The “begin” method is an opportunity to cache the instance implementing IEditableObject such that the “cancel” method can be used to restore data from this cache. The “end” method passes the instance implementing IEditableObject to the data layer.

Based on my current level of experience with this IEditableObject pattern, I am recklessly confident that my “end” method will not need to distinguish between Insert and Update. This suggests that I am rather foolish and/or I am setting a default value for the primary key associated with my instance implementing IEditableObject—like this:

[Display(Name = "Primary Key", Order = 0)]
[Key, Editable(false)]
public int? PrimaryKey
{
    get { return this.GetPrimaryKey(ref this._key); }
    set
    {
        this._key = value;
        base.RaisePropertyChanged("PrimaryKey");
    }
}

My private method GetPrimaryKey() passes the key field by reference and should be able to derive a valid key for the real-world underlying database. In fact, it can actually perform an Insert operation and have an “empty” record persisted before the user begins an edit session. This technique strongly suggests that the “cancel” method in the IEditableObject contract needs a cleanup procedure to ensure that the underlying database is not littered with “empty” records. I may need to study how more experienced developers address these issues.

What I do notice is that there appears to be no way to use IEditableObject with Delete operations. I assume that one would have to fall back on control eventing to handle any ceremony around deletes. The DataForm, for example, has a DeletingItem event, described by Tim Heuer in “Silverlight DataForm and confirming deleting an item.” Another DataForm event to consider is the EditEnded event, covered by Dino Esposito in “The DataForm Control in Silverlight 3—Revisited.”

My Scroll-into-View Strategy for the DataGrid

As of this writing this is my scroll-into-view strategy for the DataGrid:

this.DataGridOne.SelectionChanged += (s, args) =>
{
    if(this.DataGridOne.SelectedIndex == this._previousSelectedIndex) return;
    this._previousSelectedIndex = this.DataGridOne.SelectedIndex;
    this.DataGridOne.ScrollIntoView(this.DataGridOne.SelectedItem,
        this.DataGridOne.Columns[0]);
};

This approach requires declaring an x:Name on the DataGrid.

PagedCollectionView Swallows Collections Whole!

As of this writing, I know of only ways to implement the classic Master-Detail relationship between, say, the DataGrid and DataForm: with a PagedCollectionView and with the simpler CollectionViewSource. Both of these types implement ICollectionView (for details, see the 2008 article “ICollectionView explained”).

Because the PagedCollectionView supports client-side paging (and the DataPager), I prefer the CollectionViewSource (however, when server-side paging is in effect the CollectionViewSource might be useful when a more lightweight design is required). With the PagedCollectionView, the initial problem for me was getting synchronization to work between the Master control and the Detail control—the ObservableCollection<T> was not working out of the box. However, passing an instance of ObservableCollection<T> into the constructor of PagedCollectionView did the trick!

DataServiceCollection<T> is not “Blendable”

Because DataServiceCollection<T> has a dependency on some data-service “context,” DataServiceCollection<T> is not “Blendable” because mocking up design-time data is non-trivial (it may require a live, local OData service always running). However, because DataServiceCollection<T> is a subclass of ObservableCollection<T>, the recommendation here is to use ObservableCollection<T> in View Models.

My First XAML Data-Driven UI Recipe

Before XAML in particular and .NET in general, my typical data-driven UI “recipe” was to build on a Tab Control—usually just a bunch of forms in Tabs. The Tab aesthetic is directly connected to the “classic” desktop metaphor—directly coming from Xerox PARC. Next to the desktop there are filing cabinets—and in a drawer of the file cabinets are folders—folders with Tabs.

With the release of Windows 8, Microsoft reinforces what Apple has already started: a move away from the 1920s “modern” office space to the ancient world of the laminar tablet. In the same way the human eye jumps from one space on the surface of stone bas relief to another, our eye can see the flat panel display change in response to our touch. This flat panel aesthetic expressed in XAML leads me to these controls:

  • The DockPanel will allow the ‘root’ panel display to be subdivided into smaller panels and provide dynamic flow resizing (via LastChildFill="True").
  • The Frame will usually be the “last child” of the DockPanel and provide the means to let the eye “jump” from one interactive display to another.
  • The ItemsControl with a WrapPanel template loaded in the Frame takes advantage of the flow resizing literally making the layout of items flexible.

XAML

This four-control approach is not meant to be a Microsoft-only solution. This approach actually comes from Web design (with display: inline-block) and should be replicated in, say, Adobe Flex. The Web influence on this approach can also be seen through the use of the Frame element because it leads to the Page Navigation controls clearly mimicking the loading of HTML pages.