telerik

Prevent accidentally exit of your Windows Phone SL app (with Telerik RadMessageBox or Toolkit CustomMessageBox)

preventExit

After finally being able to use my dev center account again after three long weeks, I am back into UniShare development. One of the most requested fixes was to not exit the app when users are not at the compose pivot.

Of course I am listening and I found a solution that should fit nearly all possible scenarios. Here is what I did:

        //handle back key press to prevent accidentally exit of the app
        protected async override void OnBackKeyPress(CancelEventArgs e)
        {
            //get the base handler
            base.OnBackKeyPress(e);

            //go back to the first pivot on all other pivots
            if (MainPivot.SelectedIndex != 0)
            {
                MainPivot.SelectedIndex = 0;
                e.Cancel = true;
            }
            //handle app exit
            else if (MainPivot.SelectedIndex == 0)
            {
                //cancel the back button press
                e.Cancel = true;

                //check if bool isExitQuestionCheckBoxChecked is false and the message needs to be displayed
                if (isExitQuestionCheckBoxChecked == false)
                {
                    //show the message box
                    MessageBoxClosedEventArgs args = await RadMessageBox.ShowAsync("Do you really want to exit the app?", MessageBoxButtons.YesNo, null, "don't ask me again, just exit next time", false, true);
                    if (args.ClickedButton == null)
                    {
                        //save check box value (use IsolatedStorage on earlier versions of Windows Phone)
                        App.SettingsStore.isExitQuestionCheckBoxChecked = isExitQuestionCheckBoxChecked;
                        //go back to the app
                        return;
                        
                    }
                    if (args.ButtonIndex == 0)
                    {
                        //set the check box value
                        isExitQuestionCheckBoxChecked = args.IsCheckBoxChecked;
                        //save check box value (use IsolatedStorage on earlier versions of Windows Phone)
                        App.SettingsStore.isExitQuestionCheckBoxChecked = isExitQuestionCheckBoxChecked;
                        //exit the app
                        Application.Current.Terminate();
                        
                    }
                    if (args.ButtonIndex == 1)
                    {
                        //set the check box value
                        isExitQuestionCheckBoxChecked = args.IsCheckBoxChecked;
                        //save check box value (use IsolatedStorage on earlier versions of Windows Phone)
                        App.SettingsStore.isExitQuestionCheckBoxChecked = isExitQuestionCheckBoxChecked;
                        //go back to the app
                        return;
                    }
                }
                //check if bool isExitQuestionCheckBoxChecked is false and the app should be exited
                else if (isExitQuestionCheckBoxChecked == true)
                {
                    Application.Current.Terminate();
                }
            }
        }

 

Let me explain. The first thing I am checking is if the current PivotItem is the one I want to display the message. If not, I am moving the Pivot to it.

The next step is to show the MessageBox and handle the buttons and the CheckBox. If no button is pressed, the codes saves the value false and goes back to the app.

If the Yes-button is pressed, the code saved the value of the CheckBox and exits. Same happens for the No-button.

If the user presses the back button the next time, the isExitQuestionCheckBoxChecked boolean gets checked – if the user does not want the message and checked it, the app exits as expected.

The above snippet uses the RadMessageBox.

When we use Toolkit’s CustomMessageBox, we need a slightly different approach. First, we do not override the OnBackKeyPress event – instead, we declare a new BackKeyPress event in the page’s constructor:

public MainPage()
{
    InitializeComponent();     
    BackKeyPress += MainPage_BackKeyPress;
}

 

