window phone 7 InputScope

by ManniAT 22. August 2010 12:58

Shawn Wildermuth made a nice video about Tombstoning.
In this video he also provided some information about InputScope.

In this post I’ll focus on input scopes – and on input in wp7 general.
And I’ll compare it to the iPhone input (keyboard) handling.

First of all what’s this InputScope – in simple words – you can change the behavior of the on screen keyboard by setting this value on an input element (like a TextBox). For this post I’ll always use TextBoxes.

Focusing a TextBox brings up the Keyboard. Depending on the InputScope this Keyboard has different features.
For an example the value TelephoneNumber brings up a keyboard like this:

PhoneNumberKeyboard

But InputScope does more – it also changes other behaviors like suggestions or capitalization.
Here an example which brings suggestions:

ChatKeyboard

It is defined like this: <TextBox InputScope="Chat" />

The thing is beta and some things will hopefully change!
My favorite (to change) is Url Eye-rolling

UrlKeyboard

Looks nice – maybe – lets check with the Microsoft windows phone 7 forum:

http://social.msdn.microsoft.com/Forums/en-US/windowsphone7series

First of all – we can discuss about the need for that big space in Url input.
I would say (maybe I’m wrong) spaces are not so often part of a Url.
So this space key could be smaller to make place for a much more important key the slash.
In the above Url we have 5 slashes – I guess this is worth an extra key.
For the domain you can “touch and hold” the button which brings up a (very short) list of other domains.
iPhone: here you get extra: .eu (yes Europe exists), .us and a “local domain” (like .de for my German iPhone).

Anyhow – domains are not so important – but the slash…
So lets hope this will change till RTM.

Now two words on the differences to the iPhone.
With the iPhone in general you as a developer are fully responsible for handling the keyboard.
There are also “styles” (keyboard layout) – but Correction, Capitalization and so on depend on the system settings, not on the “style”.
Although the keyboard comes up automatically when you focus a TextBox this is more or less everything you get.
The rest has to be done via delegates (in simple words you have to write a “keyboard handler”).
This is even needed for simple things like “dismiss the keyboard”. Tapping somewhere (not on a TextBox) removes the keyboard in wp7 – but not so on the iPhone.

Also you are responsible for situations where the keyboard overlays your content. There is no “auto-scroll into view” like with wp7.

But there are also positive aspects with the iPhone:

  1. Clear button
    A settings which brings up a little button at the right side of a textbox which clears the content
  2. Select text
    Done with a nice magnifier and also (after you have a selection) “changeable” (drag start / end)
    Further there is a “context menu” – “select all” and so on.
  3. Clipboard support
    Simply by tap and hold you can do copy (selected text), paste and so on

Anyhow – we have Silverlight – so we can build or own TextBox which has these features – and even more.
And (except for the Magnifier) it is not much work I guess.

2 Points are left – a short look at the keyboard in the WebBrowser control – and of course some code.

About the WebBrowser control – there is a lot to say – but here I’ll only talk about some “keyboard aspects”.
Working on a port of my RPS iPhone application I have a facebook login page – take a look:

WebBrowserKeyboard

Looks good?
No it does definitely not! At least compared to the iPhone!
On the iPhone I get – a “Next” and a “Previous” button on top of the keyboard.
Further I get a “Done” button which dismisses the keyboard (only important if I find no “free area” to tap).
And – much more important – instead of the return I get an “Open” button.

These “little helpers” enable fast an “Desktop like” input.
Enter email – tap next – enter password – tap open – done.

On wp7 – enter email.
Tap “somewhere” (if “auto-zoom” did work).
Tap password
Tap somewhere
Tap login

With the auto-zoom I mean a look like this:

WebBrowserAZKeyboard
Sometimes when you hit a textbox the WebBrowser brings this up close.

Anyhow – this is beta – so there is hope Smile

Last not least a piece of code to play with the InputScope values.
Create a windows phone 7 application.
In MainPage.xaml add the following to the content grid:

Snippet created with CBEnhancer
<Grid x:Name="ContentGrid" Grid.Row="1">
    <ListBox x:Name="lbScopes">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="200" />
                        <ColumnDefinition Width="270" />
                    </Grid.ColumnDefinitions>
                    <TextBlock Text="{Binding}" VerticalAlignment="Center" />
                    <TextBox InputScope="{Binding}" Grid.Column="1" />
                </Grid>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

Further add a handler for the loaded event of the page.
Add this code to the handler:

Snippet created with CBEnhancer
private void PhoneApplicationPage_Loaded(object sender, RoutedEventArgs e) {
    List<string> m_lE = new List<string>();
    foreach(FieldInfo fI in typeof(InputScopeNameValue).GetFields(
        BindingFlags.Static | BindingFlags.Public)){
        m_lE.Add(fI.Name);
    }
    lbScopes.ItemsSource = m_lE;
}

This brings up a list with all available InputScope values. Simply scroll through the list, focus on of the TextBoxes and you can check what the keyboard does when you use the specific value.

Kudos to Shawn Wildermuth for his great videos and blog posts.

And I’m sure he would end a thing like this with: Makes sense? Thumbs-up

Manfred

Tags: , ,

Silverlight | windows phone 7 | wp7

iAD with Monotouch

by ManniAT 4. July 2010 20:07
Technorati-Tags: ,,

Working on my RPS project (http://iphone.pp-p.net/) I decided (at a late moment) to implement iAd.

But let’s start from the beginning. The design goal for this app was to build a game which can be played with nearby players as well as over the internet.

So my first approach was to implement a form which allows me to pick peers. The result – a lot of “double entries” or only one side seeing the other and things like this.
So the next decision was – 2 forms – one for the internet and for gamekit I’ll use the GKPeerPickerController.

Unfortunately two things happened:

  1. GKPP is also showing double entries (or nothing sometimes)
  2. GKPP force me to turn on Bluetooth

So the problem became even worse – and I decided to go back to my own implementation.
The first approach was to subclass a UIAlertView (which works well) but later the iAD framework took my attention. The idea – it’s could be a boring  situation (waiting for matching players) and that’s from my point of view a good place to show an add which doesn’t annoy the user too much.

But iAD needs a UIViewController – it doesn’t work when you host it in a UIAlertView.
So I changed the things to a “normal” UIViewController which I simply push when needed.

It looks like this:

4List IMG_0331

 

As you can see – the second version shows an add.
My first problem – I couldn’t get the thing running. Messing around for about an hour I got stuck providing format information. My (typical) reaction – joining the MonoTouch IRC channel – and ask stupid questions.

And (within minutes) “kangaroo” confirmed a bug – and help me implementing a workaround.
That’s what I like most with MonoTouch – you have a problem – and get it fixed real fast.
By the way – I had only little problems – and some of them have been my fault.

Anyhow – the documentation about the iAd framework is a bit poor – so I decided to write this post.
To come to a point – after “fixing” the bug (a property returns null) it took me about 2 minutes to implement what you see above – an add at the bottom of my UI.

Here is the relevant code:

Snippet created with CBEnhancer
public class Application {
    static void Main(string[] args) {
        Globals.IsOnOS4 = UIDevice.CurrentDevice.RespondsToSelector(new Selector("isMultitaskingSupported"));
        if(Globals.IsOnOS4) {
            Globals.IsMultitaskingEnabled = UIDevice.CurrentDevice.IsMultitaskingSupported;
        }
        Console.WriteLine("OS4: " + Globals.IsOnOS4.ToString() + " Multi: " + Globals.IsMultitaskingEnabled.ToString());
        UIApplication.Main(args);
    }
}

 

My project is a universal app – so I placed this code in Main.cs – you could also place something like this in you AppDelegate… file at FinishedLaunching.

“Globals” is a static class which holds some information I need all around the project.

Now to the iAd related code in the UIViewController:

Snippet created with CBEnhancer
00 private object m_adBannerView;
01 
02 public override void ViewDidLoad() {
03     base.ViewDidLoad();
04     //boring stuff
05     if(Globals.IsOnOS4) {
06         m_adBannerView = new ADBannerView();
07         ADBannerView adBannerView = m_adBannerView as ADBannerView;
08         NSMutableSet nsM = new NSMutableSet();
09         nsM.Add(new NSString("ADBannerContentSize320x50"));
10         adBannerView.RequiredContentSizeIdentifiers = nsM;
11         adBannerView.AdLoaded += new EventHandler(m_adBannerView_AdLoaded);
12         adBannerView.FailedToReceiveAd += new EventHandler<AdErrorEventArgs>(m_adBannerView_FailedToReceiveAd);
13         adBannerView.Frame = new RectangleF(0, m_uivInner.Frame.Bottom + 9, 320, 50);
14         View.AddSubview(adBannerView);
15         adBannerView.Hidden = true;
16     }
17 }
18 
19 void m_adBannerView_AdLoaded(object sender, EventArgs e) {
20     (m_adBannerView as ADBannerView).Hidden = false;
21 }
22 void m_adBannerView_FailedToReceiveAd(object sender, AdErrorEventArgs e) {
23     (m_adBannerView as ADBannerView).Hidden = true;
24 }

 

First I declared the m_adBannerView – since I was a bit scared if it could make problems on “prior iOS 4” systems I declared it as object.
This explains the code in line 07 – where I use a local variable to prevent me from permanent casting.

Line 09 – a set to tell the AddBannerView which formats I support (the constant in line 09 is because of the bug).
Then two methods I need to implement – AdLoaded (called when an ad is available) and FailedtoReceiveAd.
The second method (although the event parameter is “..Error…”) is nothing more than an information that no ad is there (no matching ad in the inventory, no internet connection, …)

And for the ones curious about line 13 – this m_uivInner is a childview in the blue rectangle which holds buttons, the list and so on.
I use this subview since the same thing is also used on the iPad – but with a different size / location.

Anyhow – the code does 3 very simple things:

  1. It creates the ADBannerView  - telling it that I support portrait mode only (…320x50)
    It adds this view to my UI and hides it
  2. …AdLoaded displays the view
  3. …FailedToReceiveAd hides the view again

Of course I could have used an inline delegate – but I like methods – and these to guys will get some extra code to animate the things. So having the methods isolate gives me more isolation (primarily optical).

Snippet created with CBEnhancer
void m_adBannerView_FailedToReceiveAd(object sender, AdErrorEventArgs e) {
        float fZoom = 0.45f;
        float fAngle = 45;

        UIView.BeginAnimations("HideAdStep1");
        UIView.SetAnimationDelegate(this);
        UIView.SetAnimationCurve(UIViewAnimationCurve.EaseIn);
        UIView.SetAnimationDuration(0.2);
        CGAffineTransform ctZoom = CGAffineTransform.MakeScale(fZoom, fZoom);
        ctZoom.Rotate(ToRadians(fAngle));
        (m_adBannerView as ADBannerView).Transform = ctZoom;
        (m_adBannerView as ADBannerView).Alpha = fZoom;
        UIView.SetAnimationDidStopSelector(new Selector("DoHideAdStep2"));
        UIView.CommitAnimations();
    }
    [Export("DoHideAdStep2")]
    private void DoHideAdStep2() {
        UIView.BeginAnimations("HideAdStep2");
        UIView.SetAnimationDelegate(this);
        UIView.SetAnimationCurve(UIViewAnimationCurve.EaseOut);
        UIView.SetAnimationDuration(0.1);
        (m_adBannerView as ADBannerView).Alpha = 0;
        UIView.CommitAnimations();
    }

 

This is just a simple example – it turns the add (45°) – makes it smaller – and in step 2 it hides it by setting alpha to 0. The reverse thing is done in AdLoaded.

There are other events for the ADBannerView you might be interested.
The ActionFinished (tells you that the user closed the “banner dialog”). This is also available as event on the ADBannerView.
The second thing is (unfortunately not available as event) ActionShouldBegin. To handle this you have to implement you own delegate (just overriding this single method).

In my case I don’t care – a user watches gets bored and clicks the ad. The iAd guide says I should (!!!) disable sounds, animation or other activities that require user interaction.

That’s (almost) what I do – except – if someone invites the user while he watches the ad content I notify him with a sound. My understanding of the iAd guide makes me feel that this is ok.

Manfred

I attached a little sample showing the things.
The iAdTest$.. project is the VS project - the one without the $ signs the MT project.

iAdTest.zip (13.84 kb)

Tags: , ,

iPhone | MonoTouch

telerik RAD Controls for the iPhone / iPad

by ManniAT 31. May 2010 15:55

Technorati-Tags: ,,

Working on iDivine I had to provide an update mechanism for puzzles.
The goal was to provide some kind of web interface where users can select puzzles and download them.

The first idea was to work with web services. This would mean to build an iPhone (iPad) UI which displays the data provided by the service. Since there is no “multi select list” on these devices I would have to implement such a thing. Not that big problem – but it made me think about a different solution.
I also wanted to provide a “normal web view” (just to see the riddles on a website).

And the biggest problem – timing. I wanted to use the expected “application review time” to finish these things.
Then I tried if I could achieve the desired results using an apsx page. And it worked.
At the iPhone / iPad side I needed just to call some java-script functions and a few methods to download content and provide information (installed games list) for the website.

Looking for an easy way to provide a nice looking UI I (of course) took a look at the
telerik RAD controls for ASP.NET Ajax.

The result (on the iPhone) looks like this:

IMG_0315

There is a little scrolling which doesn’t appear on the iPad where this dialog is a bit larger.
The “tricks” I’ve done in this form are two things.

  1. I made the checkboxes bigger
  2. I provided a “details view” to keep the list small without loosing information
    which MAY (not must) be of interest

The details look like this:

IMG_0314

As you can see there is another RAD Control on the details view – RAD Rating.
While the list itself is optimized for the iPad (little scrolling on iPhone) the details are optimized for the iPhone (no scrolling there).

When you have a look at the supported browsers in RAD Controls for ASP.NET Ajax   you won’t find the mobile safari browser. But anyhow – the controls work as expected.

While this page is optimized to be used inside the game (templates) I also use the grid on the “default web interface” without any special adaption for the iPhone / iPad. The following image proofs that rendering works correct without special customization:

IMG_0316

The same view from a PC (IE 8):
iDivineSite1

You can checkout yourself: http://idivine.pp-p.net/GameInfo/RiddleList.aspx

I will have to do some adoptions (notice the bigger text above the list in the upper screenshot) – but notice also that this only affects my own elements where a CSS style makes this to big text.
The telerik RAD Grid looks perfect – without any need for customization.

And since most of my blog post provide at least a little code – here is how the “game page” (download list) has been done. The details page is (to save work) done using the Edit mode of RAD Grid.

Snippet created with CBEnhancer
<ClientSettings Selecting-AllowRowSelect="true" >
        <Selecting AllowRowSelect="True" EnableDragToSelectRows="false" UseClientSelectColumnOnly="true"></Selecting>
        <ClientEvents OnPopUpShowing="PopUpShowing" />
    </ClientSettings>
    <MasterTableView DataKeyNames="GameID" DataSourceID="odsGames" EditMode="PopUp">
    <NoRecordsTemplate>
    <p>Sorry - we found no games for you</p>
    </NoRecordsTemplate>
        <EditFormSettings CaptionDataField="Name" CaptionFormatString="<b>{0}</b>" PopUpSettings-Modal="true" PopUpSettings-Width="290px" PopUpSettings-Height="320px"
        EditColumn-Display="False" EditColumn-Visible="False" />

The first 2 lines bring up the checkboxes to select the puzzles.
Next I set EditMode=”PopUp” – which will show “editing” in a popup window.
And since I need no “Update / Cancel” buttons on this form I set EditColumn-Display=”False”.

There is a little more needed. First some functionality to place the popup:

Snippet created with CBEnhancer
<script type="text/javascript">
    function PopUpShowing(sender, eventArgs) {
        var popUp = eventArgs.get_popUp();
        popUp.style.left = (getScrollWidth() + 3).toString() + "px";
        popUp.style.top = (getScrollHeight() + 6).toString() + "px";
    }
    function getScrollHeight() {
        var h = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
        return h ? h : 0;
    }
    function getScrollWidth() {
        var h = window.pageXOffset || document.body.scrollLeft || document.documentElement.scrollLeft;
        return h ? h : 0;
    }

</script>
And (since I suppressed EditColumn-Display) I needed the close button.

I combined it with the Comment display like this:

Snippet created with CBEnhancer
<telerik:GridTemplateColumn EditFormColumnIndex="0" ItemStyle-Font-Size="11px" Visible="false" EditFormHeaderTextFormat="{0}">
            <EditItemTemplate>
            <div style="border:1px solid green;">
                <uc:CommentDisplay ID="CommentDisplay1" runat="server" TheText='<%#Eval("Comment")%>' Width="180px" FontSize="10px" />
            </div>
            <div style="width:100%;text-align:right"><asp:Button CssClass="BigButton" CommandName="Cancel" runat="server" Text="Close" /></div>
            </EditItemTemplate>
        </telerik:GridTemplateColumn>

It is nothing more than a button with the command name set to “Cancel” (which will cancel “edit” and close the form).

The last element is the “Get selected games button”. Thanks to the “client select interface” of the telerik RAD Grid the code is very easy:

Snippet created with CBEnhancer
protected void btnGetSelected_Click(object sender, EventArgs e) {
        List<int> lSelectedGames = new List<int>();
        lblInfo.Text="";
        foreach(GridDataItem gdI in rgGames.SelectedItems) {
            lSelectedGames.Add((int)gdI.GetDataKeyValue("GameID"));
        }

    }

With this code I get the list of selected games (their IDs) – the rest is easy.

Conclusion: the title of this post is misleading I know – I was kidding a bit.
Of course there are now telerik controls for the iPhone – iPad – but although telerik doesn’t promise that  their ASPX controls work for iPhone / iPad browsers (which are different beasts than desktop Safari) – they do their job pretty perfect.

As far as I remember telerik had a slogan: deliver more than expected

And that is exactly what I (not for the first time) learned with this “let’s simply try it approach” building a UI beyond the scope of a normal web site.

Manfred

Tags: , ,

iPhone | telerik | iPad

AppReviews 1.0.1

by ManniAT 20. April 2010 17:28
Technorati-Tags: ,

Yesterday I posted a simple tool to check application reviews / ratings.

It works fine except:

  1. Applications must be added / removed editing a XML file in the installation directory
  2. To change the stores (set / clear Active-Flag) you must also edit a XML file in the installation directory
  3. Reviews are loaded one Store after the other (not a problem but slow)
  4. Problems with the Japanese Store

So I decided to change this.
First I move the XML files to a location where a user (non admin) has write access.
Next I added two windows holding a RadGridView. Using this telerik control it took me just a few minutes to implement editing of Applications and Stores – including some simple validation.

I did it very simple – just two dialogs with a RadGridView and 2 buttons.
The fix for the Japanese store is also done. It was a parser problem. While usernames in other stores are inside a b tag - they are not in the JP store.

The next thing I changed was about point 3. Instead of loading on store after another I fire all calls to the web on start and collect the results as they are returned from iTunes.

Compared to version 1.0.0 the current version collects data about 30 to 50 times (if only a little number of stores have entries) faster.

Have fun

Manfred

Release1.0.1.zip (1.40 mb)

Tags: ,

iPhone | telerik

Frustration with iTunes Connect and Customer Reviews

by ManniAT 20. April 2010 00:42
Technorati-Tags: ,

Have you ever tried to check what customers are thinking about your iPhone application?

So you may have been at “iTunes Connect / Manage Applications / Customer Reviews“.
And there you find

  1. A combobox with all stores worldwide
  2. A version string (not changeable)
  3. Nothing more

The thing is – you have to select every single store in the combobox, wait until the result is loaded.
And YES in a lot of cases you wait for nothing.
There is no sing of “here is a comment” (like bold entries in the combobox or so), there is no way to get “Ratings” and last not least you can’t retrieve reviews from older versions.

There is a way to get this information. Start iTunes – select a store, select the application…
Not much faster than the iTunes Connect approach – but at least you get “Ratings” and Reviews for older versions.

Frustrated by the situation I built a simple WPF application which does all the things for you.
Checks every store – searches for Ratings and Reviews – and also “older Version” information.

The application is not perfect (strange results for Japanese reviews), but last not least it gives me what I need.

You can download the application from here. I provide it “as it is” labeled with “WOMPC” (works on my PC).

There are two files in the applications installation directory:
Apps.xml (enter your Apps there – one is inside for testing)
AppStores.xml (set IsActive to false if you don’t want to search a particular shop).

Post any feature suggestions here as comment.

Manfred

AppReview1.0.zip (544.11 kb)

Tags:

iPhone

Messing around with the telerik RadTransitionControl

by ManniAT 6. April 2010 14:46
Technorati-Tags: ,,

This series is about a promotion game we built to support our iPhone apps.
You can play the game here – it is “early stage” but you can really win!

For the newcomers – here the things start.
In the previous post I showed how the first steps using the telerik RadTransitionControl.
And I showed what we are trying to achieve.

TE

Here the things start to be a bit more complicated. As I told before we want to play this animation while we search for new twitter entries. Or more technical – while we are in a WCF call.
The first thing – you can not really predict how long it will take till the service call returns.
And even if you could it wouldn’t help. Of course you can set the animation duration, but that means that the animation takes more time (runs slower) which will not really look good.

So what we need are repeated animations.

  • Make the call
  • Start the animation
  • When the animation finishes check if we are still in the call
    If so – restart the animation
    Else – display the new value in the RadGauge

Unfortunately the RadTransitionControl doesn’t inform you when a transition (animation) finished.
And although there is a property “IsTransitioning” it doesn’t do what the name promises.
By the way – there is a second reason why we want to know the end of the transition.
As I wrote before – RadGauge animates value changes. And we want to have this visible.
This means we have to wait until the fade effect ends else it would be hard to see.

A second missing thing is a “start animation” method. The RadTransitionControl starts its animation automatically as soon as the content changes. But in our scenario the content wouldn’t change (always the same RadGauge).
So we also needed to implement this.

OK – the .NET way is to enhance functionality is to derive from the base control. We did it this way:

Snippet created with CBEnhancer
public class MyTransitionControl : RadTransitionControl {
    public event EventHandler OnTransitionFinished;
    DispatcherTimer m_dptWatchTransition;

    #region InTrasition
    public bool InTransition { get; set; }
    #endregion

    public MyTransitionControl() {
        m_dptWatchTransition = new DispatcherTimer();
        m_dptWatchTransition.Tick += new EventHandler(m_dptWatchTransition_Tick);
    }

    void m_dptWatchTransition_Tick(object sender, EventArgs e) {
        m_dptWatchTransition.Stop();
        InTransition = false;
        if(OnTransitionFinished != null) {
            OnTransitionFinished(this, EventArgs.Empty);
        }
    }
    public void StartTransition() {
        if(!InTransition) {    //only if not running
            object o = Content;
            Content = null;
            Content = o;
        }
    }
    protected override void OnContentChanged(object oldContent, object newContent) {
        base.OnContentChanged(oldContent, newContent);
        if(newContent != null) {    //don't watch removing
            m_dptWatchTransition.Interval = Duration;
            m_dptWatchTransition.Start();
            InTransition = true;
        }
    }
}

That’s all. A timer which starts when the content changes. When the timer ends we fire an event.
And we handle a Boolean “InTransition”.
Last not least we provide a “StartTransition” which only changes the content to “nothing” and back to what was in.
This in fact tells the RadTransitionControl to start its animation.

How is this used? Let me explain the general approach:

  • We start a WCF call
  • At the same time we initiate a transition (StartTransition)
  • When ever a transition ends we check if we are still in the WCF call
    If so – we start a new transition
  • If not we assign the new value to the RadGauge

YES – the gauge (to animate) also needs a change – in this case the value must change.
To handle this is also very easy. You remember – as long as we are in a WCF call we have a running transition.
When the call finishes we get an event (the result value changes). In that event we set the value of the RadGauge to 0. We can (almost) be sure that AFTER this the running transition will end.
And there we assign the new value – which shows a nice bar animation.
Here is some code:

Snippet created with CBEnhancer
void App_LastStatusChanged() {
    if(!rtcGauge.InTransition) { //wait to end transition
        EnterStatus();
    }
}
void rtcGauge_OnTransitionFinished(object sender, EventArgs e) {
    if(App.IsUpdatingStatus) {
        rtcGauge.StartTransition();
        return;
    }
    EnterStatus();
}

rtcGauge is the RadTransitionControl which holds the RadGauge. To have this running we only have to assign the event handler which is done like this:

Snippet created with CBEnhancer
rtcGauge.Transition = new WaveTransition { Angle = 0.5, Amplitude = 0.15 };
rtcGauge.OnTransitionFinished += new EventHandler(rtcGauge_OnTransitionFinished);

When you play the game you will see that the product images change. Of course this is also handled by a RadTransitionControl. We simply load a list of images and with a timer we change the content. The nice “move and zoom effect” is done with one line of code:

Snippet created with CBEnhancer
    rtcPromoImages.Transition = new SlideAndZoomTransition { MinZoom = 0.6 };
}
void m_dtImageChanger_Tick(object sender, EventArgs e) {
    if(!m_bImVisible) {
        return;
    }
    m_nCurImageIndex++;
    if(m_nCurImageIndex == m_aImages.Length) {
        m_nCurImageIndex = 0;
    }
    rtcPromoImages.Content = m_aImages[m_nCurImageIndex];
}

The “complicated” function shown after this single line of code does only check the bounds of our image array and then it assigns the next image to the RadTransitionControl.

I need to write a last few words about the RadGauge. First of all I want to show my laziness again and second I want to proof that I’m able to handle binding. After doing so much the “plain .NET way” I’m really afraid some of you might thing – this guy has no idea how Silverlight works Happy

The lazy part – of course I could have “restyled” the RadGauge. Or even I could have built my own custom control derived from RadGauge. Instead I created a user control, set a RadGauge as the only content and changed the look of it in Blend.
The only problem with that approach – I can’t bind a the value like this: Value=”{TemplateBinding TheVal}”. Of course I can’t do this – the control is not a template control; it’s a user control.

But (and here is the “I have a bit Silverlight knowledge” part Happy) User controls can also be data bound.
Here is (a part of) the markup:

Snippet created with CBEnhancer
<gauge:IndicatorList Margin="1,0,0,0">
    <gauge:LinearBar x:Name="linearBar" IsAnimated="true"
                    StrokeThickness="0"
                    BorderBrush="White"
                    StartWidth="0.04"
                    EndWidth="0.04"
                    Location="OverCenter"  Value="100" Opacity="0.82"
                    RangeColorMode="ProportionalLastRangesBrush"
                    RangeColorGradientOrientation="Center"
                    UseRangeColor="True" />
</gauge:IndicatorList>

And to bind the value of “linearBar” I do this in code behind:

Snippet created with CBEnhancer
public partial class DispCurVal : UserControl {
    #region TheValue (DependencyProperty)
    public int TheValue {
        get { return (int)GetValue(TheValueProperty); }
        set { SetValue(TheValueProperty, value); }
    }
    public static readonly DependencyProperty TheValueProperty =
        DependencyProperty.Register("TheValue", typeof(int), typeof(DispCurVal),  new PropertyMetadata(0));
    #endregion
    public DispCurVal() {
        InitializeComponent();
        linearBar.SetBinding(LinearBar.ValueProperty, new Binding() { Source = this, Path = new PropertyPath("TheValue") });
    }
}

Last not least – I didn’t write anything about RadBook we used to display our “game manual”. That is beyond the scope of this series. Just take a look at the telerik site. The control is “old” (which means well documented) and you’ll see that changing a (boring) scroll view with a manual (which nobody reads) to a great looking book is extremely easy with this control.
We did nothing more than to pull a list of objects (icon, topic, page content, and “page number text”) from a WCF service and bind this list to the RadBook.

I hope you enjoyed this series and maybe you’ve learned something new about the brand new and fantastic RadTransitionControl. By the way – the control can do more than that what I showed – give it a try.

And if you found this blog useful – take a look at our Promotion Game.
Although I used the game as an example in this blog – the thing is live; it is working and you can really play it and win prices.
It is “early stage” (maybe we find bugs) – but it’s no demo.
The game is a working thing which shall help us to promote our iPhone apps.

Support us by playing the game here – it is “early stage” but you can really win!

Thank you for reading
Manfred

Tags: , ,

telerik | Silverlight | iPhone

Cool look out of the telerik box

by ManniAT 6. April 2010 13:33
Technorati-Tags: ,,

This series is about a promotion game we built to support our iPhone apps.
You can play the game here – it is “early stage” but you can really win!

Like explained in the previous posts of the series we’ve been building a promotion game for our iPhone apps.
The facts:

  • We have skills on “game mechanics”
  • We have skills on “infrastructure”
  • We have skills on Silverlight
  • We are everything else than designers

Fortunately telerik introduced a new control the RadTransitionControl which helped us a lot with our project.
I already did some work with the RadGauge and the game has a part where this control could help.

Lets talk about this step first. Part (main) of the game is that you (the player) spread information about the promotion. As I wrote before we use twitter as “transport” for this. For us it is important that as much people as possible get informed about the game / product. To motivate the player to spread the news we offer promotion codes as prices.
Each promotion code has its own “win counter” – a number which must be reached to win.
We measure “how much” a player spreads the information via his "follower counter”. Depending on this value (we have limits and calculations behind it) we raise the “Promo code counter”.
The reason that every code has its own counter is to bring some kind of “dynamics” into the game.
The player never knows the number of points needed to reach the goal.

Anyhow – to give the player some feedback we decided to use a RadGauge to display the percentage of the current counter. RadGauge has some kind of animation built in which animates the “needle / bar” when the value changes. But in our scenario this was not enough. As I told before we use a WCF Service to query twitter. This can be a bit (Seconds) time consuming.

From the client perspective two things happen: The search (takes time) and the display of a new value.
I had the idea to simulate some kind of “tuning thing” while we retrieve the new information.
Maybe you remember old films where an actor hits his (monochrome) TV to get a better display.
The display “flickers” and after some time (punches) it becomes sharp. You may have also seen effects like this in “Space Movies” when the video link to the starship is bad.
I think an effect like this reflects best what’s going on behind the scenes – we have “un-sharp” information about the current value and we try to get better ones. Here is what I mean:

TE

We have 3 “pages” in the solution – First a manual, next the game itself and last not least a “popup” when we found a result.
The next thing we wanted to achieve was a “page transition”. Silverlight offers things for this – but RadTransition impressed me so much that I decided to do this also with that control.

We need such a “page transition” 2 times – once when the user starts the game (from manual to game) and a second time when the user clicks the “help button” (from game to manual).

And we need some kind of “popup” to display the game result a soon as we find the entry (tweet made by the player) in twitter.

The popup was very easy – we just used a RadWindow changed its style (we need no border or things like this) and called the “ShowDialog” method of the window.
The window contains a user control with the information. It also has two buttons OK / Cancel. OK ends the game, Cancel keeps the game open (with limited functionality). And the content of the popup depends on what happened. The player won, he did not win, he spammed…
For this our user control offers a function to set the information (yes no binding Happy).

As you may know everything (almost) in Silverlight is asynchronous. So RadWindow will not stop the calling thread. Instead it will fire an events when something happens. For us it is important to know when the window closes. There we have to find out if the user clicked OK or Cancel. Here is the window markup:

Snippet created with CBEnhancer
<telerikNavigation:RadWindow x:Name="rwFoundInfo" CanClose="True" CanMove="False" ResizeMode="NoResize" WindowStartupLocation="CenterOwner" Style="{StaticResource RWInfoStyle}">
    <local:FoundInfoDisplay x:Name="fdFoundDisplay" />
</telerikNavigation:RadWindow>

In code behind we do:

Snippet created with CBEnhancer
    rwFoundInfo.Closed += new EventHandler<WindowClosedEventArgs>(rwFoundInfo_Closed);
    fdFoundDisplay.SetInfoText(strResult, strResultInfo, App.ThePromoInfo.CodePrompt, strCode, App.ThePromoInfo.OKInfo, App.ThePromoInfo.CancelInfo, App.ThePromoInfo.PromoImage, App.ThePromoInfo.PromoTitle);
    rwFoundInfo.ShowDialog();
}
void rwFoundInfo_Closed(object sender, WindowClosedEventArgs e) {
    if(e.DialogResult.HasValue && e.DialogResult.Value) {
        HtmlPage.Window.Navigate(btnResearch.NavigateUri);
    }
}

And the user control in the window does this to handle OK / Cancel:

Snippet created with CBEnhancer
private void btnOK_Click(object sender, RoutedEventArgs e) {
    RadWindow rW = RadWindow.GetParentRadWindow(this);
    rW.DialogResult = true;
    rW.Close();
}

private void btnCancel_Click(object sender, RoutedEventArgs e) {
    RadWindow rW = RadWindow.GetParentRadWindow(this);
    rW.DialogResult = false;
    rW.Close();
}

Very little code, and what we get is a modal (!!) popup which displays information.
OK – some code is not displayed here – it is the (stupid) transfer of values to control content in SetInfoText.
But this is “our problem” – we could have used bindings or other things.

Now back to the RadTransitionControl. We have a user control which holds the surrounding border the background image and the promotion title / icon. In it we display two different things – the manual and the game itself. It looks like this:
HolderManual HolderGame

Our goal was to have two different transitions – one for manual ==> game and the other for game ==> manual.
Here is what I mean (static):

HolderTrans1 HolderTrans2

To do this we needed a bit of code – first the markup (part of it) from the “holder”:

Snippet created with CBEnhancer
<telerik:RadTransitionControl Grid.Row="1" Grid.ColumnSpan="2" x:Name="rtcTrans" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="3,0,0,0">
</telerik:RadTransitionControl>

In Code behind we do the following:

Snippet created with CBEnhancer
public MainPage() {
    InitializeComponent();
    m_fwPTrans = new FlipWarpTransition();
    m_rtTrans = new RollTransition();
    rtcTrans.Transition = m_fwPTrans;
}

We create two “transitions” and assign one to the RadTransitionControl (Manual to Game).
Have a look at the telerik demos to see these animations live.

Snippet created with CBEnhancer
private void UserControl_Loaded(object sender, RoutedEventArgs e) {
    btnHelp.Visibility = Visibility.Collapsed;
    m_ucInfoPages = new InfoPages();
    m_ucInfoPages.StartClicked += new InfoPages.StartClickedDG(ucInfoPages_StartClicked);
    rtcTrans.Content = m_ucInfoPages;
}

void ucInfoPages_StartClicked() {
    if(m_gIC == null) {
        m_gIC = new GameInnerContent();
    }
    rtcTrans.Transition = m_fwPTrans;
    rtcTrans.Content = m_gIC;
    btnHelp.Visibility = Visibility.Visible;
}

private void btnHelp_Click(object sender, RoutedEventArgs e) {
    rtcTrans.Transition = m_rtTrans;
    rtcTrans.Content = m_ucInfoPages;
    btnHelp.Visibility = Visibility.Collapsed;
}

First we hide the “help button” (not needed when we display the manual). Next we create the manual user control assign a handler for the StartButton and simply set it as content of the RadTransitionControl.
The button handlers (Start / Help) are also very easy. They set the wanted transition and assign the Content to the RadTransitionControl. This (content changed) starts the transition automatically.

There is no hidden code or other “magic behind” – except (of course) the one provided by telerik.

As I told you before – the RadTransitionControl if “beta” (CTP) so there are some things missing at the moment. But it is very easy to implement those parts. We needed to do this for our “fade effect”. The things are (a little bit) tricky – so I made an extra post about that.

Stay tuned
Manfred

Tags: , ,

iPhone | Silverlight | telerik

The Silverlight side of life

by ManniAT 5. April 2010 23:33
Technorati-Tags: ,

This series is about a promotion game we built to support our iPhone apps.
You can play the game here – it is “early stage” but you can really win!

Before I wrote about WCF Services – here is the client part of this.
For the newcomers – here is the start of this series.

When we create a reference to a WCF service we get everything we need generated.
So we have the classes we use with the service, methods to invoke the service and so on.

I decided to keep these generated class as they are. The question was WHERE do I call the methods.
Since the service is “not perfectly designed” some calls contain things that are needed in multiple “forms”.

So my decision was to do the things in the application class. And I use simple .NET events and properties to handle WCF calls and their results.
The idea is simple and easy. App has some static properties (and methods) which interact with the WCF service.

A sample:

Snippet created with CBEnhancer
private static PromoInfo m_piThePromoInfo;
public static PromoInfo ThePromoInfo {
    get { return m_piThePromoInfo; }
    private set {
        if(m_piThePromoInfo != value) {
            m_piThePromoInfo = value;
            if(PromoInfoChanged != null) {
                PromoInfoChanged();
            }
        }
    }
}

