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.

Sunday, September 28, 2008

Baking the Abstract Factory Pattern

The abstract factory pattern is a common fixture of well designed code.  As useful as it is, it can be an annoying pattern because the scaffolding to implementation ratio is quite high.  It also breaks up code that most of the time should be together.  Other patterns that reach this level of usage often benefit from being baked into the language framework, so why not this pattern.

Let's look at a fairly basic implementation:

public interface ButtonFactory
{
Button CreateButton();
Button CreateButton(Control parent);
}

public interface Button
{
void Draw();
}

public class WinButtonFactory : ButtonFactory
{
public Button CreateButton() { return new WinButton(); }
public Button CreateButton(Control parent) { return new WinButton(parent); }
}

public class WinButton : Button
{
internal WinButton() { ... implementation ... }
internal WinButton() { ... implementation ... }

public void Draw() { ... implementation ... }
}

public class SampleUser
{
public void UseFactory()
{
ButtonFactory factory = new WinButtonFactory();
Button parent = factory.Create();
Button child = factory.Create(parent);
}
}


This is okay, but if we had a little syntax help:



public interface Button
{
Button();
Button(Control parent);
void Draw();
}

public class WinButton : Button
{
public WinButton() { ... implementation ... }
public WinButton() { ... implementation ... }

public void Draw() { ... implementation ... }
}

public class SampleUser
{
public void UseFactory()
{
Factory<Button> factory = WinButton.GetFactory<Button>();
Button parent = factory;
Button child = factory(parent);
}
}



That's a fair bit more succinct, and it also allows the definition of the "Create" to reside within the interface, making it much more obvious to consumers of the API the relationship between the factory and the interface.  The same is true for the implementation, where it's no longer necessary to either provide a workaround to the visibility issues that arise from having object initialization in a separate class.



Some might object on the basis that the use of the factory pattern extends beyond the example above, but those uses can still be accommodated:



public class ColoredButtonFactory : Factory<Button>
{
private Color _color;
private Factory<Button> _factory;
public ColoredButtonFactory(Color color, ButtonFactory factory);
{
_color = color;
_factory = factory;
}

public Button()
{
Button button = _factory();
button.Color = _color;
return button;
}
}



Which is equivalent to this implementation without language level factory support:



public class ColoredButtonFactory : ButtonFactory
{
private Color _color;
private ButtonFactory _factory;
public ColoredButtonFactory(Color color, ButtonFactory factory);
{
_color = color;
_factory = factory;
}

public Button CreateButton()
{
Button button = factory.CreateButton();
button.Color = _color;
return button;
}
}



An alternative (with pluses and minuses) the language level factory support would allow for is:



public class ColoredButtonFactory<TButton> : Factory<TButton>
where TButton : Button
{
private Color _color;
public ColoredButtonFactory(Color color);
{
_color = color;
}

public TButton()
{
TButton button = new TButton();
button.Color = _color;
return button;
}
}

Wednesday, September 24, 2008

deSleeper Beta 0.5

Another update to deSleeper finished up today.  I've been trying to make it a bit more user friendly.  I should have finished a bootstrapper but I got distracted by some other wants...  For example a much better way to get your credentials in and a way for you to wake up a system via host name (i.e. mypc.mycompaniesinternaldomainname.com). 

The catch to this second feature is that for most PCs it's only possible to resolve a host name to a MAC address while the computer is actually on.  What deSleeper does is store a cache of hostname/MAC address pairs so that it can do that resolution when the computer is off, but to make that work it has to search at least once to populate the cache.  So if you have your target machine on, send a wake up request with the client that will cache the hostname.  Then you can use the hostname with target off.  Since this is a new feature, might want to make sure you have the MAC address available just in case though.

Saturday, September 13, 2008

The end of the light bulb joke

Question: In 2020, how many kids will it take to change a light?

 

Answer: None, LED lights last 20 years so they'll be adults before one burns out.

Monday, September 08, 2008

deSleeper Beta 2 Released

I posted a new build of deSleeper to CodePlex last night.  I was interested in learning a bit more about WPF so I used some of that time to touch up the UI and neaten things up under the covers a bit.

deSleeper Wake Up Tab

Also, feature wise, I've added a tab to help you configure the "target" machine's network card driver to accept wake up requests.  You can do the same things through device manager and control panel, but this is a bit more convenient.  One note though, to support Wake-on-Lan requests from all power states (such as hibernate and power off) you still need to make sure the BIOS is properly configured.  The network card driver usually can't do anything more than make sure you can come out of a sleep state.

image

I still have a more plans for deSleeper, such as a distributed mesh system (this should allow you to take by hostname or IP, rather than MAC address), but I thought I'd mention 1E WakeUp I ran across recently that while it may cost a bit does appear to tackle the same issues as deSleeper.  If your a network admin with lots of computers to configure, I won't blame you for choosing 1E over deSleeper.  As long as you get your office setup to allow those hard working PCs have a good nights sleep, I'll be happy.

Should the U.S. drill "everywhere"?

My purist thinking side says, no, the places where the opportunity to drill remains restricted are a combination of costly to recover, dangerous to recover, and not very large anyhow.  I'd rather see the money spent on building solar panels, wind farms, battery cars, hybrid cars or even cellulosic biofuel than on oil platforms, deep water drilling, and all the complicated machinery necessary to keep the environmental effects of drilling obnoxious rather than disastrous.

My political compromising side says, drilling is dumb, but it's only a little bit dumb.  It's not as dumb as letting solar and wind tax credits expire, it's not as dumb as subsidizing the oil companies, it's not as dumb as driving an SUV, and it's certainly not as dumb as not investing in public transportation.  I also realize that a significant number of people not only fail to realize how dumb those other acts are, but think that drilling is the most brilliant idea ever conceived.  So I recognize an opportunity here, an opportunity to trade-in on the totally out of proportion enthusiasm drilling inspires in the opponents of public transportation and renewable energy.  It's not perfect, but that's what politics and compromise are.

My dark, sarcastic side goes further.  That part thinks, well maybe it's really important to allow the drilling, because if we do, it won't be more than 6 months later before the proponents of drilling realize how stupid they were to think it was the solution to the problem.  Sure, you have politicians who support drilling who say things like "drilling will not solve all of America's energy problems - as if we all didn't know that already", but among their supporters and colleagues individuals who really believe that is the solution, and that somehow it will take effect tomorrow too.  I'd like to burst their bubble just for spite.  Let em try and drill there way out and see the look on their faces when they finally realize 6 months to a year later, hey, it's gonna take 10 years, cost a lot and even then be no more than a drop in the bucket.