Then, add this code to the newly generated event handler:

        //handle back key press to prevent accidentally exit of the app
        void MainPage_BackKeyPress(object sender, System.ComponentModel.CancelEventArgs e)
        {
            //go back to the first pivot on all other pivots
            if (MainPivot.SelectedIndex != 0)
            {
                MainPivot.SelectedIndex = 0;
                e.Cancel = true;
            }
            //handle app exit
            else if (MainPivot.SelectedIndex == 0)
            {   
                ////check if bool isExitQuestionCheckBoxChecked is false and the message needs to be displayed
                if (isExitQuestionCheckBoxChecked == false)
                {
                //generate a CheckBox as Content
                CheckBox chkbox = new CheckBox()
                {
                    Content = "don't ask me again, just exit next time",
                    Margin = new Thickness(0, 14, 0, -2)
                };

                //generate msg and handle the result
                CustomMessageBox msg = new CustomMessageBox()
                {
                    Title = "Attention",
                    Message = "Do you really want to exit the app?",
                    Content = chkbox,
                    LeftButtonContent = "yes",
                    RightButtonContent = "no"
                    
                };

                msg.Dismissed += (s1, e1) =>
                    {
                        switch (e1.Result)
                        {
                            case CustomMessageBoxResult.LeftButton:
                                //save check box value
                                isExitQuestionCheckBoxChecked = (bool)chkbox.IsChecked;

                                //save the check box value
                                if (IsolatedStorageSettings.ApplicationSettings.Contains("isExitQuestionCheckBoxChecked"))
                                {
                                    IsolatedStorageSettings.ApplicationSettings.Remove("isExitQuestionCheckBoxChecked");
                                }
                                IsolatedStorageSettings.ApplicationSettings.Add("isExitQuestionCheckBoxChecked", isExitQuestionCheckBoxChecked);

                                IsolatedStorageSettings.ApplicationSettings.Save();

                                //exit the app
                                Application.Current.Terminate();
                                break;
                            case CustomMessageBoxResult.RightButton:
                                //save check box value
                                isExitQuestionCheckBoxChecked = (bool)chkbox.IsChecked;

                                //save the check box value
                                if (IsolatedStorageSettings.ApplicationSettings.Contains("isExitQuestionCheckBoxChecked"))
                                {
                                    IsolatedStorageSettings.ApplicationSettings.Remove("isExitQuestionCheckBoxChecked");
                                }
                                IsolatedStorageSettings.ApplicationSettings.Add("isExitQuestionCheckBoxChecked", isExitQuestionCheckBoxChecked);

                                IsolatedStorageSettings.ApplicationSettings.Save();

                                //go back to the app
                                break;
                            case CustomMessageBoxResult.None:
                                break;
                            default:
                                break;
                        }
                    };
                    //show message
                    msg.Show();

                    //cancel all BackKey events
                    e.Cancel = true;

                }
                //check if bool isExitQuestionCheckBoxChecked is false and the app should be exited
                else if (isExitQuestionCheckBoxChecked == true)
                {
                    Application.Current.Terminate();
                }
            }
        }

 

This code is taken from a Windows Phone 8 project and does the same as the first snippet by using the Windows Phone Toolkit.

As always, I hope this is helpful for some of you.

Happy coding, everyone!

Posted by msicc in Dev Stories, windev, 0 comments

How to build a custom Application Bar for your Windows Phone app (the easy way)

customappbarexpanded

In one of my recent projects, I was forced to use icons for the ApplicationBarButtons that didn’t fit into the circled template of the standard Windows Phone application bar.

The icons have special circles themselves, and I am not allowed to change anything on that icons (you’re right, it is for the corporate app I am working on). That’s why I needed to find another solution – and I started to write my own “ApplicationBar”.

As I am using Telerik’s Windows Phone Controls, I knew that the RadImageButton have exactly the same behavior than the buttons in the standard ApplicationBar. That point was already save, the only thing I needed to change was the ButtonShape of the RadImageButton from Rectangle to Ellipse – done.

This is the UserControl I created to achieve my goal:

