It’s basically Dances with Wolves in space, and it has
- Spaceships
- Aliens
- Boobs
- Giant robots
- Soldiers
- Horses
- Dragons
- Energy weapons
- Exotic wildlife
- Exciting chase scenes
- Lots of explosions
- State of the art CG
- Noble savages
- Elves (the noble savages are tall and slender with pointy ears, and run around communing with nature)
- A soppy doomed-love story
- Resurrection themes
All the good-guys are attractive and smart. All of the annoying characters get killed.
BusyIndicator is your friend
Let me begin by stating the obvious: if you bind your UI to one or more DDSs (DomainDataSources) then when the UI renders it will fetch values from those DDSs. Now let me ask you a question: if you hover the mouse over a grid, will that cause data to be fetched? You can guess that it does, from the mere fact that I’ve posed the question. But how can this be?
With the default stylesheet, and indeed most stylesheets, the DataGrid and other widgets are thoroughly littered with triggers that respond to mouse activity. This of course is what makes Silverlight the out-of-box multimedia extravaganza that it is, and we wouldn’t have it any other way. But it does mean that the mere proximity of a mouse pointer triggers rendering, which in turn fetches data. If the DDS involved isn’t ready this can produce unsightly exceptions that quite spoil the UX.
So what’s a girl to do?
Use a BusyIndicator, that’s what.
I can’t think of a scenario in which you wouldn’t add a BusyIndicator as the outermost widget in your Visual Tree. If you don’t do binding then it’s harmless, and if you should plonk a data-bound widget on your page or window then it’s there waiting to monitor IsBusy on any and every DDS that becomes its child, preventing user interaction until they become ready.
This disabling of UI until all the DDSs are ready sorts out a variety of issues:
- It no longer matters in what order DDSs become ready, because combo-boxes and other Selector derivatives won’t try to fetch from lookups till they render.
- Mouse activity no longer triggers UI activity cascading into premature fetches.
What happened to AutoBind?
AutoBind, for the great unwashed, is or rather was a Boolean property which when set to True would cause the BusyIndicator to find all its child DDSs and behave as though IsBusy were bound to the OR of all the DDS IsBusy properties, so any DSS becoming busy would lock the UI.
Sound good? According to this blog post, AutoBind was removed for performance reasons.
A workaround
Here’s how to efficiently provide the same behaviour using very little code.
First, synthesise a value from your various DDSs by creating a page property.
172 public bool IsBusy
173 {
174 get
175 {
176 return assetDomainDataSource.IsBusy
177 || assetGroupDomainDataSource.IsBusy
178 || contactDomainDataSource.IsBusy
179 || deviceDomainDataSource.IsBusy
180 || employeeDomainDataSource.IsBusy
181 || employeeGroupDomainDataSource.IsBusy;
182 }
183 }
Notice that each DDS already has an event handler for its _LoadedData event. You don’t need five identical handlers. Delete all of them and paste this instead.
156 private void LoadingData(object sender, LoadingDataEventArgs e)
157 {
158 busyIndicator1.IsBusy = IsBusy;
159 }
160
161 private void LoadedData(object sender, LoadedDataEventArgs e)
162 {
163 busyIndicator1.IsBusy = IsBusy;
164 textBoxSearchTerm.Focus();
165 if (e.HasError)
166 {
167 System.Windows.MessageBox.Show(e.Error.ToString(), "Load Error", System.Windows.MessageBoxButton.OK);
168 e.MarkErrorAsHandled();
169 }
170 }
Now go through your XAML and fix up your DDSs so they refer to the two handlers you just pasted in. The quickest way to do this is to use Edit/Replace with wildcards like this:
I suggest you also gather all your RIA declarations together, and put them in load dependency order. This is not strictly necessary, but it’s easier to check whether you have everything when the code is orderly.
If you try to run this it will probably barf on this line of code.
164 textBoxSearchTerm.Focus();
Your page probably doesn’t contain a TextBox named textBoxSearchTerm. I left this in to point out that if there’s a control you’d like to focus when the data finishes updating then this is a pretty good spot to do the deed. Just remove the whole line if you don’t want to interfere with focus.
How it works
Whenever a DDS starts loading data, the page IsBusy property will return true. With subsequent load starts this property will continue to return true. When a DDS finishes loading, the page IsBusy will only return false if none of the DDSs are busy, so the BusyIndicator will remain visible until the last DDS finishes loading – exactly the desired behaviour, completely event driven and with less code than the designer generates.
I’d like to see the designer do this automatically, but I doubt the VS team would consider it. Perhaps someone with experience creating Visual Studio Addins might help.
CopySourceAsHtml is a Visual Studio Add-in originally from JTLeigh and Associates, now available from Codeplex. Although testing is not complete it does seem to work with the beta of VS2010, and a patched MSI is available from http://copysourceashtml.codeplex.com/SourceControl/PatchList.aspx
However, Copy As HTML is conspicuously absent from the context menu for the XAML editor. To correct this, follow these steps:
- Right-click on a toolbar and choose Customize…
- Select the Commands tab.
- Select the Context menu radio button. This will enable a combobox.
- From the combobox, select Editor Context Menus| XAML Editor. This will show the items in that context menu.
- Scroll down and select Copy.
- Click the Add Command… button. This will open the Add Command dialog.
- Select Addins from the list of categories. This will show the list of commands available from add-ins, which should contain four items from JTLeigh.
- Select JTLeigh.Tools.Development.CopySourceAsHtml.Connect.CopyNow and click the OK button. This will cause CopyNow to appear just above Copy in the context menu but for some reason it will end up just before Run…
- You can also click the Keyboard… button and set up a keyboard shortcut.
- Click the Close button.
2D map
2D map view
2D view
3D map
3D map view
3D view
Add favourite
Add to favourites
Avoid roadblock
Brightness down
Brightness up
Calculate alternative
Calculate an alternative route
Calculate original
Calculate the original route
Call
Call back
Call home
Clear route
Continue itinerary
Correct map error
Current location
Day view
Daytime view
Decrease brightness
Decrease volume
Increase brightness
Increase volume
Map error
Mark as favourite
Mark map error
Mark safety camera
Minimise delays
Minimise traffic delays
Navigate home
Navigate to a city centre
Navigate to a favourite
Navigate to a postcode
Navigate to a recent destination
Navigate to an address
Navigate to home
Navigate to the nearest camping ground
Navigate to the nearest campsite
Navigate to the nearest car park
Navigate to the nearest car repair service
Navigate to the nearest cash dispenser
Navigate to the nearest cash machine
Navigate to the nearest dentist
Navigate to the nearest doctor
Navigate to the nearest hospital
Navigate to the nearest hotel
Navigate to the nearest parking garage
Navigate to the nearest petrol station
Navigate to the nearest pharmacy
Navigate to the nearest police station
Navigate to the nearest post office
Navigate to the nearest railway station
Navigate to the nearest rest area
Navigate to the nearest restaurant
Navigate to the nearest tourist information office
Navigate to the next itinerary destination
Night view
Nighttime view
Phone
Phone back
Phone home
Read aloud traffic info
Read aloud traffic information
Read traffic info
Read traffic information
Recalculate original
Recalculate the original route
Redial
Repeat instruction
Report safety camera
Safety camera
Sound off
Sound on
Start itinerary
Travel via a city centre
Travel via a favourite
Travel via a postcode
Travel via a recent destination
Travel via an address
Travel via home
Travel via the nearest camping ground
Travel via the nearest campsite
Travel via the nearest car park
Travel via the nearest car repair service
Travel via the nearest cash dispenser
Travel via the nearest cash machine
Travel via the nearest dentist
Travel via the nearest doctor
Travel via the nearest hospital
Travel via the nearest hotel
Travel via the nearest parking garage
Travel via the nearest petrol station
Travel via the nearest pharmacy
Travel via the nearest police station
Travel via the nearest post office
Travel via the nearest railway station
Travel via the nearest rest area
Travel via the nearest restaurant
Travel via the nearest tourist information office
Turn brightness down
Turn brightness up
Turn down brightness
Turn down volume
Turn off sound
Turn on sound
Turn sound off
Turn sound on
Turn up brightness
Turn up volume
Turn volume down
Turn volume up
Use day colours
Use night colours
Volume down
Volume up
Weather report
What is the weather?
Where am I?
Zoom in
Zoom out