And the “form” (user control) subscribes to this event (PromoInfoChanged) like this:

Snippet created with CBEnhancer
    App.PromoInfoChanged += new App.EntryChangedDG(App_PromoInfoChanged);
}

#region Promoinfo handling
void App_PromoInfoChanged() {
    SetPromoInfo(App.ThePromoInfo);
}
private void SetPromoInfo(PromoInfo pI) {
    if(pI == m_piLastSet) {    //we got this - nothing new to set
        return;
    }
    m_piLastSet = pI;    //remember it
    string strUriExtend = pI.PromoTweetStartText + App.CallKey + " " + string.Format(pI.SpreadTextAddition, pI.TwitterName);
    //btnFollowMe.NavigateUri = null;

    btnSpread.NavigateUri = new Uri("http://twitter.com/?status=" + HttpUtility.UrlEncode(strUriExtend));
    txtFollowMe.Text = pI.FollowMeText;
    App.SimpleFormatToHTML(pI.FollowMeTextInfo, tbFollowMeInfo);
    txtSpread.Text = pI.SpreadText;

And if the “form” wants to call a WCF method it looks like this:

Snippet created with CBEnhancer
if(!App.IsSearching) {
    if(App.SearchResult()) {
        rtcSearchResults.StartTransition();
    }
}

I know I could do some of these things using binding and dependency properties or “more Silverlight like” methods. But it fulfills my needs in this case and (as you see in the above method) one part of this project is the extended use of the new telerik RadTransistionControl.

The next post will handle this topic – and it will address readers which may not be so familiar with Silverlight as you might be. Since the RadTransitionControl is really new I feel (in my role as telerik MVP) a need to write something about this control which also helps newcomers.
So please excuse my “primitive” handling here.

To finalize the above shown things here the completed handler for the PromoInfo call:

Snippet created with CBEnhancer
void m_tsClient_GetPromoInfoCompleted(object sender, GetPromoInfoCompletedEventArgs e) {
        if(e.Error == null && e.Cancelled == false) {
            ThePromoInfo = e.Result;
        }
    }

That’s it about the WCF Silverlight client. In the next part I’ll show you how simple you can achieve stunning results, cool animations and other things like this – even if you are a “got to be used to designer” like me Happy

Stay tuned
Manfred

Tags: ,

Silverlight | twitter

WCF and the rest

by ManniAT 5. April 2010 22:31
Technorati-Tags: ,,

This series is about a promotion game we built to support our iPhone apps.
You can play the game here – it is “early stage” but you can really win!

As I told before we used Silverlight to implement this game. And we do some UI localization (English, German) using Database Tables with “simple HTML”. I described this here.

I guess most of you know that Silverlight is a client technology. This (among others) means that we have no direct database access.

All we can do must be done with some kind of “Web Server Communication”. There are RIA Services (too enhanced for my simple project) and of course “plain” Windows Communication Foundation – or WCF Services.

That’s what I use. So I have a service which provides a list of “ManualPage entries”.
A manual page has: PageNumber, PageTopic, PageContent and “PageNumberText” (a formatted version of PageNumber).

The service method looks like this:

Snippet created with CBEnhancer
[OperationContract]
public List<PromoManualPage> GetManual(string strLangCode) {
    return (new PromoManual(strLangCode).PageList);
}

The constructor of PromoManual reads the pages from the database and provides it in it’s “PageList” memeber.
This looks good – BUT – there is a but.
Assume a lot of players are online. Every time a new player joins the game we create our instance of PromoManual, retrieve the manual from the database – send it to the client…

How often will this manual change? OK, while development often – you are right. But then? Almost never compared to the frequency of calls to this WCF method.

So it is a good idea to keep the things in memory somehow to prevent heavy (and useless) database access.

Static objects? No – we already have a cool thing for this – the cache!
Our call turns to this:

Snippet created with CBEnhancer
[OperationContract]
[OperationBehavior(AutoDisposeParameters = false)]
public List<PromoManualPage> GetManual(string strLangCode) {
    return (GetCachedManual(strLangCode).PageList);
}

And the method we call looks like this:

Snippet created with CBEnhancer
public static PromoManual GetCachedManual(string strLanguageCode) {
    //return (new PromoManual(strLanguageCode));

    string strCacheName = "PM_" + strLanguageCode;
    Cache cH = HttpRuntime.Cache;
    PromoManual pM = cH[strCacheName] as PromoManual;
    if(pM == null) {
        pM = new PromoManual(strLanguageCode);
        //reflect manual changes after 30 minutes - or simply free memory if the game "sleeps"
        cH.Insert(strCacheName, pM, null, DateTime.UtcNow.AddMinutes(30), Cache.NoSlidingExpiration);
    }
    return (pM);
}

This means we search for PM_xx (xx==Language Code) in the cache. If we don’t find it we create such an object and place it in the cache. In this case I decided to keep the things 30 Minutes in Cache.
So I can update my manual pages (fix typos or whatever) – and after max. 30 minutes the players will see the new version. And if the game “sleeps” (no one plays) I’ll free the memory.

Have you seen the commented line? – That’s for text editing when I want to see changes immediately.

Someone may have noticed that I added an OperationBehaviour to my WCF Method.
The reason for this (I had to learn it the bitter way) – WCF call Dispose if your class implements IDisposable.
While this is a good idea if the object dies (fast resource release) it turn into an enemy when you want to keep your objects in cache.

Our Access to twitter is also cacheable. But it is handled a bit different.

Snippet created with CBEnhancer
public static TwitterAccessor GetCachedTwitterAccessor() {
    string strCacheName = "TWA_Accessor";
    Cache cH = HttpRuntime.Cache;
    TwitterAccessor twA = cH[strCacheName] as TwitterAccessor;
    if(twA == null) {
        twA = new TwitterAccessor();
        cH.Insert(strCacheName, twA, null, Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(10));
    }
    return (twA);
}

The difference is the insert call. Here we don’t use a absolute expiration. Instead we use a sliding expiration.
So as long as someone (within 10 Minutes) calls the accessor from the cache this timer starts again.
There is no need for “absolute” expiration – like with the manual pages.

One last “mystery” about the twitter access. If I search for a new “promotion tweet” I do it like this:

Snippet created with CBEnhancer
private static PromoSearchResult GetSearchResult(string strPromoName, string strEntryCode) {
        PromoList pL = GetCachedPromoList(strPromoName);
        if(!pL.DoesEntryExist(strEntryCode)) {    //we didn't find it
            TwitterAccessor twA = GetCachedTwitterAccessor();
            DateTime dtLastTwitterSearch = twA.GetLastSearchForThisPromo(strPromoName);
            //30 seconds would mean (if full running) 120 calls - 150 are available
            //50 means about 72 calls - thats fine for us - as long as we run not more than TWO promos a time (and fully loaded)
            if(dtLastTwitterSearch.AddSeconds(50) < DateTime.Now) {    //if older than - try to find it
                ulong ulLastPost = pL.GetLastPromoID();
                PromoInfo pI = GetCachedPromoInfo(strPromoName, "en");    //always use english
                List<PromoEntry> lPE = twA.SearchEntries(strPromoName, ulLastPost, pI.PromoTweetStartText);
                if(lPE != null && lPE.Count > 0) {    //we found something
                    pL.HandleTwitterData(lPE, twA);
                }
            }
        }
        return (new PromoSearchResult(strPromoName, strEntryCode));
    }

Notice that I avoid searches due to the “twitter call limit”. YES there are methods that allow me to check the current limit – and linq2twitter supports these methods. But I was lazy and avoided to implement it.
By the way it is not so easy as it looks (what if I have little calls in the beginning – and later massive access?) to implement a real good solution which brings the best (use almost all 150 calls) result.

Of course I could do this – but laziness is not the only reason to avoid it.
As a part of the game you should answer 3 questions – or in other words “learn more about the product”.

Who do you think would do this if he clicks a button – and at the very moment he gets a result?
By the way – this would never happen – twitter search also has some delay.

Anyhow – you do something in the game – I search for it – but I take time to do this – while you search for answers in the game. The balance is not to bad (boring) with less than a minute searches.
And if you follow the game (as I want you to do) – you initiate the call (tweet promotion) – look for the answers and normally I would have found your tweet before you could find the answers.

Two things also to consider – 50 seconds is “worst case” and even if you hit this – the “new PromoSearchResult” contains your result if the twitter search found it in the call 50 seconds before.

A last word about the Cache – always use it in scenarios like this! Online “things” (if successful) may have a lot of calls per second. And (in most cases) it makes no difference for the client if the data is 1 or 3 seconds old.
But it makes a lot of difference for your infrastructure (database and so on).
What I means is – even in situation where data is very volatile – it’s worth to cache for 2 seconds or even one if the load on your server is heavy.

In the next post I’ll handle the Silverlight parts of these WCF service.

Stay tuned
Manfred

Tags: ,

Silverlight | twitter

Twitter infrastructure

by ManniAT 5. April 2010 21:34

Technorati-Tags: ,

This series is about a promotion game we built to support our iPhone apps.
You can play the game here – it is “early stage” but you can really win!

I already told about the background of this series in my first post. And I handled some parts of the infrastructure in the second part.

Now lets focus on the game itself. Again – the primary goal is to spread information about iPhone software.
And we decided to use twitter as carrier for this.

I already played around with twitter before. http://manniat.pp-p.net/TwitterSL/Default.aspx

But this was nothing more than a proof of concept – I didn’t even put content on that page.
Anyhow – the first thing I did was to take a look a the twitter guidelines for “competition games” – yes there is a guideline for this.

Anyhow – I found that what I need was not covered by my previous work.
So I looked around a bit and stumbled into linq2twitter by Joe Mayo.

First of all I love Linq – next it looks as if this project is under active development (some others I found seem more or less to be “frozen”).
Anyhow – I gave it a try – and my first thoughts – there is something missing.

OK – I found something on how to send a direct message – but it looked “a bit strange”:

Snippet created with CBEnhancer
var message = twitterCtx.NewDirectMessage("16761255", "Direct Message Test - " + DateTime.Now);

But (reading the manual sometimes helps) it turned out that almost everything is available using a Linq query.

Snippet created with CBEnhancer
from A in m_twcContext.Status where A.Type == StatusType.Mentions 
&& A.Count == nSearchCount orderby A.StatusID descending select A

This query for an example searches for tweets where your account is mentioned. Since I want to get only a certain number of entries I say A.Count==nSearchCount.

m_twcContext is the “main token” which holds you account info and other things. Simply use it to make your queries. The “strange” thing I wrote about before is that you give twitter API parameters as “conditions” in your Linq statement.

But – after some experience with it you will learn the same as I did: that’s the correct way to do this.
And by the way – sometimes I was confused by my own code. The reason? I had to look twice to find out if I query my SQL Server or twitter Happy

So once again thank you Joe Mayo for sharing this great work.

And last not least a snippet which shows how easy it is to get a list of Mentions.
For those not familiar with the twitter API – you get max 200 entries per call – so if you get exactly 200 entries you have to check if more entries exist. The following code fills a list handling this paging in a simple manner.

Snippet created with CBEnhancer
List<Status> lRet = new List<Status>();
int nSearchCount = 200;
int nPage = 2;    //this is the first number for the second call :)
lTmpErg = (from A in m_twcContext.Status where A.Type == StatusType.Mentions && A.Count == nSearchCount orderby A.StatusID descending select A).ToList();
while(lTmpErg.Count() == nSearchCount) {    //maybe more exists
    lRet.AddRange(lTmpErg);
    lTmpErg = (from A in m_twcContext.Status where A.Type == StatusType.Mentions && A.Count == nSearchCount && A.Page == nPage orderby A.StatusID descending select A).ToList();
    nPage++;
}
if(lTmpErg.Count() > 0) {
    lRet.AddRange(lTmpErg);
}

Sending a direct message is also very simple:

Snippet created with CBEnhancer
public bool SendDirectMessage(string strUser, string strMessage) {
            try {
                if(!m_twAuth.IsAuthorized) {
                    m_twAuth.SignOn();
                }
                m_twcContext.NewDirectMessage(strUser, strMessage);
                return (true);
            }
            catch {
                return (false);
            }
        }

With this I’ll finish the part about the twitter access.
In the next part I’ll talk about the rest of the infrastructure – primarily about WCF and Caching.

Stay tuned
Manfred

Tags:

twitter

Powered by BlogEngine.NET 1.5.0.7

RecentPosts