<Border x:Name="customAppBarBorder"  Height="72" VerticalAlignment="Bottom">
    <Grid >
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="80"/>
            <ColumnDefinition Width="80"/>
            <ColumnDefinition Width="80"/>
            <ColumnDefinition Width="80"/>
            <ColumnDefinition Width="80"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"></RowDefinition>
            <RowDefinition Height="Auto"></RowDefinition>
        </Grid.RowDefinitions>

        <telerikPrimitives:RadImageButton x:Name="CustomAppBarRadImageButton1" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" ButtonShape="Ellipse" RestStateImageSource="null" ></telerikPrimitives:RadImageButton>
        <telerikPrimitives:RadImageButton x:Name="CustomAppBarRadImageButton2" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" RestStateImageSource="null" ButtonShape="Ellipse" ></telerikPrimitives:RadImageButton>
        <telerikPrimitives:RadImageButton x:Name="CustomAppBarRadImageButton3" Grid.Row="0" Grid.Column="3" HorizontalAlignment="Center" ButtonShape="Ellipse" RestStateImageSource="null"></telerikPrimitives:RadImageButton>
        <telerikPrimitives:RadImageButton x:Name="CustomAppBarRadImageButton4" Grid.Row="0" Grid.Column="4" HorizontalAlignment="Center" ButtonShape="Ellipse" RestStateImageSource="null"></telerikPrimitives:RadImageButton>

        <Image x:Name="overflowDots" Grid.Row="0" Grid.Column="5" Width="72" Source="/Assets/AppBar/overflowdots.png" VerticalAlignment="Top" HorizontalAlignment="Right" Tap="overflowDots_Tap"></Image>

        <TextBlock x:Name="CustomAppBarButtonItem1Text" Grid.Row="1" Grid.Column="1" Width="72" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Margin="0,-4,0,0" />
        <TextBlock x:Name="CustomAppBarButtonItem2Text" Grid.Row="1" Grid.Column="2" Width="72" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Margin="0,-4,0,0" />
        <TextBlock x:Name="CustomAppBarButtonItem3Text" Grid.Row="1" Grid.Column="3" Width="72" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Margin="0,-4,0,0" />
        <TextBlock x:Name="CustomAppBarButtonItem4Text" Grid.Row="1" Grid.Column="4" Width="72" FontSize="14" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" Margin="0,-4,0,0" />
    </Grid>
</Border>

It was a bit tricky to get all the size to get a similar appearance, but it does look like the original one.

The RadImageButton Control has also a Text that we can enter, but the text was to small or to close to the button, no matter what I did. That’s why there is another row in my Grid with the corresponding text.

You may have recognized the image with the Source “overflowdots.png” above. These are located in the Windows Phone icon folder (in Microsoft SDKs under program files). We need this icon to generate the transition the standard ApplicationBar has. It is done with two simple StoryBoards:

<UserControl.Resources>
    <Storyboard x:Name="FadeCustomAppBarButtonTextIn">
        <DoubleAnimation Storyboard.TargetName="customAppBarBorder"
                         Storyboard.TargetProperty="Height"
                         From="72" To="102" Duration="0:0:0.2"/>
    </Storyboard>

    <Storyboard x:Name="FadeCustomAppBarButtonTextOut">
        <DoubleAnimation Storyboard.TargetName="customAppBarBorder"
                         Storyboard.TargetProperty="Height"
                         From="102" To="72" Duration="0:0:0.2"/>
    </Storyboard>
</UserControl.Resources>

All we need now is a proper EventHandler – the TapEvent of the image inside the control is perfect for that:

private void overflowDots_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
    if (customAppBarBorder.ActualHeight == 72)
    {
        FadeCustomAppBarButtonTextIn.Begin();
    }
    else if (customAppBarBorder.ActualHeight == 102)
    {
        FadeCustomAppBarButtonTextOut.Begin();
    }
}

I am using a Border for the animation because with a Grid it was not as fluent as I wanted. That’s the whole code of the control I created. Let’s have a look at the implementation:

First thing is an additional row in our LayoutRoot Grid,  where we can add our custom app bar control to (set the Height to “Auto”). Add this code to add the app bar:

//declare the control:

public CustomAppBarWP8 customappbar;

//add your data to the app bar:

customappbar = new CustomAppBarWP8();

            customappbar.CustomAppBarBackground = new SolidColorBrush(Colors.Green);

            customappbar.CustomAppBarButtonItem1Text.Text = "test 1";
            customappbar.CustomAppBarButtonItem2Text.Text = "test 2";
            customappbar.CustomAppBarButtonItem3Text.Text = "test 3";
            customappbar.CustomAppBarButtonItem4Text.Text = "test 4";

            customappbar.CustomAppBarRadImageButton1.RestStateImageSource = new BitmapImage(new Uri("Assets/AppBar/microphone.png", UriKind.RelativeOrAbsolute));
            customappbar.CustomAppBarRadImageButton2.RestStateImageSource = new BitmapImage(new Uri("Assets/AppBar/save.png", UriKind.RelativeOrAbsolute));
            customappbar.CustomAppBarRadImageButton3.RestStateImageSource = new BitmapImage(new Uri("Assets/AppBar/delete.png", UriKind.RelativeOrAbsolute));
            customappbar.CustomAppBarRadImageButton4.RestStateImageSource = new BitmapImage(new Uri("Assets/AppBar/questionmark.png", UriKind.RelativeOrAbsolute));

