Welcome to The Digital Lifestyle and Media Center Show Sign in | Join | Help
in Search
mControl for Windows Media Center

The Digital Lifestyle Developer Blog

Windows Media Center development hints, tips, tutorials and information

Stage 11: Responding To Answers (Timers and Commands)

OK, we can now answer trivia questions and keep a score...but you've got to keep watching that darn bottom corner to see if you got it right or not!

So how about we add a little more feedback to the questions by having it obvious if you were right or wrong.

 To do that, we are going to need another UI component. Let's start by making one for the 'Correct' response.

<UI Name="AnswerResponse">

<UI/>

In this case, we are going to make a large piece of text (saying 'Correct!') appear on the screen where our list of answers are. It will fade in and move 'towards' us, then fade back out.

So we build our content...

<Panel Name="MainPanel" Alpha="1" Visible="false" Layout="Center">

   <Children>

      <Text Color="Green" Content="Correct!" Font="Arial,50,Bold" />

   </Children>

</Panel>

Basics done. Now, since we want to make this appear to 'zoom in', we will need an animation that scales the object from the middle. We can do this by setting it's CenterPointPercent property.

<Panel Name="MainPanel" Alpha="1" Visible="false" CenterPointPercent="0.5,0.5,0.5" Layout="Center">

Since we also only want this text to appear occasionally (rather than all the time) I've set the Visible property to false.

I've probably already explained this, but just to make sure you know...if an object is not Visible, then it does not interact with the keyboard and mouse. If an object has it's alpha set to 0, you won't be able to SEE it, but it can still block mouse events. So we want to make this object completely dissapear. In this case, we use Visible rather than Alpha.

Now, when a item changes from Visible="false" to Visible="true", the 'Show' animation is run. So let's create an animation for our panel that will fade the object in, enlarge it, then fade it out again.

<Panel Name="MainPanel" Alpha="1" Visible="false" CenterPointPercent="0.5,0.5,0.5" Layout="Center">

   <Animations>

      <Animation Type="Show">

         <Keyframes>

            <AlphaKeyframe Time="0" RelativeTo="Absolute" Value="0"/>

            <ScaleKeyframe Time="0" RelativeTo="Absolute" Value="1,1,1"/>

            <AlphaKeyframe Time="0.3" RelativeTo="Absolute" Value="1"/>

            <AlphaKeyframe Time="2" RelativeTo="Absolute" Value="1"/>

            <AlphaKeyframe Time="2.3" RelativeTo="Absolute" Value="0"/>

            <ScaleKeyframe Time="2.3" RelativeTo="Absolute" Value="1.2,1.2,1.2"/>

         </Keyframes>

      </Animation>

   </Animations>

   ...

The entire animation will run (as you can see from the above 'Time' settings) 2.3 seconds.

 

Cute. But how do we trigger the thing to appear?

Well, there are a number of ways to do this. You could create a string that had three states - for example, "Right", "Wrong" and "Waiting", you could use a Choice object, you could do all kinds of things that are messy and complicated. But MCML has a special object designed to handle these kinds of 'event driven' situations.

The Command object can be used to make MCML objects do what you need them to do in response to an event. In this case, we are going to enter our C# code and create two Command objects - one for a correct answer and one for an incorrect answer.

Command _WasRight;

Command _WasWrong;

public Command WasRight

{

   get { return _WasRight; }

}

public Command WasWrong

{

   get { return _WasWrong; }

}

With 'Command' objects, we don't need to bother about 'FirePropertyChanged' or any of that business. To make things happen from our C# code, we need to Invoke them. This is very easy...they have a member function called Invoke.

So when we validate our answer in C#, we do the following...

if (Right)

{

    _WasRight.Invoke();

}

else

{

    _WasWrong.Invoke();

};

There you go - if the answer was correct, we Invoke the 'WasRight' and if was wrong, we Invoke the 'WasWrong' commands.

Now we need to react to them. Command objects work in a very similar way to the ClickHandler object. You use a Changed rule to see if anything has happened. Let's see how we do this to handle when the user has answered the question right...

 

<Changed Source="[game.WasRight.Invoked]">

   <Actions>

       <Set Target="[MainPanel.Visible]" Value="true"/>

   </Actions>

</Changed>

