Looking back at WPF/Silverlight/WinRT

Last week I had to write a small WPF application, and I was surprised how hard it is to get WPF right. By “right” I mean not just getting the code to work, but to write easily maintainable code I won’t feel ashamed of later. I haven’t being programming in WPF for about a year. A year is not long enough to lose touch, but long enough to get some perspective. While I was in the thick of it, I did not realize how ridiculous some things really are.

Of course, WPF is virtually dead, so its problems may not really matter, but WPF’s alleged successor “Modern UI” a.k.a. “Metro” a.k.a “WinRT” inherited most of WPF’s baggage. So, whenever I say “WPF” it really means “WPF, Silverlight, Metro and all other XAML-based technologies”. In fact, WPF successors made some problems worse, e.g. by excluding MarkupExtension.

WPF problem number one is that it is verbose. You have to write too much code to achieve simple things. Verbosity in WPF comes in multiple flavors:

  • XAML is verbose.
  • NotifyPropertyChanged is verbose and repetitive.
  • Value converters are verbose.
  • Dependency properties are verbose.
  • Attached properties are outright scary.

WPF problem number two is lack of consistent programming model. Putting business logic in views leads to mixing it with presentation, and your data binding looks awkward. Putting business logic in view models leads to ridiculous questions like “how do I handle double click”, “how do I open a new window from my view model”, or “how do I set focus to a control from my view model”. Any way you do it, it is either complex, creates unwanted dependencies, or both.

XAML is Verbose

It is amazing how little attention WPF authors put to the expressive power of the language. E.g., consider this grid definition:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinition>
    <Label Grid.Row="0">Foo</Label>
    <TextBox Grid.Row='1" TextWrapping="Wrap" AcceptsReturn="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" />
    <Button Grid.Row="2" HorizontalAlignment="Center" Width="200">Submit</Buton>
</Grid>

Who came up with the idea of enumerating rows in a separate section and then referring to them by number? Whose idea was it to give HorizontalScrollBarVisibility attribute a 29-character name? With some effort this definition could be simplified to

<Grid>
   <Row><Label>Foo</Label></Row>
   <Row Height="*"><TextArea /></Row>
   <Row><Button HAlign="Center" Width="200"/>Submit</Button></Row>
</Grid>

If we abandoned XML, which is by definition verbose, we could even get something Python-like:

Grid
    Label "Foo"
    Row Height="*" TextArea
    Button HAlign="Center" "Submit"

None of that happened. Of course, there are tools that allow you to create XAML visually, but they tend to suck, and the resulting XAML is even more verbose than the one written by hand.

WPF properties are verbose

NotifyPropertyChanged is another code-bloating monster. In WPF, each view model property has to raise PropertyChanged event when it is updated. This sounds innocuous enough, but in practice instead of

public int MyProperty { get; set; }

You get

public int MyProperty
{
    get { return _myProperty; }
    set { _myProperty = value; RaisePropertyChanged("MyProperty"); }
}
private int _myProperty;

Ouch. Double ouch, because this has to be repeated for every property in every view model. There are multiple solutions to that problem, from proxy classes a-la nHibernate to swiping updates like in Angular, but WPF did not even attempt to address it. Third party frameworks allow to use lambda expression instead of string property name. This reduces typos, and associated silent lack of updates at run time, but does not address verbosity in any way.

I won’t cover dependency properties and attached properties here. Look at some examples in MSDN. Suffice it to say that part of the example reads “FrameworkPropertyMetadataOptions.AffectsRender“.

Value converters are verbose

Value converters are needed for the simplest tasks in WPF. E.g., if I have a Boolean property that I want to show as “yes” when true, and as “no” when false, I need a value converter (or I could just do the conversion in my view model, but this is usually a bad idea). The framework provides only a handful of converters out of the box, and most of those are highly specialized ad-hoc converters WPF authors needed for themselves. No attempt was made to create a comprehensive library of converters. To convert a Boolean to a string I need to write a converter class:

public class BoolToTextConverter : IValueConverter
{
    public string TrueText { get; set; }
    public string FalseText { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        bool flag = false;
        if (value is bool) flag = (bool)value;
	else if (value is bool?) flag = ((bool?)value == true);

        return flag ? TrueText : FalseText;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Then I need to reference this class in my XAML, and don’t forget the namespace reference too:

<Window xmlns:local="clr-namespace:My.Code">
    <Window.Resources>
        <local:BoolToTextConverter x:Key="BoolToText" TrueText="Yes" FalseText="No" />
    </Window.Resources>

And then finally I can use my beloved converter in a binding expression:

<TextBlock Text="{Binding MyBoolValue, Converter={StaticResource BoolToText}"/>

There are more elegant ways to do this, but the amount of ceremony remains astonishing. Also, neither Silverlight, nor WinRT have MarkupExtension class, so this solution applies only to pure WPF.

For a simple task like this I expect to write something like {Binding MyBoolValue, False=No, True=Yes} and be done with it.

WPF lacks conceptual coherence

WPF offers multiple ways of handling user input and program output:

  • Data binding.
  • Routed events.
  • Commands.
  • Direct calls on controls like SetFocus().

Somehow WPF authors never came up with a strategy that allows all these methods to co-exist peacefully. Data binding assumes you are going to use view models, which are data objects devoid of presentation details. This is great idea for separation of concerns, but other ways of handling program/UI interaction don’t fit well with it. Routed events are handled in views and completely ignore view models. Commands are better, but they are quite limited in scope compared to routed events, and are unusable out-of-the-box, since WPF provides no implementation for the ICommand interface. Every project needs to include an implementation like DelegateCommand or RelayCommand, or borrow it from a third party framework. Frankly, I find such lack of fundamental building blocks disturbing. Some calls like “SetFocus” or “ShowDialog” don’t fall under any of the “structured” categories above, and they are the worst.

Every time you write a program bigger than “Hello, world”, you keep running into philosophical questions, because view models are not supposed to know about the views, and MVVM machinery simply does not have easy answers on how to achieve things like handling arbitrary events, setting focus, or creating new windows.

Bottom line

WPF has a lot of interesting ideas, especially around hierarchical controls. I like the fact that I can put checkbox inside a button or button inside a checkbox. However, pervasive verbosity and lack of conceptual coherence make creating good WPF (Silverlight, Metro) applications conceptually hard, forcing the developer to write lots of code to achieve simple things, and to struggle with philosophical questions which should have been solved on the framework level.

Leave a Reply

Your email address will not be published. Required fields are marked *