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.
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.
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:
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"
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();
}
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"
/>
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:
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:
private
void
Application_Launching(
object
sender, LaunchingEventArgs e)
{
ApplicationUsageHelper.Init(
"1.0"
);
}
private
void
Application_Activated(
object
sender, ActivatedEventArgs e)
{
ApplicationUsageHelper.OnApplicationActivated();
}
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.