//registering the tap events:

            customappbar.CustomAppBarRadImageButton1.Tap += CustomAppBarRadImageButton1_Tap;
            customappbar.CustomAppBarRadImageButton2.Tap += CustomAppBarRadImageButton2_Tap;
            customappbar.CustomAppBarRadImageButton3.Tap += CustomAppBarRadImageButton3_Tap;
            customappbar.CustomAppBarRadImageButton4.Tap += CustomAppBarRadImageButton4_Tap;

//adding the app bar to the dedicated Grid:
            AppBarGrid.Children.Add(customappbar);

The standard Application Bar does fading out the text on a button tap, so we need to add this line in every tap event. Otherwise, it would remain open all the time.

if (customappbar.ActualHeight == 102)
{
    customappbar.FadeCustomAppBarButtonTextOut.Begin();
}

To get the same result on tapping outside our custom app bar, add the same code to your main Grid’s MouseLeftButtonDown event. This way, you have the same behavior like in the original control.

Additional note: I needed to find a quick way to achieve this, that’s why I may have not been using best practices. I also used the RadImageButton Control to speed things up. I will refine this control when I have more time available for it, as well as add a version without Telerik controls and adding the menu items.

If you have any idea on how to improve this, feel free to left a comment below.

Anyways, you can download the source of the code above here: https://github.com/MSiccDev/CustomAppBar_WP8

As always, I hope this will be helpful for some of you.

Posted by msicc in Dev Stories, windev, 0 comments

How to update a live tile in a background agent with web data on Windows Phone

scheduledtaskWP

In one of my recent projects, I needed to update the live tile of the app via a background agent with data from a WordPress based web site. I did what I always do when implementing a feature I never used before: researching.

I found tons of example on how to update the live tile periodically, but non of them told me how I can use the data from the web site or where I need to put it in.

In the end, it was Jay Bennet, developer of the fantatsic WPcentral Windows Phone app, who gave me the last hint I needed – where do I start the request for the data I need. Thanks to him for that!

Ok, but let’s start in the beginning. When it comes to web based services, you first need a class (or ViewModel) that can hold your data you receive from your service. I explained that already pretty well here. No matter if you are running your request within your app project or in a PCL, it pretty much always works like this.

After stripping of our class out of the JSON string, we are now able to create our request as well as our Background Agent.

The first thing you need to do is to add a Windows Phone Scheduled Task Agent. Create a new project within your app and choose the project type mentioned before. Then, in your main project, add it as a reference (right click on References/Add Reference/Solution => select your background agent project there. That’s it.

No go to your ‘ScheduledAgent.cs’ file and open it. You will find this code in there:

protected override void OnInvoke(ScheduledTask task)
{
  //TODO: Add code to perform your task in background

  NotifyComplete();
}

And thanks to Jay, I know that this is where all the action (not only updating the tile like in all samples I found) happens. This may sound very trivial for those of you who have experience with that, but if you’re new to it, it may hold you back a bit. However, there are a few points you’ll need to take care of:

    • you only have 25 seconds to perform all action here
    • your task will run every 30 minutes, no way to change that
    • scheduled tasks need to be restarted within 14 days after the current start
    • Battery saver and the OS/the user can deactivate the agent
    • there is a long list of what you are not able to do in here (check MSDN)
    • there are memory limits (check MSDN)

all action needs to be finished before NotifyComplete() is called

Based on this information, I created my task as following:

        protected async override void OnInvoke(ScheduledTask task)
        {
        //performing an async request to get the JSON data string        
            PostsFetcher postfetcher = new PostsFetcher();
            Constants.latestPostsForLiveTileFromWordPressDotComResultString = await postfetcher.GetLatestPostFromWordPressDotComForLiveTileOnPhone();

        //deserialize all data
            var lifetileBaseData = JsonConvert.DeserializeObject<json_data_class_Posts.Posts>(Constants.latestPostsForLiveTileFromWordPressDotComResultString);

            Deployment.Current.Dispatcher.BeginInvoke(() =>
            {
        //using Telerik's LiveTileHelper here
                Uri launchUri = new Uri("Mainpage.xaml", UriKind.Relative);
                RadFlipTileData fliptileData = new RadFlipTileData();
                fliptileData.BackContent = lifetileBaseData.posts[0].title;
                fliptileData.WideBackContent = lifetileBaseData.posts[0].title;
                fliptileData.BackTitle = string.Format("{0} {1}", DateTime.Now.ToShortDateString(), DateTime.Now.ToShortTimeString());
                fliptileData.Title = "LiveTileTitle";               

                if (lifetileBaseData.posts[0].featured_image != string.Empty)
                {
                    fliptileData.BackgroundImage = new Uri(lifetileBaseData.posts[0].featured_image, UriKind.RelativeOrAbsolute);
                    fliptileData.WideBackgroundImage = new Uri(lifetileBaseData.posts[0].featured_image, UriKind.RelativeOrAbsolute);
                    fliptileData.BackBackgroundImage = new Uri("Images/BackBackground.png", UriKind.RelativeOrAbsolute);
                    fliptileData.WideBackBackgroundImage = new Uri("Images/WideBackBackground.png", UriKind.RelativeOrAbsolute);
                }
                else
                {
                    fliptileData.BackgroundImage = new Uri("Images/PlaceholderBackgroundImage.png", UriKind.RelativeOrAbsolute);
                    fliptileData.WideBackgroundImage = new Uri("Images/PlaceholderWideBackgroundImage.png", UriKind.RelativeOrAbsolute);
                    fliptileData.BackBackgroundImage = new Uri("Images/BackBackground.png", UriKind.RelativeOrAbsolute);
                    fliptileData.WideBackBackgroundImage = new Uri("Images/WideBackBackground.png", UriKind.RelativeOrAbsolute);
                }

                foreach (ShellTile tile in ShellTile.ActiveTiles)
                {
                    LiveTileHelper.UpdateTile(tile, fliptileData);
                }
            });

            NotifyComplete();
        }

As I fetch different data from the site, I create a class that holds all request methods. In those methods, I just created an HttpClient that downloads the desired Json string into my app. I take only the first post in the case above, to make the live tile updating also on slow internet connections within the 25 seconds and to not reach any memory limit. In the end, I use Telerik’s LiveTileHelper to create a FlipTile with image and text from the site (the image will be downloaded automatically).

That’s all we need to to in the Scheduled Task Agent. Now we need to implement the agent into our app project.

First thing we should implement is a switch where the user can turn our agent on and off. I used a ToggleSwitch for that, saving the isChecked state as a Boolean to the IsolatedStorage of my app.

Knowing I need to restart the background agent after some time, I implemented the agent handling in App.xaml.cs. This way, I need to write less code as I tend to use separate settings pages. The only thing you need to think of is to set up all objects as static and public.

First, we need to declare a PeriodicTask as well as a name for it:

public static PeriodicTask LiveTileUpdaterPeriodicTask; 
public static string LiveTileUpdaterPeriodicTaskNameString = "LiveTileUpdaterPeriodicTaskAgent";

Now we need to generate a method that handles everything for our background task:

       public static void StartLiveTileUpdaterPeriodicTaskAgent()
        {
        //declare the task and find the already running agent
            LiveTileUpdaterPeriodicTask = ScheduledActionService.Find(LiveTileUpdaterPeriodicTaskNameString) as PeriodicTask;

            if (LiveTileUpdaterPeriodicTask != null)
            {
        //separate method, because we need to stop the agent when the user switches the Toggle to 'Off'
                StopLiveTileUpdaterPeriodicTaskAgent();
        //contains:
        //try
                //{
                //  ScheduledActionService.Remove(App.LiveTileUpdaterPeriodicTaskNameString);
                //}
                //catch { }
            }

        //generate a new background task 
            LiveTileUpdaterPeriodicTask = new PeriodicTask(LiveTileUpdaterPeriodicTaskNameString);

        //provide a description. if not, your agent and your app may crash without even noticing you while debugging
            LiveTileUpdaterPeriodicTask.Description = "This background agent checks every 30 minutes if there is a new blog post.";

        //start the agent and error handling
            try
            {
                ScheduledActionService.Add(LiveTileUpdaterPeriodicTask);
            }
        catch (InvalidOperationException exception)
            {
        //user deactivated or blocked the agent in phone settings/background tasks. Ask him to re-activate or unblock it
                if (exception.Message.Contains("BNS Error: The action is disabled"))
                {
                    RadMessageBox.ShowAsync("it seems you deactivated our Background Agent for the Live Tiles. Please go to settings/background tasks to activate our app again.", "Whoops!", MessageBoxButtons.OK);
                }

        //the maximum of running background agents is reached. No further notification to the user required, as this is handled by the OS
                if (exception.Message.Contains("BNS Error: The maximum number of ScheduledActions of this type have already been added."))
                {
                    //changing the Boolean to false, because the OS does not allow any new taks
                    isLiveTileActivated = false;
                }
            }
            catch (SchedulerServiceException)
            {
                //if there is a problem with the service, changing the Boolean to false. 
        //feel free to inform the user about the exception and provide additional info
                isLiveTileActivated = false;
            }
        }

In Application.Launching() and in ToggleSwitch_Checked event, call this method. In ToggleSwitch_UnChecked event, call ‘StopLiveTileUpdaterPeriodicTaskAgent()’ instead to stop the agent.

Before we are now able to debug our agent, there are two things left. The first thing is to declare

#define DEBUG_AGENT

in the very first line of ‘App.xaml.cs’ as well as in ‘ScheduledAgent.cs’ before all using statements.

The second thing is adding an if-Debug command to our ‘StartLiveTileUpdaterPeriodicTaskAgent()’ and also to our ‘OnInvoke(ScheduledTask task)’ methods:

#if(DEBUG_AGENT)
 ScheduledActionService.LaunchForTest(LiveTileUpdaterPeriodicTaskNameString, TimeSpan.FromSeconds(60));
 #endif

Add this after adding the task to the SchedulerService in our agent starter and before ‘NotifyComplete()’ in ‘ScheduledAgent.cs’.

If you run the project now in Debug mode, your agent will be debugged and forced to run after 60 seconds. If you run the project in Release mode, Visual Studio will throw an ‘Access Denied’ error, so make sure you set it up correctly.

If you follow all steps above, you will be able to add a Live Tile updated via background agent very easily to your app.

As always, I hope this real world scenario will help some of you.

Until then, happy coding!

Posted by msicc in Dev Stories, windev, 7 comments

How to modify the Background of a Telerik RadListPicker Control

In one of my current projects, I needed to change the Background of the Popup on a Telerik RadListPicker control. While it took me some time, I want to share how to achieve that to make it easier for you.

First, you need to create a copy of the RadListPicker Template. You can use either Blend or Visual Studio 2012 to achieve this.

In Blend just go to the menu and choose Object -> Edit Style -> Edit a Copy. In Visual Studio, right click on your RadListPicker in the Designer Window and choose Edit Template -> Edit a Copy.

Now you will find a new Style within your Application.Resources in App.xaml.

To change the style you have to modify two parts, the PopupHeader and the Popup itself.

To change the Background of the PopupHeader search for telerikPrimitives:RadWindow x:Name=”Popup” . Under that, you will find a Grid.

In this Grid, you will need to set the Background to the desired Color or Brush you want to use:

<Grid Background="#FF0A0D38" telerik:RadTileAnimation.ContainerToAnimate="{Binding ., ElementName=PopupList}">

To change the Background of the List in you ListPicker, you will have to style the Background of the underlying RadDataBoundListBox Control:

<telerikPrimitives:RadDataBoundListBox x:Name="PopupList" CheckModeDeactivatedOnBackButton="False" DisplayMemberPath="{TemplateBinding DisplayMemberPath}" IsCheckModeActive="{Binding SelectionMode, Converter={StaticResource SelectionModeToBooleanConverter}, RelativeSource={RelativeSource TemplatedParent}}" telerik:InteractionEffectManager.IsInteractionEnabled="True" ItemContainerStyle="{TemplateBinding PopupItemStyle}" Grid.Row="1" Style="{TemplateBinding PopupStyle}">
   <telerikPrimitives:RadDataBoundListBox.Background>
      <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
          <GradientStop Color="#FF0A0D38" Offset="0"/>
          <GradientStop Color="#FF9FCFEC" Offset="1"/>
      </LinearGradientBrush>
   </telerikPrimitives:RadDataBoundListBox.Background>
</telerikPrimitives:RadDataBoundListBox>

As you can see, the I changed the Background to a GradientBrush to match the rest of the application.
The result looks like this:

wp_ss_20131021_0001

As always, I hope this will be helpful for some of you.

Happy coding!

Posted by msicc in Dev Stories, windev, 1 comment

Use Telerik RadControls for WP? Then use RadDiagnostics to enable users to find bugs!

I know this is a little provocative title – that is my intention. And of course I will tell you why.

I am participating in several betas for Windows Phone apps. I know some of the developers from Twitter, and had several conversations  about bug finding and solving methods. In the end, we as developers have all one goal: a buttery smooth running app without any bugs.

Some of the betas I use are also using Telerik RadControls. They enable us developers to easily create awesome apps without writing the controls form the ground up. On Top, we are able to customize them for our needs with a bit of XAML manipulation.

One of these controls is RadDiagnostics. RadDiagnostics is catching all unhandled exceptions from your application. And believe me, there will be a ton of it – even if you handle a lot of them already.

I didn’t believe that, too. But then I ran the beta of my TweeCoMinder app for Windows Phone. I tested the app a lot before publishing my beta, including several scenarios like no network connection available, low battery, and so on. At this time, I stumbled over the RadDiagnostics Control in the documentation.
I immediately saw the advantages of using this control:

  • advanced error logging, including a great bunch of information like OS Version, device, network type, and more
  • the app won’t crash even on unhandled exceptions
  • the user feels more integrated in the development process
  • users tend to use the app in other ways than we developers think – and we can’t even get close to catch all those usage scenarios while testing alone
  • there are a lot of users that are really searching for bugs – which is both a good and a bad thing

Let me hook into the last point a bit deeper – as we are able to get the most from it. If users find bugs, they will get either annoyed and stop using our apps or they will talk about it. Let us make them talk about the problems to us, the developer! Like I mentioned above, the RadDiagnostics control makes this very easy for the user.

A MessageBox shows up where the user is asked to send us the report, which is done via email. This has two additional advantages: First, we are able to collect all kind of errors. An even bigger advantage: We are able tor respond directly to the user as we have their mail address. I learned a lot during the first beta versions of TweeCoMinder, be it how users use my app as well as from the coding part – and I was able to continuously improve my app.

Some of you might argue that you don’t want the user to see your code. Really, that is stupid. An average user does not even know what all those lines in of the exception mean. Only developers are able to understand what is going on. Where is the problem? That they see you have an exception at point x? Chances are very high, that they had the same exception at another point and needed them to iron out.

Personally, I don’t have a problem with the fact that the exception is readable for some beta tester/users. I made the experience that users love to give feedback – if you make it very easy for them. RadDiagnostics is a very easy way as it needs only three taps (ok => choose mail account => send button).

As this is a dev post, here is how easy it is to integrate it into your app:

  • Declare the RadDiagnostics in public partial class App : Application
    public RadDiagnostics diagnostics;
  • Initiate Telerik ApplicationUsageHelper in private void Application_Launching(object sender, LaunchingEventArgs e)
ApplicationUsageHelper.Init("0.9.5");
  • call RadDiagnostic in the App() constructor:
diagnostics = new RadDiagnostics();
 {
diagnostics.EmailTo = "yourmail@outlook.com";
diagnostics.EmailSubject = "Here is your email subject";
diagnostics.HandleUnhandledException = true;
diagnostics.Init();
 }

That’s all you need to get it working. A few line of codes that will give you so much input to improve your app, which will result in this message:

ReadDiagnosticsMSG

Once again, if you use RadControls for Windows Phone, then use RadDiagnostics to let users help you finding bugs. You will not get better and more helpful feedback other than this!

You can find the complete documentation of RadDiagnostics here: http://www.telerik.com/help/windows-phone/diagnostics-gettingstarted.html

Another great article that helps you to deeply understand how RadDiagnostics work is over at Kunal Chowdhury’s blog.

Feel free to discuss your sight below in comments. Until then, Happy coding!

Posted by msicc in Dev Stories, windev, 0 comments

How to use and customize “pull to refresh” on Telerik RadDataBoundListBox

If you are following me and my development story a little bit, you know that I am building a new app (ok, it’s RTM already).

I wanted to add a manual refresh button to my MainPage, but there was no place left on the AppBar. So I started thinking about alternatives. As I am using a lot of Telerik controls, I found something that perfectly suits my needs: RadDataBoundListBox .

Wait… what?

You read it right, I am using a ListBox that holds only one item. The reason is very easy: It has the “pull to refresh” feature built in. But it is not all about adding it and you are fine.

raddataboundlistbox-features-pulltorefresh

The first thing we need to do is to set the “IsPullToRefreshEnabled” property to “True”. Honestly I don’t like the controls arrow as well as I wanted to remove the time stamp line on it.

Luckily, we are able to modify the control’s style. Just right click on the RadDataBoundListBox in the designer window and extract the “PullToRefreshIndicatorStyle”.

Screenshot (187)

After choosing whether you want the new Style to be available only on one page or in your app over all, name the new Style as you like. This will add the XAML code as a new style to your application/page resources. Now the fun begins. The first thing I changed was the arrow.

To do this,  I added the beloved metro arrow in a circle (go for the “ContentPresenter  with the name “PART_Indicator””) – done:

<Viewbox xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<Grid>
 <Grid Name="backgroundGrid" Width="48" Height="48" Visibility="Visible">
   <Path Data="M50.5,4.7500001C25.232973,4.75 4.75,25.232973 4.7500001,50.5 4.75,75.767029 25.232973,96.25 50.5,96.25 75.767029,96.25 96.25,75.767029 96.25,50.5 96.25,25.232973 75.767029,4.75 50.5,4.7500001z M50.5,0C78.390381,0 101,22.609621 101,50.5 101,78.390381 78.390381,101 50.5,101 22.609621,101 0,78.390381 0,50.5 0,22.609621 22.609621,0 50.5,0z" Stretch="Fill" Fill="#FFF4F4F4" Name="Stroke" Visibility="Visible" />
     </Grid>
       <Path Data="F1M-224.887,2277.19L-240.615,2261.47 -240.727,2261.58 -240.727,2270.1 -226.173,2284.66 -221.794,2289.04 -202.976,2270.22 -202.976,2261.47 -218.703,2277.19 -218.703,2235.7 -224.887,2235.7 -224.887,2277.19z" Stretch="Uniform" Fill="#FFFFFFFF" Width="26" Height="26" Margin="0,0,0,0" RenderTransformOrigin="0.5,0.5">
         <Path.RenderTransform>
             <TransformGroup>
                <TransformGroup.Children>
                  <RotateTransform Angle="0" />
                     <ScaleTransform ScaleX="1" ScaleY="1" />
                 </TransformGroup.Children>
              </TransformGroup>
          </Path.RenderTransform>
   </Path>
</Grid>
</Viewbox>

No we are going to  remove the time stamp. If you simply delete the TextBlock, you will get a couple of errors. The TextBlock is needed in the template. What works here is to set the Visibility to Collapsed. As the control has different Visual States, we need to set the Visibility of every occurrence of  “PART_RefreshTimeLabel” in every state to collapsed. Finally we need to do the same at the TextBlock itself to hide the time stamp line.

Ready… or not?

Now we have our style ready to be used, right? Let’s have a look how it looks when we are using our control right now:

(link for app users)

As you can see, the behavior of the Pull to refresh – control is not like expected. In this state, we have to throw it up first, then it will recognize the pull gesture. To get rid of this, we need to adjust two additional things.

The first thing we need to do is set the “UseOptimizedManipulationRouting” property to “False”.

Second, after setting the ItemsSource of the RadDataBoundListBox, we need to bring the first item into view. You can do this very easily:

RadDataBoundListBox.BringIntoView(ItemsSourceName.First());

After that, we have finally a customized and smooth Pull to refresh function on our RadDataBoundListBox:

(link for app users)

At this point I want to give a special thanks to Lance and Deyan from Telerik for their awesome support on this case.

Happy coding everyone!

Posted by msicc in Dev Stories, windev, 0 comments