Wednesday, January 31, 2007

Tips & Tricks: 'Global' Variables

A quick word for the wise when it comes to MCML and your variables.

As much as you would like every UI to be it's own completely autonomous control, there are times when you need real feedback from your UI's.

This can actually be quite a problem, since a UI can not talk to it's parent.

So what is the trick? It's actually not too difficult, but for the newbie it can be very confusing.

We have already introduced properties, allowing you to set the attributes of the UI's you are creating. As well as properties, we have locals. These are in a very similar form to properties, with the only real difference being that you can't tell a UI what it's locals should be.

The trick is to take one of your local variables and basically just 'pass it on' as properties to all other objects that need access to it.

BUT - and here's the trick - you need to be aware of what TYPE of property you are using. This is because the variables work differently depending on what type you use.

If you use an object from the cor: namespace (such as cor:String, cor:Int32, cor:Boolean etc.) then you have created a simple type, like 'int' or 'long' in C. If you pass simple objects to a UI, it gets it's own new copy of the variable, meaning that if you change the value in any of your sub-items, the change will only effect THAT ITEM.

However, if you use something more complicated, a CLASS like EditableText for instance, every UI that is sent it as a property gets a reference to the object. This means that when you change a value in ANY of the UI's you have passed it to, it will be changed for ALL UI's.

<UI Name="MainUI">

  <Locals>
    <cor:String Name="Brand" cor:string="My Brand">
    <EditableText Name="Area" EditableText="None">
  </Locals>

  <Content>
    <Panel Layout="VerticalFlow">
      <Children>
        <Text Name="BrandName" Color="White" Font="Tahoma,20"/>
        <Text Name="AreaName" Color="White" Font="Tahoma,20"/>
        <me:BrandedOption BrandVar="[Brand]" AreaName="Option #1" BrandName="ACME" AreaVar="[Area]"/>
        <me:BrandedOption BrandVar="[Brand]" AreaName="Option #2" BrandName="Someone Else" AreaVar="[Area]"/>
      </Children>
    </Panel>
  </Content>

  <Rules>
    <Binding Source="Brand" Target="BrandName.Content">
    <Binding Source="Area" Target="AreaName.Content">
  </Rules>

</UI>

<UI Name="BrandedOption">

  <Properties>
    <cor:String Name="BrandVar" cor:string="$Required">
    <cor:String Name="BrandName" cor:string="$Required">
    <EditableText Name="AreaVar" EditableText="$Required">
    <cor:String Name="AreaName" cor:string="$Required">

  </Properties>

  <Content>
    <Panel Layout="HorizontalFlow">
      <Children>
        <Text Name="ButtonArea" Color="Red" Font="Arial,20" Content="[AreaName]"/>
        <Text Name="ButtonBrand" Color="Red" Font="Arial,20" Content="[BrandName]"/>
      </Children>
    </Panel>
  </Content>

  <Rules>
    <Condition Source="[Input.MouseFocus]" SourceValue="true">
      <Actions>
        <Set Target="[BrandVar]" Value="[BrandName]">
        <Set Target="[AreaVar]" Value="[AreaName]">
      </Actions>
    </Condition>
  </Rules>

</UI>


I haven't actually TESTED this UI (although I do something similar in my existing MCML) but that will give you the basic outline.

What we have is an interface that has two text boxes in white, giving you the current brand name setting, and the current area name setting. These are constantly updated with the rule we have specified, which makes sure the value of 'Area' and 'Brand' are copied into the text controls whenever the values are updated.

There are also two buttons. Each button has two text elements, the brand and the area/type of a product (set with the AreaName and BrandName properties) and the button is also passed our global Brand and Area variables through the AreaVal and BrandVal.

In the buttons, we have a rule that says that whenever the object is given mouse focus (Input.MouseFocus = true) then we are to set the AreaVal and BrandVal properties to AreaName and BrandName (the names displayed on the button).

What you should find when you do this is that when you roll over a button, the AREA will change, but the BRAND will not. This is because of the rules I explained earlier.

So now you know how to share a variable through your entire UI. This will come in handy in the next project discussed.

No comments: