Monday, January 29, 2007

Turning UIs into Controls

As I mentioned last post, UI's contain not only content, but also can have their own properties and local variables. We are going to play with those now, to create a more flexible, reusable control.

This time we are creating a text object in a coloured box. We are starting with the code we were using in the last post :

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BooText>
      <me:BooText>
    </Panel>
  </Content>
</UI>

<UI Name="BooText">
  <Content>
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
  </Content>
</UI>


So the first step is to add our coloured box. This is easy - it's done with a colorfill.

So 'BooText' changes to become...

<UI Name="BooText">
  <Content>
    <Colorfill Content="Red">
      <Text Content="Boo" Font="Tahoma,30" Color="Blue"/>
    </Colorfill>
  </Content>
</UI>


In the above code we have surrounded the text control with a filled red square.

But just saying 'Boo' is very, very boring. We can't expect to reuse a control like that. So now we need to add a property to our BooText UI. And while we are there, let's rename it to 'BGText'.

<UI Name="BGText">
  <Properties>
    <cor:String Name="Label" String="$Required"/>
  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="[MainText.Content]"/>
  </Rules>

  <Content>
    <Colorfill Content="Red">
      <Text Name="MainText" Font="Tahoma,30" Color="Blue"/>
    </Colorfill>
  </Content>
</UI>


Yes, this may need a little bit of explaining.

The first thing we did was declare a new property for this UI. In this case, it's a String (from the cor namespace) named 'Label'. We have set it to the reserved word '$Required' instead of giving it a value (eg. cor:String="My Default Value") which means that the UI that creates this object MUST specify the label.

The label can be assigned either as an attribute (eg. <me:BGText Label="My Label"> or as a tag (eg. <me:BGText><Label>My Label</Label></me:BGText>

In the next part of our UI, we defined a rule. This controls how the control actually responds at runtime. In this case, we have created a binding. We have bound the property called 'Label' to the Content property of the control name MainText. This means that when we pass a value to the Label property of this UI, it will automatically be copied over into the text control named 'MainText'.

Then in our content section, we have given the text element a name (MainText) and removed the Content section, since we will now be giving it content through the Label property.

Last step - change the main UI to reflect our changes.

<UI Name="Main">
  <Content>
    <Panel Layout="VerticalFlow">
      <me:BGText Label="Text #1">
      <me:BGText Label="Text #2">
    </Panel>
  </Content>
</UI>


So we now have two text boxes, one saying "Text #1" and one saying "Text #2", with coloured backgrounds.

Of course, you can play a lot more. You can give the control more properties. For instance, properties to adjust the colour of the text, the colour of the background, the font, etc. Just remember that instead of using the name of the colour (eg. "White") you use the name of the property, in square brackets(eg. "[BackgroundColour]")

<UI Name="BGText">
  <Properties>
    <cor:String Name="Label" String="$Required"/>
    <Color Name="TextColour" Color="White"/>

  </Properties>

  <Rules>
    <Binding Source="[Label]" Target="[MainText.Content]"/>
  </Rules>

  <Content>
    <Colorfill Content="Red">
      <Text Name="MainText" Font="Tahoma,30" Color="[TextColour]"/>
    </Colorfill>
  </Content>
</UI>

No comments: