Telerik blogs

This is part 4 of the blog series presenting Telerik’s cloud-powered controls for Windows Phone. This post will show you how to easily add user settings to your application and how to get notified about issues that your app may have.

Recap

In the first three parts of these blog series we created the Memories application – an application that allows users to store their most memorable moments in their lives. First we added the user's authentication, then we added the memory items, and last time we allowed the user to extend the memory items with pictures. The application has already covered the specifications that we created in the very beginning, but we won’t stop here. Today we will extend it with more goodies that will make it even better.

Application Settings

When the number of the memories that a user has created with our application increases, it might become difficult for them to find a specific item. In order to solve this we will add sorting and grouping options to the application, that will help users with the organization of the memories according to their own preferences. RadCloudSettingsControl will help us with the settings management. First, let’s add a new class to the Models folder and name it MemoriesSettings. This class will define the settings that our application will use:

MemoriesSettings.cs:
public class MemoriesSettings : EverliveSettings
{
    private SortingOption sortingOption;
    private bool isGroupingEnabled;
    private GroupingOption groupingOption;
 
    public SortingOption SortingOption
    {
        get
        {
            return this.sortingOption;
        }
        set
        {
            if (this.sortingOption != value)
            {
                this.sortingOption = value;
                this.OnPropertyChanged("SortingOption");
            }
        }
    }
    public bool IsGroupingEnabled
    {
        get
        {
            return this.isGroupingEnabled;
        }
        set
        {
            if (this.isGroupingEnabled != value)
            {
                this.isGroupingEnabled = value;
                this.OnPropertyChanged("IsGroupingEnabled");
            }
        }
    }
    public GroupingOption GroupingOption
    {
        get
        {
            return this.groupingOption;
        }
        set
        {
            if (this.groupingOption != value)
            {
                this.groupingOption = value;
                this.OnPropertyChanged("GroupingOption");
            }
        }
    }
}
 
public enum SortingOption
{
    Title,
    Date
}
 
public enum GroupingOption
{
    Year,
    FirstLetter
}

Now that we have the class in the application, we need to define its counterpart on Everlive.com:



The structure of our application settings is ready. Now we need to associate the CloudProvider with this structure. Go to the place where the provider is defined at App.xaml.cs and set the EverliveProviderSettings' SettingsType in the App constructor:

App.xaml.cs:
settings.SettingsType = typeof(MemoriesSettings);

Of course, in order to allow the user to actually change the default settings, our application will need a page where this will happen. Create a new page in the Views folder and call it Settings.xaml. Add an instance of the RadCloudSettingsControl:

Settings.xaml:
<Grid x:Name="LayoutRoot" Background="Transparent">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
 
    <!--TitlePanel contains the name of the application and page title-->
    <StackPanel Grid.Row="0" Margin="12,17,0,28">
        <TextBlock Text="MEMORIES" Style="{StaticResource PhoneTextNormalStyle}"/>
        <TextBlock Text="settings" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
    </StackPanel>
 
    <!--ContentPanel - place additional content here-->
    <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
        <telerikCloud:RadCloudSettingsControl x:Name="settingsControl" >
            <Grid>
                <telerikInput:DataField
                    Header="Sort by"
                    TargetProperty="SortingOption">
                </telerikInput:DataField>
 
                <telerikInput:DataField
                    Header="Enable Grouping"
                    TargetProperty="IsGroupingEnabled">
                    <telerikInput:DataField.CustomEditor>
                        <telerikDataForm:CustomEditor>
                            <CheckBox
                                x:Name="checkBox"
                                telerikDataForm:CustomDataField.IsEditor="True"
                                telerikDataForm:CustomDataField.EditorValuePath="IsChecked" />
                        </telerikDataForm:CustomEditor>
                    </telerikInput:DataField.CustomEditor>
                </telerikInput:DataField>
                     
                <telerikInput:DataField
                    Header="Group by"
                    IsEnabled="{Binding IsChecked, ElementName=checkBox}"
                    TargetProperty="GroupingOption">
                </telerikInput:DataField>
            </Grid>
        </telerikCloud:RadCloudSettingsControl>
    </Grid>
</Grid>
     
