Monthly Archives: October 2013

Animation in XAML (Part 1)

Introduction

I recently wrote a little application in WPF, which displayed a button. I thought it would be nice to have the button “burst” onto the screen, which is unlike me… normally the screen looks like it looks, or it looks like a command prompt (apparently not everything can be a console app).

When looking around on the web, I found very little information about this. What I did find was a mixture of code that didn’t work, wasn’t explained, or both. As you may have gathered from the previous paragraph; I’m no expert in this, but I’m going to try and collate my findings into a series of posts.

Button Animation using WPF with no code-behind

So here’s the code for creating a button in WPF (you might want to sit down, as the technical brilliance of this XAML may make you dizzy):

             <Button Width ="200" Height="150" name="testbutton">
                Don't Click Me               
            </Button>

I know, and still no call from Microsoft to go there as a consultant! Anyway, believe it or not, there’s more. I want to make the button expand as it’s loaded; so an event trigger allows me to do this quite easily (this is inside the button definition):

    <Button.Triggers>
        <EventTrigger RoutedEvent ="Button.Loaded">

So, anything in this event should fire when the button is loaded. What I want to fire is an animation. In WPF terms, this is a storyboard; basically, that’s just a collection of animations. The storyboard definition is inside the trigger:

<BeginStoryboard>
     <Storyboard>

The expanding animation looks something like this:

                                
                                <DoubleAnimation
                                    Storyboard.TargetName="MyAnimatedScaleTransform"
                                    Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                                     From="0" To ="1" Duration="0:0:0.2"/>
                                <DoubleAnimation
                                    Storyboard.TargetName="MyAnimatedScaleTransform"
                                    Storyboard.TargetProperty="(ScaleTransform.ScaleY)"
                                     From="0" To ="1" Duration="0:0:0.2"/>;
  

So what have I told it there? I’ve told it that I want to animate a double value (i.e. a floating point number) – DoubleAnimation; I’ve told it that I want to change a property within something called “MyAnimatedScaleTranform” (more on this in a minute); and that the property is called “ScaleTransform.ScaleX” (“ScaleTransform.ScaleY” for the second one). I’ve then told it what to change that property from and to, and how long to take.

Okay, so we now have a button, a storyboard and an animation that tells it what to do; but that’s not all – remember MyAnimatedScaleTranform from the last paragraph? The problem is that WPF doesn’t know what ScaleTransform is, and so inside the button definition we need to define that. Here’s the full code for the button:

<Button
  Name="testbutton"
  Width="200" Height="150">
    Don't Click Me               
    <Button.RenderTransform>                    
        <ScaleTransform x :Name="MyAnimatedScaleTransform"
              ScaleX="1" ScaleY ="1" CenterX="100" CenterY="75"  />
    </Button.RenderTransform>                
    <Button.Triggers>
        <EventTrigger RoutedEvent ="Button.Loaded">
             <BeginStoryboard>
                 <Storyboard>
                     <DoubleAnimation
                         Storyboard.TargetName="MyAnimatedScaleTransform"
                         Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                         From="0" To ="1" Duration="0:0:0.2"/>
                     <DoubleAnimation
                         Storyboard.TargetName="MyAnimatedScaleTransform"
                         Storyboard.TargetProperty="(ScaleTransform.ScaleY)"
                         From="0" To ="1" Duration="0:0:0.2"/>
                 </Storyboard>
             </BeginStoryboard>
        </EventTrigger>
    </Button.Triggers>
</Button>

The CentreX and CentreY properties tell it where to grow from (i.e. where the origin is). These values are relative, so you can place this button anywhere on a form and it will still grow from the middle.

So, that should do it… well, it should give you a button that grows into existence; try it. I wanted mine to “pop”, though. So I decided I needed it top grow a bit to big, and then correct itself. To make the button grow too big is easy-peasy:

From ="0" To ="1.2"

Now it grows too big. So it needs to get smaller; that’s “drink me” isn’t it:

                                 <DoubleAnimation
                                    Storyboard.TargetName="MyAnimatedScaleTransform"
                                    Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                                     From="1.2" To ="1" Duration="0:0:0.1">
                                <DoubleAnimation
                                    Storyboard.TargetName="MyAnimatedScaleTransform"
                                    Storyboard.TargetProperty="(ScaleTransform.ScaleY)"
                                     From="1.2" To ="1" Duration="0:0:0.1">

Add those after the existing two `DoubleAnimation` elements and run again. At first glance, it would appear that they will execute in sequence; but of course if they did, you would have seen the X co-ordinate expand before the Y. What, in fact, happens, is the last animation wins and it just contracts.

With no small help from a well known site that allows programmers to ask questions of other programmers, with the intention of writing a blog post and passing the knowledge off as their own, I found this little trick. There is a `BeginTime` property of DoubleAnimation:

                                 < DoubleAnimation
                                    Storyboard.TargetName="MyAnimatedScaleTransform"
                                    Storyboard.TargetProperty="(ScaleTransform.ScaleX)"
                                     From ="1.2" To ="1" Duration="0:0:0.1"
                                                            BeginTime="0:0:0.2"/>
                                < DoubleAnimation
                                    Storyboard.TargetName="MyAnimatedScaleTransform"
                                    Storyboard.TargetProperty="(ScaleTransform.ScaleY)"
                                     From ="1.2" To ="1" Duration="0:0:0.1"
                                                            BeginTime="0:0:0.2"/>

Now try it – good eh? You can play with the “pop”, make it grow bigger, or smaller. There’s even a repeat property.

Conclusion

I intend this to be the first in a few posts on animation. Next, I intend to write about how you would do the same thing using code; and later, I’ll look at how this all works in WinRT (I’ll give you a clue – it’s not the same!).

Implementing a Review Reminder in a Windows Store C# XAML App

If, like me, you aren’t getting very many reviews for your Windows Store Apps, you might want to give people a nudge. Be careful with this approach, as there’s nothing more irritating than a constantly nagging textbox whining about reviewing an app. Don’t be surprised (or blame me) if you get a review saying: Stop nagging about reviews. But done correctly (in-frequently) you might just persuade a few extra people to review your app.

The process is relatively straightforward; you first need to store two additional roaming setting; mine look like this:

var reviewed = roamingSettings.Values["ReviewedProduct" ];
var lastReminder = roamingSettings.Values["LastReminder" ];

I’m not sure these need any explanation (but I’ll provide one): one to determine whether the product has ever been reviewed and one to say when.

