IanG on Tap

Ian Griffiths in Weblog Form (RSS 2.0)

Blog Navigation

April (2018)

(1 item)

August (2014)

(1 item)

July (2014)

(5 items)

April (2014)

(1 item)

March (2014)

(1 item)

January (2014)

(2 items)

November (2013)

(2 items)

July (2013)

(4 items)

April (2013)

(1 item)

February (2013)

(6 items)

September (2011)

(2 items)

November (2010)

(4 items)

September (2010)

(1 item)

August (2010)

(4 items)

July (2010)

(2 items)

September (2009)

(1 item)

June (2009)

(1 item)

April (2009)

(1 item)

November (2008)

(1 item)

October (2008)

(1 item)

September (2008)

(1 item)

July (2008)

(1 item)

June (2008)

(1 item)

May (2008)

(2 items)

April (2008)

(2 items)

March (2008)

(5 items)

January (2008)

(3 items)

December (2007)

(1 item)

November (2007)

(1 item)

October (2007)

(1 item)

September (2007)

(3 items)

August (2007)

(1 item)

July (2007)

(1 item)

June (2007)

(2 items)

May (2007)

(8 items)

April (2007)

(2 items)

March (2007)

(7 items)

February (2007)

(2 items)

January (2007)

(2 items)

November (2006)

(1 item)

October (2006)

(2 items)

September (2006)

(1 item)

June (2006)

(2 items)

May (2006)

(4 items)

April (2006)

(1 item)

March (2006)

(5 items)

January (2006)

(1 item)

December (2005)

(3 items)

November (2005)

(2 items)

October (2005)

(2 items)

September (2005)

(8 items)

August (2005)

(7 items)

June (2005)

(3 items)

May (2005)

(7 items)

April (2005)

(6 items)

March (2005)

(1 item)

February (2005)

(2 items)

January (2005)

(5 items)

December (2004)

(5 items)

November (2004)

(7 items)

October (2004)

(3 items)

September (2004)

(7 items)

August (2004)

(16 items)

July (2004)

(10 items)

June (2004)

(27 items)

May (2004)

(15 items)

April (2004)

(15 items)

March (2004)

(13 items)

February (2004)

(16 items)

January (2004)

(15 items)

Blog Home

RSS 2.0

Writing

Programming C# 5.0

Programming WPF

Other Sites

Interact Software

DataBinding, Layout, Avalon, and Windows Forms 2.0

Sunday 22 August, 2004, 06:12 PM

In Chris Sells' recent article on data binding in Avalon, he points out something that makes data binding in Avalon much easier to use than in Windows Forms today. He shows a Windows Forms example binding a Score property of some Game object to a UI, and then laments:

"What's missing in this scheme, however, is the opportunity to do any composition of the data with the "Score: " prefix."

Because he binds the Score property of his data source to the Text property of the relevant user interface object, it ends up displaying the value of the property and nothing else. This is unfortunate, because he would like to display, say, "Score: 42" rather than just "42". As Chris points out, it's possible to customize what appears but you have to use the rather ungainly technique of handling the Convert event on the Binding object to set the text.

Chris then illustrates a much better way of doing it in Avalon - something like this:

<FlowPanel>
  <Text TextContent="Score: " />
  <Text TextContent="*Bind(Path=Score)" />
</FlowPanel>

This feels much better to me than the Windows Forms example - it captures the intent much more cleanly. We have some markup to define the appearance of this part of our UI, and one of the elements acts as a placeholder for the Score.

But hold on just a minute. We can use this exact same technique today with Windows Forms. The main difference between this code and Chris's first Windows Forms databinding example is not that this second snippet uses Avalon. To me, the really significant change is that in the second example we've got two user interface elements - one to display the "Score: " text, and another to bind to the Score property. We can do exactly the same thing in Windows Forms.