<phone:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar>
        <shell:ApplicationBar.Buttons>
            <shell:ApplicationBarIconButton IconUri="/Assets/AppBar/Save.png" Text="save" Click="OnButtonSave_Click" />
            <shell:ApplicationBarIconButton IconUri="/Assets/AppBar/Cancel.png" Text="cancel" Click="OnButtonCancel_Click" />
        </shell:ApplicationBar.Buttons>
    </shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>


Don't forget to map the necessary prefixes:

xmlns:telerikCloud="clr-namespace:Telerik.Windows.Controls.Cloud;assembly=Telerik.Windows.Controls.Cloud"
xmlns:telerikDataForm="clr-namespace:Telerik.Windows.Controls.DataForm;assembly=Telerik.Windows.Controls.Input"
xmlns:telerikInput="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.Input"

Now let’s add handlers for the click events of the ApplicationBar buttons that will make sure that the settings will be saved properly:

 

Settings.xaml.cs:
private async void OnButtonSave_Click(object sender, EventArgs e)
{
    this.settingsControl.Success += OnApplicationSettings_SavedSuccessfully;
    await this.settingsControl.CommitAsync();
}
 
private void OnApplicationSettings_SavedSuccessfully(object sender, EventArgs e)
{
    PhoneApplicationService.Current.State["ReloadSettings"] = true;
    this.NavigationService.GoBack();
}
 
private void OnButtonCancel_Click(object sender, EventArgs e)
{
    this.NavigationService.GoBack();
}

In order to reload the settings when they are changed successfully, we are using an approach similar to the one we used to reload the memories items in RadCloudJumpList when they are updated.

Here’s how the settings page will look:



Now let’s go to the Memories page and add a link to the Settings page in the application bar:

Memories.xaml:
<shell:ApplicationBarMenuItem Text="settings" Click="OnSettings_Click"/>

Memories.xaml.cs:
private void OnSettings_Click(object sender, EventArgs e)
{
    this.NavigationService.Navigate(new Uri("/Views/Settings.xaml", UriKind.RelativeOrAbsolute));
}

Next thing we need to do is to add different group and sort descriptors in RadCloudJumpList depending on the settings of the user, so let's create a method that will actually apply the settings:

Memories.xaml.cs:
private void ApplyApplicationSettings()
{
    MemoriesSettings applicationSettings = CloudProvider.Current.CurrentSettings as MemoriesSettings;
    if (applicationSettings == null)
    {
        return;
    }
 
    this.jumpList.SortDescriptors.Clear();
    if (applicationSettings.SortingOption == SortingOption.Title)
    {
        GenericSortDescriptor<Memory, string> nameSortDescriptor = new GenericSortDescriptor<Memory, string>(memory => memory.Title);
        this.jumpList.SortDescriptors.Add(nameSortDescriptor);
    }
    else
    {
        GenericSortDescriptor<Memory, DateTime> dateSortDescriptor = new GenericSortDescriptor<Memory, DateTime>(memory => memory.Date);
        this.jumpList.SortDescriptors.Add(dateSortDescriptor);
    }
 
    this.jumpList.GroupDescriptors.Clear();
    if (applicationSettings.IsGroupingEnabled)
    {
        if (applicationSettings.GroupingOption == GroupingOption.Year)
        {
            GenericGroupDescriptor<Memory, int> yearDescriptor = new GenericGroupDescriptor<Memory, int>(memory => memory.Date.Year);
            this.jumpList.GroupDescriptors.Add(yearDescriptor);
        }
        else
        {
            GenericGroupDescriptor<Memory, char> firstLetterDescriptor = new GenericGroupDescriptor<Memory, char>(memory => memory.Title.First());
            this.jumpList.GroupDescriptors.Add(firstLetterDescriptor);
        }
    }
}

This method should be called in the constructor of the page and in OnNavigatedTo, in order to apply the settings when they are changed:

Memories.xaml.cs:
public Memories()
{
    InitializeComponent();
    this.ApplyApplicationSettings();
    this.InitializeCloudService();
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
    base.OnNavigatedTo(e);
 
    if (e.NavigationMode == NavigationMode.Back && PhoneApplicationService.Current.State.ContainsKey("ReloadMemories"))
    {
        PhoneApplicationService.Current.State.Remove("ReloadMemories");
        jumpList.ReloadCloudItems();
    }
 
    if (e.NavigationMode == NavigationMode.Back && PhoneApplicationService.Current.State.ContainsKey("ReloadSettings"))
    {
        PhoneApplicationService.Current.State.Remove("ReloadSettings");
        this.ApplyApplicationSettings();
    }
}

