Ca y est le market place a ouvert ses portes, il est désormais possible de soumettre ses applications.
La soumissions d’une application sur le market place est soumis à une certification auprès de Microsoft qui va accepter ou refuser votre application, le refus de l’application est basée sur le non respect des contraintes décrites dans la documentation que l’on peut retrouver sur le portail http://developer.windowsphone.com ou directement ici http://go.microsoft.com/?linkid=9730558.
En tout premier lieu pensez à la lire ! cela vous évitera de gros désagrément en cas de refus de votre application.
Vous retrouverez les 10 trucs pour passer facilement une certification sur le blog de Pierre Cauchois http://blogs.msdn.com/b/pierreca/archive/2010/10/08/10-trucs-pour-passer-facilement-la-certification.aspx
Je vais compléter son post sur deux points nécessaires afin de passer la certification avec succès qui sont :
- Le bouton back doit être fonctionnel et son comportement ne doit pas être modifié
- En cas de réception d’un appel la reprise de l’application doit être fonctionnelle
Pour résoudre ces problèmes j’apporterai d’une part une solution reposant sur MVVM (obligatoire! dépêchez vous de vous y mettre si ce n’est pas encore le cas RodH vous explique comment faire http://london.tequilarapido.com/creer-votre-premiere-application-windows-phone-7-en-mvvm/ ) ainsi que sur IsolatedStorage, permettant de gérer très facilement ces deux points.
Je montrerai ce que l’on serait tenter de faire et qui ne fonctionne pas et je proposerai la solution.
Concernant le premier point :
Par exemple si l’on navigue sur plusieurs “pages” de l’application et que l’on appuie sur le boutons “home”, le fais d’appuyer sur le bouton back doit impérativement nous faire revenir à la page précédente, si l’on appuie encore a nouveau sur back à la page précédente encore et ainsi de suite. Que cela implique t’il?
- cela implique pour le développeur de reconstruire le context de la page (le model)
Démarrons notre exemple, pour cela récupérer le projet ici, c’est un simple projet de type windows phone application avec une liste et une page de détails.
Ouvrez la solution et publiez le résultat est le suivant.
Ce que nous souhaitons faire, c’est au click sur un élément de la liste accéder a son détails.
Etape 1 :
Pour cela nous allons rajouter une propriété dans le ViewModel :
1: #region Property Student SelectedStudent
2: private Student selectedStudent;
3: /// <summary>
4: /// Attribut SelectedStudent
5: /// </summary>
6: public Student SelectedStudent
7: {
8: get { return selectedStudent; }
9: set
10: {
11: if (selectedStudent != value)
12: {
13: selectedStudent = value;
14: OnPropertyChanged(SelectedStudentPropertyName);
15: }
16: }
17: }
18: /// <summary>
19: /// Constante SelectedStudentPropertyName
20: /// </summary>
21: public const string SelectedStudentPropertyName = "SelectedStudent";
22: #endregion
Etape 2 :
Ajoutons maintenant le binding de cette propriété sur le SelectedItem
1: <ListBox ItemsSource="{Binding Students}" SelectedItem="{Binding SelectedStudent,Mode=TwoWay}">
2: <ListBox.ItemTemplate>
3: <DataTemplate>
4: <Grid Margin="0,0,0,12">
5: <Grid.ColumnDefinitions>
6: <ColumnDefinition Width="100"/>
7: <ColumnDefinition Width="12"/>
8: <ColumnDefinition Width="*"/>
9: </Grid.ColumnDefinitions>
10: <Image Grid.Column="0" Source="{Binding Image}"/>
11: <StackPanel Grid.Column="2">
12: <TextBlock Text="{Binding Name}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeLarge}"/>
13: <StackPanel Orientation="Horizontal">
14: <TextBlock Text="{Binding Age}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
15: <TextBlock Text=" ans" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
16: </StackPanel>
17: </StackPanel>
18: </Grid>
19: </DataTemplate>
20: </ListBox.ItemTemplate>
21: </ListBox>
Etape 3 :
Maintenant attachons nous à l’évènement OnPropertyChanged afin de détecter quand la propriété SelectedStudent est modifiée pour déclencher la navigation vers la page /View/Details.xaml
1: void List_Loaded(object sender, RoutedEventArgs e)
2: {
3: var vm = DataContext as ListViewModel;
4: vm.GetData();
5: vm.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(vm_PropertyChanged);
6: }
7:
8: void vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
9: {
10: if (e.PropertyName == ListViewModel.SelectedStudentPropertyName)
11: {
12: var vm = DataContext as ListViewModel;
13: if (vm.SelectedStudent != null)
14: {
15: NavigationService.Navigate(new Uri("/View/Details.xaml",UriKind.Relative));
16: }
17: }
18: }
Publiez et cliquez sur un élément vous accéder à la page de détails
Etape 4 :
Maintenant affichons les données, pour cela nous allons placer le même DataContext que sur List.xaml afin de récupérer le même ViewModel donc la propriété SelectedItem :
1: <phone:PhoneApplicationPage
2: x:Class="WindowsPhoneApplication1.View.Details"
3: xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
4: xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
5: xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
6: xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
7: xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
8: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
9: FontFamily="{StaticResource PhoneFontFamilyNormal}"
10: FontSize="{StaticResource PhoneFontSizeNormal}"
11: Foreground="{StaticResource PhoneForegroundBrush}"
12: DataContext="{StaticResource ListViewModel}"
13: SupportedOrientations="Portrait" Orientation="Portrait"
14: mc:Ignorable="d" d:DesignHeight="768" d:DesignWidth="480"
15: shell:SystemTray.IsVisible="True">
Etape 5 :
Et affichons les données dans /View/Details.xaml :
1: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
2: <Grid.ColumnDefinitions>
3: <ColumnDefinition Width="100"/>
4: <ColumnDefinition Width="12"/>
5: <ColumnDefinition Width="*"/>
6: </Grid.ColumnDefinitions>
7: <Image Grid.Column="0" Source="{Binding SelectedStudent.Image}"/>
8: <StackPanel Grid.Column="2">
9: <TextBlock Text="{Binding SelectedStudent.Name}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeLarge}"/>
10: <StackPanel Orientation="Horizontal">
11: <TextBlock Text="{Binding SelectedStudent.Age}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
12: <TextBlock Text=" ans" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
13: </StackPanel>
14: </StackPanel>
15: </Grid>
Publiez votre solution et vous obtenez ce résultat dans le détails :
C’est superbe ! Nous pourrions dire que c’est terminé, mais maintenant que vous êtes sur le détails je vous propose d’appuyer sur la touche “home” afin de sortir de l’application et ensuite de faire un “back” et la ouchhhhhhh !!!!!! :
Et oui lors du back sur l’application seul la View à été chargée, du coup le ViewModel associé était vide donc plus d’affichage de donner, sur cette exemple extrêmement minimaliste, l’application n’a pas planté, mais imaginer si dés traitements avait été effectuer sur des données présentes dans le ViewModel l’application aurait très certainement plantée.
Comment faire????
Pour cela revenons à l”étape 3,nous allons passer en parametre l’objet afin de le récupérer dans le OnLoaded de la vue Details.xaml. Et créer une autre propriété dans le ViewModel.
Pour cela il nous suffit de le serializer l’enregistrer dans l’IsolatedStorage et de passer le nom du fichier ainsi stocké dans l’url.
Etape 6 :
On sauvegarde le paramètre à passer, on on rajoute le nom du fichier en paramètre :
1: void vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
2: {
3: if (e.PropertyName == ListViewModel.SelectedStudentPropertyName)
4: {
5: var vm = DataContext as ListViewModel;
6:
7: if (vm.SelectedStudent != null)
8: {
9: string fileName = "SelectedStudent";
10: using (var store = IsolatedStorageFile.GetUserStoreForApplication())
11: {
12: if (!store.FileExists(fileName))
13: {
14: using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Create, FileAccess.Write, store))
15: {
16: DataContractSerializer dcs = new DataContractSerializer(typeof(Student));
17: dcs.WriteObject(stream, vm.SelectedStudent);
18: }
19: }
20: else
21: {
22: using (var stream = new IsolatedStorageFileStream(fileName, FileMode.Create, FileAccess.Write, store))
23: {
24: DataContractSerializer dcs = new DataContractSerializer(typeof(Student));
25: dcs.WriteObject(stream, vm.SelectedStudent);
26: }
27: }
28: }
29: NavigationService.Navigate(new Uri("/View/Details.xaml?data=SelectedStudent", UriKind.Relative));
30: }
31: }
32: }
Etape 7 :
Maintenant dans le Loaded de la vue Details.xaml, récupérons le paramètre passé dans les querystrings :
1: void Details_Loaded(object sender, RoutedEventArgs e)
2: {
3: Student StudentInParameter = null;
4: if (NavigationContext.QueryString.ContainsKey("data"))
5: {
6: string FileName = NavigationContext.QueryString["data"];
7: using (IsolatedStorageFile isf = IsolatedStorageFile.GetUserStoreForApplication())
8: {
9: if (isf.FileExists(FileName))
10: {
11: using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(FileName, System.IO.FileMode.Open, isf))
12: {
13: var reader = new StreamReader(stream);
14: string content = reader.ReadToEnd();
15: StudentInParameter = SerializeHelpers.Deserialize<Student>(content);
16: }
17: }
18: }
19: }
20: var vm = DataContext as ListViewModel;
21: vm.DetailsStudent = StudentInParameter;
22: }
On ajuste les bindings de la vue Details.xaml
1: <Grid x:Name="LayoutRoot" Background="Transparent">
2: <Grid.RowDefinitions>
3: <RowDefinition Height="Auto"/>
4: <RowDefinition Height="*"/>
5: </Grid.RowDefinitions>
6:
7: <!--TitlePanel contains the name of the application and page title-->
8: <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
9: <TextBlock x:Name="ApplicationTitle" Text="DETAILS" Style="{StaticResource PhoneTextNormalStyle}"/>
10: <TextBlock x:Name="PageTitle" Text="{Binding DetailsStudent.Name}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
11: </StackPanel>
12:
13: <!--ContentPanel - place additional content here-->
14: <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
15: <Grid.ColumnDefinitions>
16: <ColumnDefinition Width="100"/>
17: <ColumnDefinition Width="12"/>
18: <ColumnDefinition Width="*"/>
19: </Grid.ColumnDefinitions>
20: <Image Grid.Column="0" Source="{Binding DetailsStudent.Image}" VerticalAlignment="Top"/>
21: <StackPanel Grid.Column="2">
22: <StackPanel Orientation="Horizontal">
23: <TextBlock Text="{Binding DetailsStudent.Age}" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
24: <TextBlock Text=" ans" FontFamily="{StaticResource PhoneFontFamilySemiLight}" FontSize="{StaticResource PhoneFontSizeNormal}"/>
25: </StackPanel>
26: </StackPanel>
27: </Grid>
28: </Grid>
Et la c’est terminé, maintenant lorsque l’on appuie sur le bouton back, l’évenement “Loaded” de la view est déclenché, l’url contient le paramètre à déserializer du coup ca marche !
Sur cette exemple tout est développer “from scratch”, forcement en interne, chez tequilarapido. nous avons réaliser des Helpers permettant de passer des paramètre à une URL et de la récupérer directement déserializer, je vous laisse faire cette partie.
Ce principe permet donc de s’enlever bien des soucis, et nous permet de passer les deux tests de certifications cité ci-dessus.
Télécharger le projet ici
Venez assister à la session « tips & trick » sur windows phone 7 au techdays animée par moi-même, nous revelerons les TequilarapidoPhoneExtensions, généralisant ce principe et permettant de développer des application en quelques jours !
OMG! It is like you understand my mind! You seem to know a lot about this, like you wrote the book in it or something. I think that you could do with some images to drive the message home a bit, besides that, this is helpful blog. A wonderful read. I’ll definitely be back.
Thnx so much for this! I have not been this moved by a blog post for a long period of time! You’ve got it, whatever that means in blogging. Well, You are certainly someone that has something to say that people need to hear. Keep up the wonderful job. Keep on inspiring the people!
Great article, I just given this onto a student who was doing a little analysis on that. And he in fact bought me dinner because I discovered it for him…
.. So let me rephrase that: Thank you for the treat! But yeah Thnx for taking the time to discuss this, I feel strongly about it and love reading more on this topic. If possible, as you gain expertise, would you mind updating your blog with more information? It is highly helpful for me. Big thumb up for this post!
A brilliant blog post, I just passed this onto a friend who was doing a little research on that. And he in fact bought me dinner because I discovered it for him.. smile. So let me rephrase that: Thnkx for the treat! But yeah Thnkx for spending the time to discuss this, I feel strongly about it and enjoy learning more on this topic. If possible, as you become expertise, would you mind updating your blog with more info? It is very helpful for me. Big thumb up for this blog post!
Hi! Your article rocks and is really a very good understand!…
Thanks for this post, going to use an excerp on my own GSXR blog.
Cheers for this posting, guys, retain up the fantastic operate…
I want to thnkx for the time you have made in composing this blogpost. I am hoping the same best work from you in the upcoming as well. In fact your creative writing abilities has inspired me to start my own blog now. Truly the blogging is spreading its wings rapidly. Your write up is a fine model of it.
It is unusual for me to find something on the web that’s as entertaining and fascinating as what you have got here. Your page is sweet, your graphics are outstanding, and what’s more, you use reference that are relevant to what you’re talking about. You are definitely one in a million, great job!
Fantastic article! I’ll subscribe correct now wth my feedreader software package!…
I’m impressed, I must say. Very seldom do I discover a blog that’s both educative and entertaining, and let me tell you, you’ve hit the nail on the head. Your article is important; the matter is something that not many people are speaking intelligently about. I’m really happy that I stumbled across this in my search for something relating to this.
What a helpful post dude. Thank you But I am having trouble with the rss feed. Fail to subscribe to it. Does anyone else having same rss issue? Anybody who knows please respond. Thanks!
Cheers for this posting, guys, retain up the fantastic operate…
Do you mind allowing me to quote some of your paragraphs on my own motorcycle blog?
Could you message me with some pointers about how you made your site look this awesome , I would be appreciative!
Fantastic article! I’ll subscribe correct now wth my feedreader software package!…
Greg. Do you quarrel, sir?
Of course, what a fantastic website and enlightening posts, I surely will bookmark your website.Have an awsome day!
OMG! It is like you understand my mind! You seem to know so much about this, just like you wrote the book in it or something. I think that you can do with some pics to drive the content home a bit, but other than that, this is wonderful blog. A good read. I’ll definitely return again.
You got to push it-this essietnal info that is!
I’m impressed, I must say. Really rarely do I see a blog that is both educative and entertaining, and let me tell you, you have hit the nail on the head. Your idea is important; the issue is something that not enough people are talking intelligently about. I am very happy that I stumbled across this in my search for something relating to this.
I’m impressed, I have to say. Really rarely do I encounter a blog that’s both educative and entertaining, and let me tell you, you have hit the nail on the head. Your opinion is important; the matter is something that not many people are speaking intelligently about. I am very happy that I stumbled across this in my search for something relating to it.
Surprisingly! It is like you understand my mind! You seem to know so much about this, just like you wrote the book in it or something. I think that you could do with some pictures to drive the message home a bit, besides that, this is outstanding blog post. A good read. I’ll definitely revisit again.
I want to thnkx for the time you have put in writing this blog post. I am hoping the same best blog post from you in the upcoming as well. In fact your creative writing abilities has inspired me to start my own blog now. Really the blogging is spreading its wings quickly. Your write up is a good model of it.
This website is awesome. I constantly come across something new & different right here. Thank you for that data.
Very nice post and right to the point. I am not sure if this is really the best place to ask but do you people have any thoughts on where to hire some professional writers? Thanks
I would like to thanks for the efforts you have made in composing this article. I am hoping the same high-grade work from you in the upcoming as well. In fact your creative writing skill has inspired me to begin my own blog now. Really the blogging is spreading its wings rapidly. Your write up is a fine model of it.
This site seems to recieve a good ammount of visitors. How do you get traffic to it? It offers a nice individual twist on things. I guess having something authentic or substantial to give info on is the most important factor.
Samp. Well, sir.
You made several nice points there. I did a search on the subject matter and found the majority of persons will agree with your blog.
http://predict-gender.com/chinese-calendar-to-predict-gender
Barack may be gay
Reminds me of:It is a mathematical fact that fifty percent of all doctors graduate in the bottom half of their class. ~Author Unknown
http://phen375exposed.com/phentemine375-what-is-phen375
http://www.themoneypenny.se/?p=660
The beauty of these running a blog engines and CMS platforms is the shortage of limitations and ease of manipulation that permits builders to implement wealthy content and ‘pores and skin’ the location in such a method that with little or no effort one would never discover what it’s making the location tick all with out limiting content and effectiveness.
Quality post. I learn today’s truck owner on different blogs everyday. It is always stimulating to read content from other writers and be shown a little something there. I want to use some for this content on my blog if you don’t mind. Natually I’ll provide a link back to site. Appreciate you sharing.
Sorry for the huge review, but I’m really loving the new Zune, and hope this, as well as the excellent reviews some other people have written, will help you decide if it’s the right choice for you.
Hello. Great job. I did not anticipate this. This is a fantastic story. Thanks!