However, the one thing that is missing today in Windows Forms is the support for rich layout that makes this kind of thing very easy to use in practice without having to go to a lot of effort to make sure that all the controls are in the right place. If you wanted to put some text after the Label you bound to the Score property, you would almost certainly need some code to adjust its position based on the current size of the control showing the score. Chris's XAML on the other hand just relies on Avalon's FlowPanel class to do all this work, which is a much simpler solution. So you can just do something like this:

<FlowPanel>
  <Text TextContent="Score: " />
  <Text TextContent="*Bind(Path=Score)" />
  <Text TextContent=" (aren't you clever?)" />
</FlowPanel>

The good new for Windows Forms developers is that when .NET 2.0 ships, we'll be able to use this same technique in Windows Forms too. Lots of new layout support is being added for the next version of Windows Forms, including the FlowLayoutPanel. This new class enables us to use exactly the same trick that Chris used in his XAML example. Here is roughly what a Windows Forms equivalent (.NET 2.0 only) might look like:

Label label1 = new Label();
label1.Text = "Score:";
label1.AutoSize = true;

Label labelScore = new Label();
labelScore.DataBindings.Add("Text", game1, "Score");
labelScore.AutoSize = true;

Label label2 = new Label();
label2.Text = "(aren't you clever?)";
label2.AutoSize = true;

FlowLayoutPanel flowPanel = new FlowLayoutPanel();
flowPanel.Controls.Add(label1);
flowPanel.Controls.Add(labelScore);
flowPanel.Controls.Add(label2);

OK, that's more verbose than Chris's example, but that's mainly because I'm using imperative code and not markup. The Avalon example would look about as verbose if done in the same way. And in practice, you'd do this in the designer with Windows Forms, so it's really just a case of dropping a few controls onto a form.

Where It All Falls Down in Windows Forms

Useful though this technique is, it doesn't actually solve the problem that Chris set out to solve. I've carefully adjusted the requirements so I can demonstrate the technique. The problem is that Chris wanted to put the text in a status bar. That's a problem because, as far as I can tell, there's no way of embedding a FlowLayoutPanel inside a status bar in Windows Forms. The best you can do is put multiple panels inside the status bar and then disable their borders so that it looks like they're all part of the same piece of text, which is a bit of a hack...

This illustrates one of the big improvements Avalon offers over Windows Forms. It typically supports the nesting of arbitrary content inside of any user interface element, where in Windows Forms you tend to run up against things that just have a Text property with no way of nesting child controls. (To be fair, this restriction often doesn't apply in Windows Forms. Controls can usually be nested inside of other controls. Most of the problems arise because not everything is a control - the status bar is not a control for example. Although there are other issues - although it is technically possible to nest controls inside a Button in Windows Forms, it doesn't quite have the effect you want - the child content will not behave as the caption of the button, whereas in Avalon it will.)

Where You'd Think It Would All Fall Down in Avalon, But Turns Out Not To

But hold on - don't certain Avalon controls have a Text property too, or at least something like it? The Button has a Content property which on first glance appears to do what the Text property does on a Windows Forms Button. If you set it to be some text, that text appears as the button caption.

However, it turns out that you can in fact use whatever markup you like as a button caption in Avalon. Avalon has a rather clever way of dealing with controls like buttons, which want to provide some visuals of their own, but which also want to incorporate arbitrary markup. This is all made possible by Avalon's rather useful control content model.

There is the odd deliberate exception. The Text element Chris uses in his example is a case in point - it has a TextContent property, and that really does only support text. But that's because the Text element deliberately opts out of the normal support for fully nestable content - its purpose is to provide an ultra-lightweight element for when you really only want some very simple text, but still need it as a distinct object in the UI element tree rather than just some text in the markup. (E.g. because you want to be able to bind some data to it.) But in general, nesting works just fine throughout.

Copyright © 2002-2024, Interact Software Ltd. Content by Ian Griffiths. Please direct all Web site inquiries to webmaster@interact-sw.co.uk