So when the 'Invoked' property of the WasRight command changes (which basically means 'when somebody calls Invoke'), it should immediately set the MainPanel object (the panel that contains our text object) to be visible.

This will trigger the Show animation, which will give us a lovely fade in and fade out!

But hold on!

We fade the object out, but we never make it invisible again. As I said earlier, an object that with an Alpha of 0 can still block mouse clicks and interaction, so we need to make sure that we set the Visible attribute back to false.

Windows Media Center doesn't have a method of detecting the end of an animation. So how do we get around this, and make our object invisible again?

This is where timers come in.

 

Timer objects are similar to commands and are easy to use methods of timing events in your MCML markup. In this case, we have an animation that is 2.3 seconds long. So what we need is a timer that will tell us when 2.3 seconds have elapsed!

We create our timer object in the Locals section...

<Locals>

   <Timer Name="VisibleTimer" Interval="2300"/>

</Locals>

And as you can see, we give it a name and an 'interval' (which is the time we want to measure, in milliseconds). You can start and stop timers by using the Enabled property. If we wanted our timer to turn on immediately after the page opens, we could set this property now - but it defaults to "false", which is what we want.

So now, we need to turn the timer on. We want to do that when the animation starts...and the animation is triggered by setting the Visible property on the panel to true.

Find the code where we made the panel visible, and add a line to switch the timer's Enabled property to true. This will turn the timer on.

<Actions>

   <Set Target="[MainPanel.Visible]" Value="true"/>

   <Set Target="[VisibleTimer.Enabled]" Value ="true"/>

</Actions>

To catch when the 2.3 seconds have elapsed, you check for the Tick property in the exact same way we checked the Invoked property in a Command object.

<Changed Source="[VisibleTimer.Tick]">

   <Actions>

      <Set Target="[MainPanel.Visible]" Value="false"/>

      <Set Target="[VisibleTimer.Enabled]" Value="false"/>

   </Actions>

</Changed>

Almost an exact opposite of the Invoked function, this one makes the panel invisible again and turns the timer off (although since this is a one-time timer, we don't REALLY need to do that).

Excellent. Let's add it to our main UI and see how it looks.

<me:AnswerResponse game="[game]">

   <LayoutInput>

      <FormLayoutInput Top="Parent,.45" Bottom="Parent,.55" Horizontal="Center"/>

   </LayoutInput>

</me:AnswerResponse>

That code will create the AnswerResponse object (passing our 'TriviaCenter' object so it can check for the WasRight command to be invoked).

So now we need one for 'Wrong'. And it's going to be almost identical. Hmm...do we really need to do all that work again, or copy and paste the darn thing and have to do TWO changes should we ever add new features or fix bugs?

Well...why make this AnswerResponse object a little more universal? 

Ask yourself what the major differences are probably going to be between the 'Right' and 'Wrong' events. For getting it basically working, all we really need is to change the writing, and maybe change the colour.

So we dive into our AnswerResponse object, and make properties for these differences.

<Properties>

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

   <Color Name="Colour" Color="Green"/>

   <Command Name="ShowWhen" Command="$Required"/>

</Properties>

 This gives us the text label, the colour and the Command object we need to react to. We simply chop and change the values in our content and in our rules sections, and we have something nice and re-usable!

<me:AnswerResponse Label="Correct!" Colour="Green" ShowWhen="[game.WasRight]">

   <LayoutInput>

      <FormLayoutInput Top="Parent,.45" Bottom="Parent,.55" Horizontal="Center"/>

   </LayoutInput>

</me:AnswerResponse>

<me:AnswerResponse Label="Wrong!" Colour="Red" ShowWhen="[game.WasWrong]">

   <LayoutInput>

      <FormLayoutInput Top="Parent,.45" Bottom="Parent,.55" Horizontal="Center"/>

   </LayoutInput>

</me:AnswerResponse>

The right and wrong answer animations...done with style.

Remember to leave comments if you found this helpful...it's not like I do this for the money! Although my MSDN subscription is coming up soon, and if you happened to have a spare $900AUD...   :)

Next time, let's add some graphics and sound to this visually dull affair...and maybe we can spice up the questions too.

Sample code can be found here.

Published 23 June 2007 17:46 by IgnoranceIsBliss
Filed under: ,

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 

  
Enter Code Here: Required
Submit
mControl for Windows Media Center
Powered by Community Server (Personal Edition), by Telligent Systems