Now that we have added the grouping, let’s add a new template for the group pickers that will eventually come up:

Memories.xaml.cs:
<telerikCloud:RadCloudJumpList.GroupPickerItemTemplate>
    <DataTemplate>
        <Grid HorizontalAlignment="Stretch" Height="48" Margin="6">
            <Grid.Background>
                <LinearGradientBrush StartPoint="1,0" EndPoint="0.89,1">
                    <GradientStop Color="Transparent" Offset="0.13"/>
                    <GradientStop Color="#0795B9" Offset="0.13"/>
                </LinearGradientBrush>
            </Grid.Background>
            <TextBlock Text="{Binding}"
                VerticalAlignment="Bottom"
                FontSize="{StaticResource PhoneFontSizeMedium}"
                FontFamily="{StaticResource PhoneFontFamilyLight}"
                Margin="6"
                Foreground="White"/>
        </Grid>
    </DataTemplate>
</telerikCloud:RadCloudJumpList.GroupPickerItemTemplate>
<telerikCloud:RadCloudJumpList.GroupHeaderTemplate>
    <DataTemplate>
        <Grid HorizontalAlignment="Stretch" Height="48" Margin="0, 8, 0, 8">
            <Grid.Background>
                <LinearGradientBrush StartPoint="1,0" EndPoint="0.89,1">
                    <GradientStop Color="Transparent" Offset="0.13"/>
                    <GradientStop Color="#0795B9" Offset="0.13"/>
                </LinearGradientBrush>
            </Grid.Background>
            <TextBlock Text="{Binding}"
                VerticalAlignment="Bottom"
                FontSize="{StaticResource PhoneFontSizeMedium}"
                FontFamily="{StaticResource PhoneFontFamilyLight}"
                Margin="6"
                Foreground="White"/>
        </Grid>
    </DataTemplate>
</telerikCloud:RadCloudJumpList.GroupHeaderTemplate>

Here’s how the Memories page looks after the latest modifications:



Diagnostics

The next thing that we will add to the application is the option to send crash reports if they occur. Our users may not even understand that there is an issue with the application but we will and we will have a chance to fix this issue and release an update. RadCloudDiagnostics will help us to record each exception that occurs while the application is used. To use this component, go to App.xaml.cs and initialize it in the constructor of the App, after the initialization of the CloudProvider:

App.xaml.cs:
RadCloudDiagnostics diagnostics = new RadCloudDiagnostics();
diagnostics.Init();


Just like RadDiagnostics, this component uses ApplicationUsageHelper, which also needs to be initialized when the application starts:

App.xaml.cs:
private void Application_Launching(object sender, LaunchingEventArgs e)
{
    ApplicationUsageHelper.Init("1.0");
}
 
private void Application_Activated(object sender, ActivatedEventArgs e)
{
    ApplicationUsageHelper.OnApplicationActivated();
}

In order to store the reports, you will need to add a new content type on Everlive.com and call it EverliveDiagnosticsInfo as explained with more details here. Now if an exception occurs while someone uses your application, a new record will go to the Cloud and you will be able to prevent further occurrences of this exception.


Conclusion

Today we integrated RadCloudSettingsControl and RadCloudDiagnostics into our Memories application. You can download the full source code of the application with its current progress from here.

If you want to know more about the controls we used in this part, you can visit their online documentation: RadCloudSettingsControl and RadCloudDiagnostics.

Make sure you don’t miss the next and final part of the Memories series blog posts which shows you how to respond to your users’ feedback and how to send them notifications about upcoming updates, new applications and anything else you would like to share with them.

If you still haven’t tried Cloud Controls for Windows Phone, you can go to your Telerik account and download Q2 2013 SP1 which contains the CTP version of these controls. For a better grasp of their capabilities you can download our Examples application which demonstrates their common usages.


TodorPhoto
About the Author

Todor Petrov

Todor Petrov has been with Telerik since 2011, working on the Android and Windows Phone UI suites. He is passionate about technologies, movies and music.

 



Related Posts

Comments

Comments are disabled in preview mode.