Next, and it’s entirely your choice when but, you need to prompt the user. Having said that, at the start or end of using the app seems a sensible choice; whereas suspending the app mid way and interrupting the user, does not. I do this on load at the same time as reading the other roaming settings:

         protected override void Initialize()
        {
            try
            {
                // Get settings first
                ReadSettings();
                CheckAppReview();

My CheckAppReview function looks like this:

            var reviewed = roamingSettings.Values[ "ReviewedProduct"];

            if (reviewed == null || !Boolean.Parse(reviewed.ToString()))
            {              
                var lastReminder = roamingSettings.Values[ "LastReminder"];

                if (lastReminder == null || DateTime.Now > DateTime.Parse(lastReminder.ToString()).AddDays(5))
                {
                    MessageBoxHelper.MsgBox.ChangeButtonText("Cancel" , "Never ask again");
                    var result = await MessageBoxHelper.MsgBox.ShowAsync("Please would you consider reviewing this application?", "Review Reminder",
                                            MessageBoxButton.YesNo | MessageBoxButton.Cancel);
                    if (result == MessageBoxResult.Yes)
                    {
                        await Helpers. Product.Review();
                        roamingSettings.Values[ "ReviewedProduct"] = true ;
                    }
                    else if (result == MessageBoxResult.No)
                    {
                        roamingSettings.Values[ "LastReminder"] = DateTime.Now.ToString();
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        roamingSettings.Values[ "ReviewedProduct"] = true ;
                    }
                }
            }

The MessageBoxHelper class is the subject of another post, which can be found here.

Obviously this does have its own problems; not the least of which is that it’s pretty difficult to unit test because it uses roamingSettings directly. At some point in the future, I may supplement this with a post on the abstraction of this, but if I don’t, then you definitely should (abstract it that is, not write a blog post – although if you do the latter then send me a link and I’ll amend this post to include it!).

Other problems with it are that the 5 day interval is hard coded and it doesn’t account for the user migrating across a time zone (or even changes their culture) with their profile. So, if any of this matters then be sure not to copy and paste the code verbatim!

Conclusion

You might find this approach to be counter productive. People tend not to want to give reviews, because it means spending time doing something that has nothing to do with the functionality of your app or game. If you’re feeling brave (and I have no idea if this is compliant with the Windows Store Police) you could have certain features that are enabled only after the user agrees to review your app. You could implement that by simply checking the roaming setting:

roamingSettings.Values[ "ReviewedProduct"]

With something like a game, you could give extra credits, or if your app uses any paid features then you could offer to provide them for a limited time period or something.

I imagine this will force people to either review your app or just uninstall it!

Also, keep in mind that once the user agrees to review your app, there’s no way to tell if they’ve actually done so using this approach; nor is there any way to detect they’ve done so via another method.

MessageBox Helper for Windows Store Apps

Believe it or not, the MessageBox.Show() function is unavailable for WinRT. Admittedly, you probably shouldn’t be using it too much. But when you do, it’s unavailable (so you can’t). The workaround is to build up a MessageDialog. Have a go – for a yes / no box, you’re looking at maybe 10 lines of code.

I found an article on the web about creating a helper class; modified it a little, and then felt obliged to re-post.

(Here’s the original article: http://www.reflectionit.nl/Blog/2012/messagebox-show-in-winrt)

What you’ll see if you read that is that he produces a very nice helper class; but what if you want cancel to be called something else (which I did)? Well, here’s my attempt:

         public async Task< MessageBoxResult> ShowAsync(string messageBoxText,
                                                             string caption,
                                                             MessageBoxButton button) {
 
            MessageDialog md = new MessageDialog (messageBoxText, caption);
            MessageBoxResult result = MessageBoxResult .None;
            if (button.HasFlag( MessageBoxButton.OK)) {
                md.Commands.Add( new UICommand(buttonTextMap[ "OK"],
                    new UICommandInvokedHandler((cmd) => result = MessageBoxResult.OK)));
            }
            if (button.HasFlag( MessageBoxButton.Yes)) {
                md.Commands.Add( new UICommand(buttonTextMap[ "Yes"],
                    new UICommandInvokedHandler((cmd) => result = MessageBoxResult.Yes)));
            }
            if (button.HasFlag( MessageBoxButton.No)) {
                md.Commands.Add( new UICommand(buttonTextMap[ "No"],
                    new UICommandInvokedHandler((cmd) =>; result = MessageBoxResult.No)));
            }
            if (button.HasFlag( MessageBoxButton.Cancel)) {
                md.Commands.Add( new UICommand(buttonTextMap[ "Cancel"],
                    new UICommandInvokedHandler((cmd) => result = MessageBoxResult.Cancel)));
                md.CancelCommandIndex = ( uint)md.Commands.Count - 1;
            }
            var op = await md.ShowAsync();
            return result;
        }

The eagle eyed and alert amongst you will notice that this is a carbon copy, with the exception that I’m using a variable called buttonTextMap, instead of using a hard coded string.

Here’s the definition:

         private Dictionary<;string , string > buttonTextMap = new Dictionary> string, string>()
        {
            { "OK", "OK" },
            { "Yes", "Yes" },
            { "No", "No" },
            { "Cancel", "Cancel" }
        };

So far, so… exactly the same. The next section is not really a leap forward in software engineering though:

         public void ChangeButtonText( string button, string newButton)
        {
            buttonTextMap[button] = newButton;
        }

And that’s it. Here’s how I used it:

    MessageBoxHelper.MsgBox.ChangeButtonText("Cancel" , "Never ask again");
    var result = await MessageBoxHelper.MsgBox.ShowAsync("Please would you consider reviewing this application?", "Review Reminder", MessageBoxButton.YesNo | MessageBoxButton.Cancel);

I’ll be posting some more on the context I used it in soon.

Conclusion

What this means it that you can replace the existing buttons with custom named ones, and the code is not as hard to read as building up each option individually.

Thanks to Fons Sonnemans who wrote the original post, on which this is based.

Implementing a call to search using MVVM Light

I recently started using the MVVM Light framework to create an app. One of the first things that I found tripped me up was trying to link the ViewModel functionality with the visual interface. After a little more searching than should be necessary I came across the concept of commands. Basically, thos allows you to bind the functionality of your view model to an action on the screen. In the example below it’s the action of clicking a button.

First, create a new relay command (this is in the namespace GalaSoft.MvvmLight.Command):

    public class MainViewModel : ViewModelBase
    {
        private readonly IDataService _dataService;

        /// <summary>
        /// The <see cref="WelcomeTitle" /> property's name.
        /// </summary>
        public const string WelcomeTitlePropertyName = "WelcomeTitle" ;

        private string _welcomeTitle = string.Empty;

               // New Command Variable
        public RelayCommand SearchCommand { get ; private set ; }
        ...

Next initialise the command in the constructor of the VM:

        public MainViewModel( IDataService dataService)
        {
            this.SearchCommand = new RelayCommand (this.GetDataCount);
            ...

Obviously, the execute function must exist. For example:

        private void GetData()
        {
                _dataservice.GetData((count, error) =>
                {
                    if (error != null)
                    {
                        // Report error here
                        return;
                    }

                    // Do something with data here
                });
        }

Finally, simply add a call from the XAML in MainWindow:

Parameters

You can also pass parameters, by simply providing the CommandParameter attribute and then using it. However, given that you’re already in the databound context (i.e. you’re function is in your ViewModel, which is bound to the DataContext) I didn’t find a need for this, as it’s possible to simply reference the property directly.

Conclusion

This ends up being quite a neat way to link the two. The screen is linked to the view model without having a chunk of code in the button click handler.

Adding a settings Page to the Windows 8 Settings Charm

I recently completed by second game in Windows 8 (the first using the MonoGame framework). Given the MonoGame architecture, displaying a settings screen seemed a little more complicated than it should have been; obviously displaying this using native Windows controls will mean that I have some re-work should I ever try to port to Android.

This first thing with WIndows is always to hook up the Windows settings charm (don’t confuse this with your own settings page):

        private void AddFlyouts()
        {
            var settingsPane = SettingsPane.GetForCurrentView();           
            settingsPane.CommandsRequested += settingsPane_CommandsRequested;           
        }

This function should be called from the OnLaunched event of you app (for C# apps this is in App.xaml.cs).

Next, create the CommandsRequested event handler, and show the settings screen:

        void settingsPane_CommandsRequested(Windows.UI.ApplicationSettings.SettingsPanesender, Windows.UI.ApplicationSettings.SettingsPaneCommandsRequestedEventArgs args)
        {
             var commandSettings = 
                              new SettingsCommand ("settings" , "Settings" , settingsCommandInvoked);
            args.Request.ApplicationCommands.Add(commandSettings);
        }

And here’s what settingsCommandInvoked looks like:

        private Popup _popUp;
        private const double WIDTH = 646;
        private void settingsCommandInvoked(Windows.UI.Popups.IUICommand command)
        {
            Rect window = Window.Current.Bounds;

            _popUp = new Popup
            {
                Width = WIDTH,
                Height = window.Height,
                IsLightDismissEnabled = true,
                IsOpen = true
            };
            _popUp.Child = new Pages.SettingsPage () 
                              { Width = WIDTH, Height = window.Height };
            _popUp.SetValue( Canvas.LeftProperty, SettingsPane.Edge == SettingsEdgeLocation .Right ? (window.Width - WIDTH) : 0);
            _popUp.SetValue( Canvas.TopProperty, 0);
        }

If you’re just copying this verbatum and now compile that, you’ll discover that you need Pages.SettingsPage. That’s basically a XAML page that actually displays the settings. Mine looks something like this:

< UserControl
    x: Class ="MyApp.Pages.SettingsPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns: x ="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns: d ="http://schemas.microsoft.com/expression/blend/2008"
    xmlns: mc ="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc: Ignorable ="d"
    d: DesignHeight ="300"
    d: DesignWidth ="646">;
    <Border BorderBrush ="#FF590151" BorderThickness ="1">
        < Grid Background ="AliceBlue" VerticalAlignment="Stretch">
            < Grid.RowDefinitions>
                < RowDefinition Height ="80"/>
                < RowDefinition Height ="*"/>
            </ Grid.RowDefinitions>
            < Grid Background ="Aqua" Grid.Row="0">
                < Grid Margin ="40,20,17,13">
                    < Grid.Transitions>
                       < TransitionCollection>
                            < EntranceThemeTransition FromHorizontalOffset ="50" />
                        </ TransitionCollection>;
                    </ Grid.Transitions>
                    < Grid.ColumnDefinitions>
                        < ColumnDefinition Width ="50" />
                        < ColumnDefinition Width ="*" />
                        <; ColumnDefinition />
                    </ Grid.ColumnDefinitions>
                    < Button Click ="Button_Click_1" Margin="0,3,0,0" Grid.Column="0"
                        HorizontalAlignment ="Left" Style ="{ StaticResourceBackButtonStyle}"/>
                    < TextBlock Margin ="10,5,0,0" Grid.Column="1" FontFamily ="Segoe UI"
                        FontWeight ="SemiLight" FontSize ="24.6667" Text="Settings"HorizontalAlignment="Left" />
                    < Image Source ="/Assets/icon.png" HorizontalAlignment="Right"Grid.Column="2" Margin="0,0,6,0" />
                </ Grid>
            </ Grid>
            < Grid Grid.Row ="1" Margin="40,24,23,0" VerticalAlignment ="Top">
               
                < Grid.Transitions>
                    < TransitionCollection>
                        < EntranceThemeTransition FromHorizontalOffset ="120" />
                    </ TransitionCollection>
                </ Grid.Transitions>
                               
                < Button x : Name="MySetting" Foreground ="Black" BorderThickness="1"
                        Click ="MySetting_Click">Do Something</ Button>
               
            </ Grid>
        </ Grid>
    </Border >
</ UserControl>

That should be it. Inside the settings page itself, my suggestion would be that you use a instance of a class defined in App.Xaml.cs, and then use that elsewhere in your app / game to reference the setting. This means that you’re not constantly passing indiviual settings around.

Conclusion

As I said at the start, although this does work, if you’re using a cross platform framework for your game or app then this might not be the best approach; however, you do need to have your settings here if you intend to get into the Windows Store.

Adding Privacy Statement to Windows 8 Store App Built With Monogame

This has been covered many times on the web, but when using Monogame it isn’t as straightforward (not that it’s rocket science).

The key thing is to make sure that when creating the Monogame project, it is created using Monogame and XAML (I’ve blogged about this previously here).

In App.xaml.cs, add the following function to call your privacy statement:


Private async privacyCommandInvoked(Windows.UI.Popups.IUICommand command)
{
    Uri uri = new Uri("http://mypage.com/privacystatement.htm"");
    await Launcher.LaunchUriAsync(uri);
}

As far as I’m aware, it is a requirement of the Win 8 approval process that this be a web site; that is, it can’t simply be a XAML page that displays the text.

Now create a function to add this to the menu, and an event to handle it when it’s selected:


private AddFlyouts()
{
    var settingsPane = SettingsPane.GetForCurrentView();
    settingsPane.CommandsRequested += settingsPane_CommandsRequested;
}

void settingsPane_CommandsRequested(Windows.UI.ApplicationSettings.SettingsPane sender, Windows.UI.ApplicationSettings.SettingsPaneCommandsRequestedEventArgs args)
{
    commandHelp = new SettingsCommand("privacy", "Privacy Policy", privacyCommandInvoked);
    args.Request.ApplicationCommands.Add(commandHelp);
}

You’ll need to change the OnLaunched event to call `AddFlyouts();` and you should be set.  

Remember that this will launch a web browser, so you may need to handle the suspend / resume events to deal with that.