Off Track

Ok – I’ve managed to get a little side-tracked – there are just so many things rummaging around in my head at the moment.

This one popped into (virtual) reality the other day – a WPF based application notification area (status panel). The idea is that the panel interacts with a validation engine which governs all validation on a given page. It would also be related to a WPF equivalent of ErrorProvider. The WinForms ErrorProvider was kinda cool for doing simple demos but in real apps I always thought it was a bit of a joke. I’m aiming here to produce “notifications” that have associated metadata – primary text, secondary text (the long version), actions (e.g. intellisense options, corrective measures), locators (e.g. click to focus on the bad control) etc.

Based on previous experience most of this is really easy – its the rules validation engine that gets tricky – especially when table validation is required (e.g. grids).

 StatusPanel v0.1

I Command Thee – Exception?

Ok – so I’m reading through WPF Unleashed and I finish reading the chapter on the various deployment types which also covers the inbuilt page navigation framework. Now this is something that I’m very interested in having attempted the feat myself a few times. So I decide its time to stop reading, roll up the sleeves and give it a try.

To start with I try something like this:

The startup XAML defines we’re using a NavigationWindow with the startup page being HomePage.xaml.

<NavigationWindow x:Class="WpfParameterPassing.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300"
    Source="HomePage.xaml">
</NavigationWindow>

The HomePage contains a Button and a TextBox. The idea is that the Button triggers the navigation passing the content of the TextBox to the called page.

<Page x:Class=”WpfParameterPassing.HomePage”
   xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
   xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
   xmlns:local=”clr-namespace:WpfParameterPassing”
   Title=”HomePage”
   x:Name=”_this”>
   <StackPanel>
        <Button Content=”Make Selection” Click =”Button_Click”/>
        <TextBox x:Name=”selectionTextBox”/>
  </StackPanel>
</
Page>

The page to call is defined as a PageFunction which means it allows a value to be returned. The type of this return value is defined by the x:TypeArguments attribute, in this case a string. The called form just has an Ok and Cancel button, together with a TextBox that is populated with the input parameter and which is used to populate the return value.

<PageFunction x:Class="WpfParameterPassing.SelectFunction"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    x:TypeArguments="sys:String"
    Title="SelectFunction"
    RemoveFromJournal="True">
    <StackPanel>
        <WrapPanel>
            <Label Content="Choice to return:"/>
            <TextBox x:Name="choice" HorizontalAlignment="Stretch" Width="150"/>
        </WrapPanel>
        <WrapPanel>
            <Button x:Name="okButton" IsDefault ="True" Content="_OK" 
HorizontalAlignment
="Right" Click
="Button_Click" /> <Button x:Name="cancelButton" IsCancel="True" Content="_Cancel"
HorizontalAlignment
="Right" Click
="cancelButton_Click" /> </WrapPanel> </StackPanel> </PageFunction>

A little bit of code behind for the HomePage is used to trigger the navigation and to subscribe to the Return event so we can update the TextBox with the value returned from the called page.

    public partial class HomePage : Page
    {
public HomePage()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
SelectFunction nextPage = new SelectFunction(selectionTextBox.Text);
nextPage.Return += new ReturnEventHandler<string>(nextPage_Return);
this.NavigationService.Navigate(nextPage);
}
private void nextPage_Return(object sender, ReturnEventArgs<string> e)
{
if (!string.IsNullOrEmpty(e.Result))
selectionTextBox.Text = e.Result;
}
}

Some code behind on the PageFunction derived class is used to wire up the Ok and Cancel buttons. The constructor overload is then used to allow the input parameters to be passed. I like the idea of using constructors to pass the parameters – neat. [Its a shame parameterized constructors can’t be used to initialize objects in XAML – but that’s a whole other story.]

    public partial class SelectFunction : PageFunction<string>
{
public SelectFunction()
{
InitializeComponent();
}
public SelectFunction(string previousSelection) : this()
{
choice.Text = previousSelection;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
OnReturn(new ReturnEventArgs<string>(choice.Text));
}
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
OnReturn(new ReturnEventArgs<string>());
}
}

