Thursday, October 23, 2008

Asynchronous WPF

WPF like WinForms has a UI thread and enforces that UI properties cannot be modified by threads other than the UI thread.  There are many reasons for this design choice, but the reality is that if you want a responsive user interface you will need to make sure that any significant work is performed upon a background thread.  What this post is about, is some of the ways you can use built in WPF patterns to develop an properly asynchronous UI, and some areas that need extension.

Data-binding is one area that WPF provides built in asynchronous patterns.  Your first friend for data-binding is ObjectDataProvider.  This nifty class sometimes confuses developers who wonder why it is necessary if WPF can bind to any data object because some examples show it wrapping an object.  But where ObjectDataProvider shines is in providing an asynchronously loaded object to WPF binding's.  For example, if your UI needed to bind to properties of the system's NetworkInterface objects, you could do something similar to:

<Page ...
xmlns:NetworkInformation="clr-namespace:System.Net.NetworkInformation;assembly=System" ...>


...



  <Page.Resources>
<ObjectDataProvider
x:Key="_interfaces"
IsAsynchronous="True"
ObjectType="NetworkInformation:NetworkInterface"
MethodName="GetAllNetworkInterfaces"/>
</Page.Resources>



This succinct little bit will call GetAllNetworkInterfaces asynchronously.  In addition, any parts of your UI that create bindings to _interfaces (through {Binding Source={StaticResource _interfaces} ...}) will initially appear empty (actually it will display the binding's FallbackValue) but update after the asynchronous operation completes.



WPF also provides a property to every binding called IsAsync.  Hopefully you will have less use for this property than ObjectDataProvider because property access should not be slow.  I also prefer that data load all at once, or at least in chunks.



Surprisingly, after providing good patterns for Binding, WPF seems to neglect the more common need of asynchronous commands.  To be fair, they are less simple because it's fairly common for them to be dependent on the current setting of UI properties.  When commands are not dependent upon UI properties they can be very simple.  In many ways, this is the optimal usage for commands in general because the whole CommandParameter system is a bit clunky.



WPF does support BackgroundWorker, which can be used to create a basic AsyncCommand.



    public abstract class AsyncCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public event EventHandler RunWorkerStarting;
public event RunWorkerCompletedEventHandler RunWorkerCompleted;

public abstract string Text { get; }
private bool _isExecuting;
public bool IsExecuting
{
get { return _isExecuting; }
private set
{
_isExecuting = value;
if (CanExecuteChanged != null)
CanExecuteChanged(this, EventArgs.Empty);
}
}

protected abstract void OnExecute(object parameter);

public void Execute(object parameter)
{
try
{
onRunWorkerStarting();

var worker = new BackgroundWorker();
worker.DoWork += ((sender, e) => OnExecute(e.Argument));
worker.RunWorkerCompleted += ((sender, e) => onRunWorkerCompleted(e));
worker.RunWorkerAsync(parameter);
}
catch (Exception ex)
{
onRunWorkerCompleted(new RunWorkerCompletedEventArgs(null, ex, true));
}
}

private void onRunWorkerStarting()
{
IsExecuting = true;
if (RunWorkerStarting != null)
RunWorkerStarting(this, EventArgs.Empty);
}

private void onRunWorkerCompleted(RunWorkerCompletedEventArgs e)
{
IsExecuting = false;
if (RunWorkerCompleted != null)
RunWorkerCompleted(this, e);
}

public virtual bool CanExecute(object parameter)
{
return !IsExecuting;
}
}



From this point, you can override CanExecute and OnExectute to provide the actual body of your command.  While an asynchronous operation is executing the button/checkbox (any inheritor of ButtonBase) will be disabled.



If you need to pass a parameter in you can do so with CommandParameter, but one caution is in order.  There is some advice that for passing multiple to CommandParameter you should pass a complex object in an instance field, or resource that parts of your form bind to.  While this works fine for synchronous invocation it could be problematic for asynchronous because the bindings can alter the object while your asynchronous code is executing.



What I do when I need to pass in multiple values is to use a IMultiValueConverter and MultiBinding.



<Button.CommandParameter>
<MultiBinding Converter="{StaticResource InstallServiceParameterConverter}">
<MultiBinding.Bindings>
<Binding ElementName="_this" Path="IsInstalled"/>
<Binding ElementName="localURI" Path="Text"/>
<Binding ElementName="meshURI" Path="Text"/>
<Binding ElementName="registerWithMesh" Path="IsChecked"/>
</MultiBinding.Bindings>
</MultiBinding>
</Button.CommandParameter>



It is a bit clunky, especially with the converter, but it's also safe since your Command will be passed a newly created object.  I'm still looking for better solutions, but so far this seems the closest to ideal.

Thursday, October 16, 2008

Two Forms of Confidence

What's the difference between confidence and meglomania?  I don't think it's so much a difference in the degree of confidence, but a difference in the perception of what a capable individual can accomplish.  If a person is very smart, then they are confident if they believes the same thing.  But to be meglomaniacal, doesn't need to believe they are inhumanly smart, they just need to believe that a very smart person is capable of fixing everything with a single thought.  They need to believe that perfection really is possible.

In a sense, to be meglomaniacal, a person must be dumb to the reality of life, to the wisdom that mistakes happen, even to the best of us.

Wednesday, October 15, 2008

deSleeper 0.8

Another version of deSleeper was posted to CodePlex last night.  The important part is it fixes the networking tab so that XP users can now easily setup their network card for WakeOnLan functions without knowing needing to be a Windows expert.  Also added the ability to set the sleep timer from the same place.  That was a fair bit more work since I wrapped up the Power Management APIs to do so.  But now I have a nice clean .NET interface for power management which hides the behind the scene changes from XP to Vista. 

I'll post more about that later, but if you're considering writing a .NET app that deals with setting up power management you may want to check it out.  Since deSleeper is Apache, it's free to reuse with some mild attribution.