So – put all this together and it works as expected. Enter a value on the first page (HomePage) – click the button and the value is transferred to the second page (SelectFunction) where it can be modified and returned via the return result.

The next step is to get rid of all that code behind that binds HomePage to SelectFunction. What better way to do this than with a Command? This is where things began to get fuzzy. If I want to create my own command what should it derive from? After a few false starts attempting to derive from RoutedCommand etc. I decide not to derive from anything and just implement ICommand myself.

    public class SelectCommand : ICommand, INotifyPropertyChanged
    {
private string _selection;
public SelectCommand()
{
//Text = "Select Choice";
        }
public Page CallingPage { get; set; }
public string Selection
{
get
{ return _selection; }
set
{
_selection = value;
OnPropertyChanged("Selection");
}
}
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}

        #region ICommand Members
public bool CanExecute(object parameter)
{
return true;
}
public event EventHandler CanExecuteChanged;
public void Execute(object parameter)
{
if (CallingPage == null)
CallingPage = (Page) parameter;
if (CallingPage == null)
throw new InvalidOperationException(
"CallingPage cannot be null when invoking the Execute method."); SelectFunction nextPage = new SelectFunction(Selection); nextPage.Return += new ReturnEventHandler<string>(nextPage_Return); CallingPage.NavigationService.Navigate(nextPage); }
#endregion private void nextPage_Return(object sender, ReturnEventArgs<string> e) { if (!string.IsNullOrEmpty(e.Result)) Selection = e.Result; } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion }

Get rid of all the code behind in HomePage and redefine the Button and TextBox to instantiate a new command and a bit of binding to glue it together.

       <Button Content=”Make Selection” CommandParameter=”{Binding ElementName=_this}”>
           <Button.Command>
               <local:SelectCommand x:Name=”selectCommand”/>
           </Button.Command>
       </Button>
       <TextBox x:Name=”selectionTextBox” Text=”{Binding ElementName=selectCommand, Path=Selection}”/>

Now that’s much better. My button is set to execute a command when its activated (Clicked) and the command controls the page navigation and parameter passing for me. We get the result back into the page simply by binding our output field (in this case selectionTextBox) to the Selection property of the command (essentially the output parameter).

But does it work… well no. It generates this little beauty:

WPF Exception

Hmm… so is this a bug – or have I somehow hooked into some interop? If I remove the event handler subscription to the Return event everything works fine – except of course I don’t get my value .

I even tried Dispatching back to the UI thread in case it was a weird threading related issue – no luck. Interestingly when I first attempted to create my command by inheriting from RoutedCommand the button was disabled. This was despite the fact that my CanExecute method is hard-coded to return true. Its at this point I think I need to go back to the books – I’m obviously missing something.

___________________________________

And the answer is given here.

To work around the limitation I need to make the callback for the return an instance method of the calling form. Hmm… easy enough passing as a callback delegate in C# but how to declare that in XAML? Not too sure about the merits of this limitation – means putting code in the HomePage code behind again.

        public void Returned(object sender, ReturnEventArgs<string> e)
{
if (!string.IsNullOrEmpty(e.Result))
selectionTextBox.Text = e.Result;
}

Oh – and a bit of reading into RoutedUICommand makes things clearer as to why inheriting from it got me nowhere Maybe it can help me with the problem above though?

Windows Home Server RTM

Just setup my Windows Home Server machine to the RTM version (from RC). Performed a manual backup using a single drive (320Gb) which does an amazing job of backing up my main workstation and the home theatre PC [this isn’t a full backup given the workstation alone has over a terabyte of disk – but its most of the important stuff]. However, I then included the second drive into the storage “array” and the backups started failing again. This was the same problem I had with the RC – basically the server machine just reboots halfway through a backup. It seems like a hardware issue given how sudden the reboot is (there is nothing untoward reported in any of the event logs) – but as to which device is failing…

The most obvious candidate would be the second hard drive – a 400Gb Seagate drive. Thing is I’ve run all of Seagate’s own diagnostics over this drive (SeaTools) and it comes up fine every time. Maybe its the SATA controller – but that’s an on-board device which also is operating the primary drive. Maybe its the Intel gigabit on-board LAN controller – but why does it only fail when the second drive is operational. The Seagate drive is marginally faster than the Western Digital – but both drives are less than 6 months old. The S.M.A.R.T. diagnostics for both drives also look pretty normal – with both showing near-perfect health.

Another annoying problem is that I can’t seem to install the Windows Home Server Connector software on my sons PC. It was all working fine under the RC but for some reason refuses to un-install correctly and hence can’t install the update. Frustrating – I was about to resort to some sysinternals tools to track exactly where it was getting stuck – but figured its probably time to just rebuild the machine anyway given its a very old box whose OS has probably hasn’t been re-installed for 6 years or so. Was thinking of upgrading it from XP SP2 to Vista but my 4 ½ year old son has some nostalgic feelings towards XP and isn’t ready for the leap (stumble?) to Vista.

As for the Windows Home Server box itself… dunno – I checked out some motherboard and PSU pricing tonight. Its currently running a crusty old P4 2.8GHz and given its going to be running 24 hours a day I figured I might opt for a more energy efficient choice with a silent PSU to boot. The home theatre PC is silent from any distance greater than 30cm and uses a CoreDuo mobile chip. Seems like a Home Server box should probably be running the same sort of hardware… which leads me to wonder why I need both a Home Server and Home Theatre PC – both of which run 24/7. Oh well – I think its a common sentiment that hopefully the Home Server team will address in the next version.

______________

Slowly but steadily working my way through the WPF book. There are some huge similarities between a lot of what’s in WPF and that I’ve been working on (in my day job) over the last 3 years. This isn’t surprising given that we based a lot of our work on some early XAML samples from Microsoft (and others). I’m already imagining how it would be possible to build an infrastructure framework over the top of WPF to more easily create business applications. So should I dig into Acropolis or just go ahead and build my own?

Extension Methods

This is one feature in C# 3.0 that I’ve been really looking forward to for a long time.

It gives us the ability to extend classes that we didn’t author and can’t inherit. One of the key benefits I see in this is the ability to extend primitive .NET classes such as String, Int32 etc. These classes can’t be inherited so there hasn’t previously been a neat way of extending them.

The following example adds a rather simplistic method to the System.Int32 type – IsPrime which simply returns true or false depending upon whether the integer is a prime number. [Ok – I know the method is half done and performs poorly – its meant to explain extension methods not prime number evaluation algorithms].

    public static class ExtensionTest
    {
public static bool IsPrime(this int value)
{
for (int denominator = 2; denominator <= value / 2; denominator++)
{
if (value % denominator == 0)
return false;
}
return true;
}
}
    public class Test
    {
public void TestMethod()
{
for (int i = 0; i < 100; i++)
{
if (i.IsPrime())
System.Diagnostics.Debug.Write(i + ", ");
}
}
}

What I really love about the .NET implementation is the way in which extension methods are understood by the IDE intellisense and how you bring the extension methods into scope by importing (using) the namespace. This means the you only see the relevant methods based on the current namespace scope.

The intellisense displays a little arrow against the standard method icon to indicate that the method in question has been extended by a static extension method. Very cool.

 Intellisense drop down showing IsPrime extension method

Little to Report

I haven’t made any progress for the last week on my WPF attempt at PhotoPlay for a bunch of reasons relating to work and home commitments. I’m pretty disappointed about this – I had hoped to have got further. The good news is that I received an e-mail on Monday from www.fishpond.com.au indicating that my book has been shipped and I should expect it by the end of the week.

I must admit I almost resorted to Amazon when purchasing this book – but then at the last minute I figured there must be a local alternative with quicker shipping. The local alternative was fractionally cheaper although I believe they still import the book from their overseas distributors, so I doubt the delivery would have been much different. I’m glad I bothered to look around though because I’m an anti-fan of Amazon – I know the rest of the world disagrees but I just find the entire Amazon web experience to be dismal. Their search never seems to work – even when you know they have the book, and their ordering/check-out process is frustrating.

Hmm… Ok – I had a bad day at work today – vent over…