Bienvenue dans la deuxième partie de la création d’un Wallview inspiré par iTunes. Dans cette partie, nous allons écrire tout le code en C # pour les deux UserControls que nous avons créés avec Expression Blend dans le didacticiel précédent..
Jetez un autre regard sur la démonstration vidéo du résultat final sur lequel nous allons travailler (ou consultez simplement la démonstration Web ci-dessus):
Ouvrez Visual Studio et cliquez sur "Fichier"> "Ouvrir"> "Projet / Solution" dans la barre de menus..
Ensuite, accédez au projet que nous avons créé dans la première partie de ce didacticiel. Nous l'avons appelé "WallviewApp".
Sur le côté droit de Visual Studio est l'Explorateur de solutions par défaut. Ici vous pouvez voir tous les fichiers du projet. Allez-y et ouvrez les deux fichiers * .cs "image.xaml.cs" et "wallview-img.xaml.cs" des deux UserControls que nous avons créés dans le précédent tutoriel de Blend, ainsi que le "MainPage.xaml.cs". qui a fourni automatiquement.
Une fois que vous avez ouvert ces trois fichiers, vous pouvez voir que les trois classes sont vides..
Commençons par coder la classe d'image. Assurez-vous d’éditer le fichier "image.xaml.cs" et ajoutez les déclarations suivantes juste au-dessus du constructeur "public image ()":
bool public sélectionné; private double defaultSize; wallview_img wallview privé; private SolidColorBrush colorDefault, colorSelected;
Nous allons maintenant programmer le constructeur qui a deux paramètres: une BitmapImage et une String. En outre, les variables déclarées précédentes sont initialisées, les paramètres du constructeur sont affectés à la source du "img" et au texte du bloc de texte "imgName". Nous enregistrons également un gestionnaire d'événements pour l'événement MouseLeftButtonDown de "img":
image publique (BitmapImage src, Nom de chaîne) // Requis pour initialiser les variables InitializeComponent (); sélectionné = faux; defaultSize = 200; colorDefault = new SolidColorBrush (Color.FromArgb (0x00, 0x76, 0xA2, 0xF9)); colorSelected = new SolidColorBrush (Color.FromArgb (0xFF, 0x76, 0xA2, 0xF9)); this.img.Source = src; this.imgName.TextAlignment = TextAlignment.Center; this.imgName.Text = name; this.imgDate.TextAlignment = TextAlignment.Center; this.img.MouseLeftButtonDown + = new MouseButtonEventHandler (image_MouseLeftButtonDown);
Le paramètre BitmapImage est souligné d'une couleur rouge car Visual Studio ne peut pas trouver l'espace de noms. Pour résoudre ce problème, cliquez simplement sur le mot BitmapImage et un petit rectangle bleu devrait apparaître sous la lettre B:
Lorsque vous déplacez votre souris sur le petit rectangle, un menu déroulant apparaît. Cliquez sur l'entrée "Using System.Windows.Media.Imaging;":
Maintenant, Visual Studio connaît cet espace de noms et le soulignement rouge disparaîtra..
Juste après le constructeur, nous allons écrire quelques méthodes dont nous aurons besoin plus tard. Les méthodes sont assez auto-descriptives à partir de leurs noms de méthodes. image_MouseLeftButtonDown
est le gestionnaire d'événements du MouseLeftButtonDown
événement de "img" que nous avons enregistré dans le constructeur. Il contrôle essentiellement ce qui se passe lorsque vous cliquez sur l'image, en fonction de son statut (qu'elle soit déjà sélectionnée ou non):
public void setWallview (wallview_img wv) wallview = wv; public void changeSize (double newsize) this.imgName.Width = defaultSize * newsize; this.imgSize.Width = defaultSize * newsize; this.imgSize.Height = defaultSize * newsize; public void unselectImage () selected = false; this.imgBorder.BorderBrush = colorDefault; public void selectImage () selected = true; this.imgBorder.BorderBrush = colorSelected; void privé image_MouseLeftButtonDown (expéditeur de l'objet, System.Windows.Input.MouseButtonEventArgs e) wallview.imageSelected = true; if (wallview.ctrlPressed == true) if (sélectionné == true) unselectImage (); sinon selectImage (); else wallview.unselectAllImages (); selectImage (); e.Handled = true;
Maintenant nous en avons fini avec la classe image.
Ne vous inquiétez pas des parties soulignées en rouge dans votre code. Ces variables et méthodes n'existent pas encore et c'est pourquoi Visual Studio ne les connaît pas mais nous allons changer cela bientôt.
Puisque nous en avons terminé avec la classe image, ouvrez le document "wallview-img.xaml.cs". Commencez par écrire les déclarations de variables juste au-dessus du constructeur "public wallview_img ()":
liste publiqueimageList; liste privée panelList; public bool ctrlPressed, imageSélectionné; private double defaultSize, changeSize;
Juste comme avant avec BitmapImage, Visual Studio ne connaît pas l’espace de noms de liste
. Pour résoudre ce problème, comme précédemment, cliquez sur l'une des listes, puis sur le rectangle bleu et sélectionnez "à l'aide de System.Collections.Generic;" à partir du menu:
Ajoutez le code suivant qui initialise les variables précédemment déclarées, enregistre certains événements et désactive les boutons de la barre de navigation:
public wallview_img () // Requis pour initialiser les variables InitializeComponent (); ctrlPressed = false; imageSelected = false; imageList = nouvelle liste(); panelList = nouvelle liste (); defaultSize = 200; changeSize = 1; // enregistrement de tous les événements MouseLeftButtonUp + = new MouseButtonEventHandler (wallviewMouseLeftButtonUp); SizeChanged + = new SizeChangedEventHandler (resizeScrollViewer); KeyDown + = new KeyEventHandler (keyDownEvent); KeyUp + = new KeyEventHandler (keyUpEvent); this.slider.ValueChanged + = new RoutedPropertyChangedEventHandler (sliderValueChanged); // boutons dont nous n'avons pas encore besoin this.btnAllAlbums.IsEnabled = false; this.btnCurrentAlbum.IsEnabled = false; this.btnNext.IsEnabled = false; this.btnPrev.IsEnabled = false;
Ajoutez les méthodes suivantes sous le constructeur. Le commentaire avant chaque méthode explique ce que fait la méthode:
// ajoute une image à la liste d'images et appelle resizeimages () qui l'ajoute au dernier empilage public void addImage (image img) img.imgName.Width = 200; img.setWallview (this); imageList.Add (img); resizeImages (); // efface tout le contenu dessiné, chaque panneau, chaque albumlist et chaque membre du public public void clearLists () imageList.Clear (); foreach (StackPanel x dans panelList) x.Children.Clear (); this.content.Children.Clear (); panelList.Clear (); // calcule combien de stackpanels = de lignes sont nécessaires public void updatePanels () if (imageList.Count> 0) foreach (StackPanel sp dans panelList) sp.Children.Clear (); panelList.Clear (); double gridWidth = 0; if (this.content.ActualWidth == 0) gridWidth = 800; else gridWidth = this.content.ActualWidth; int gridWidthInt = Convert.ToInt32 (gridWidth); int imageAmount = imageList.Count; int imageMargin = 10; int imageWidth = Convert.ToInt32 (defaultSize * changeSize); int imageSize = imageWidth + 2 * imageMargin; double ratio = gridWidth / (double) imageSize; int ratioInt = Convert.ToInt32 (ratio); si (ratioInt - ratio> 0) ratioInt - = 1; int newImageMargin = ((gridWidthInt - ratioInt * imageWidth) / ratioInt) / 2; double panelAmountDouble = (double) imageAmount / ratioInt; int panelAmountInt = (int) panelAmountDouble; if (panelAmountDouble - panelAmountInt> 0) panelAmountInt ++; si (panelAmountInt < 1) panelAmountInt = 1; int x = 0; for (int i = 0; i < panelAmountInt; i++) StackPanel panel = new StackPanel(); panel.Orientation = Orientation.Horizontal; panel.Margin = new Thickness(0, 5, 0, 0); for (int j = 0; j < ratioInt; j++) if (x < imageAmount) imageList[x].Margin = new Thickness(newImageMargin, 0, newImageMargin, 10); imageList[x].changeSize(changeSize); imageList[x].setWallview(this); panel.Children.Add(imageList[x]); x++; panelList.Add(panel); //selects all images, gets called when ctrl + a is pressed public void selectAllImages() foreach (image i in imageList) i.selectImage(); //unselects all iamges public void unselectAllImages() foreach (image i in imageList) i.unselectImage(); //gets called when the slider value changes private void resizeImages() updatePanels(); this.content.Children.Clear(); foreach (StackPanel sp in panelList) this.content.Children.Add(sp); //method gets called by the slidervaluechanged event public void changeImageSize(double newsize) changeSize = newsize; resizeImages();
Dans cette étape, nous écrivons les gestionnaires d’événements nécessaires pour les événements que nous avons enregistrés précédemment dans le constructeur:
// gestionnaire d'événements pour le moment où le curseur est modifié void private sliderValueChanged (expéditeur de l'objet, System.Windows.RoutedPropertyChangedEventArgse) changeImageSize (this.slider.Value); // gestionnaire d'événements qui est appelé lorsque windowsize change de void privé resizeScrollViewer (expéditeur d'objet, System.Windows.SizeChangedEventArgs e) resizeImages (); // gestionnaire d'événements qui désélectionne toutes les images lorsque vous ne cliquez pas sur une image vide wallviewMouseLeftButtonUp (expéditeur d'objet, MouseButtonEventArgs e) if (! imageSelected) unselectAllImages (); sinon imageSelected = false; // gestionnaire d'événements pour appuyer sur les touches void private keyDownEvent (expéditeur d'objet, System.Windows.Input.KeyEventArgs e) if (e.Key == Key.Ctrl) ctrlPressed = true; sinon if (e.Key == Key.A) if (ctrlPressed) selectAllImages (); // gestionnaire d'événements pour la libération des clés void private keyUpEvent (expéditeur de l'objet, System.Windows.Input.KeyEventArgs e) if (e.Key == Key.Ctrl) ctrlPressed = false;
Maintenant nous en avons fini avec le wallview-img
classe. Continuons avec la création d’un service Web dont nous aurons besoin pour la Page d'accueil
classe.
Le service Web que nous allons écrire nous fournit essentiellement les images d’un certain dossier. Pour créer un service Web, cliquez avec le bouton droit de la souris sur "WallviewApp.Web" dans l'Explorateur de solutions situé à droite de Visual Studio, puis sélectionnez "Ajouter"> "Nouvel élément" dans le menu.
Dans la fenêtre contextuelle, sélectionnez "Service WCF compatible Silverlight Visual C #" et entrez "WCF.svc" pour un nom, puis cliquez sur "Ajouter":
Comme vous pouvez le constater, nous avons obtenu une autre classe appelée WCF avec son propre document de code, "WCF.svc.cs"..
Ajoutez les deux méthodes suivantes dans la classe WCF juste en dessous de la ligne indiquant "// Ajoutez d'autres opérations ici et marquez-les avec [OperationContract]
":
// méthode pour obtenir tous les noms de fichier d'un dossier [OperationContract] public string [] getFileNames (String dir) try String tmp = HttpContext.Current.Request.MapPath (dir); return Directory.GetFiles (@tmp, "* .jpg"); catch (Exception) return null; // méthode qui retourne la date de création d'un fichier ou d'un dossier [OperationContract] public String getFileDates (String file, int i) return i.ToString () + "-" + File.GetLastWriteTime (fichier) .ToString ( )
Corrigez les espaces de noms manquants comme nous l'avons fait précédemment en cliquant sur les noms affectés, puis sur le rectangle bleu et sur "importer ..." ou en ajoutant ces deux lignes manuellement en haut du document:
using System.Web; using System.IO;
Afin de pouvoir utiliser le service Web, nous devons ajouter une référence de service au projet principal. Avant de réussir, nous devons construire le projet une fois. Par conséquent, cliquez sur "Construire" dans le menu situé tout en haut de Visual Studio, puis sur "Construire WallviewApp":
Une fois la construction réussie, cliquez avec le bouton droit de la souris sur "WallviewApp" dans l'Explorateur de solutions et choisissez "Ajouter une référence de service" dans le menu.
Dans la popup suivante, cliquez sur le bouton "Découvrir" et entrez "WCFRef" dans le champ Namespace, puis cliquez sur "OK":
Sans construire le projet avant d'essayer d'ajouter une référence de service, vous auriez reçu ce message d'erreur:
Ouvrez le fichier "MainPage.xaml.cs" et ajoutez les lignes de code suivantes au-dessus du constructeur "page principale publique ()
":
client privé WCFRef.WCFClient; chaîne privée imagedir = "/ image /"; public wallview_img wvi; private int amountImages;
Le constructeur du Page d'accueil
ressemble à ça. Nous initialisons les déclarations de l'étape précédente, enregistrons les gestionnaires d'événement du Webservice et ajoutons le wallview_img
nommé "wvi
" au la grille
"LayoutRoot
" du Page d'accueil
:
public MainPage () InitializeComponent (); montantImages = 0; client = new WallviewApp.WCFRef.WCFClient (); client.getFileNamesCompleted + = new EventHandler(client_getFileNamesCompleted); client.getFileNamesAsync (imagedir); client.getFileDatesCompleted + = new EventHandler (client_getFileDatesCompleted); wvi = new wallview_img (); this.LayoutRoot.Children.Add (wvi);
Ajoutez les deux gestionnaires d’événements suivants et la méthode sous le constructeur de MainPage.
Le "client_getFileNamesCompleted ()
"obtient un tableau de chaînes qui est renvoyé par le service Web. Le tableau est converti en chaînes séparées à partir desquelles le nom de fichier est extrait..
En utilisant le localhost
adresse, le port, le répertoire de l'image et le nom du fichier, nous construisons un Uri
appelé "src". Cette Uri
est utilisé pour créer un nouveau Image bitmap
"bmi" nécessaire à la création d'une nouvelle image "tmp". L'image "tmp" est alors ajoutée à la wallview_img
"wmi".
Ensuite, la méthode qui renvoie la date de création d'un fichier est appelée avec un numéro de compteur. Tout ce que cette méthode retourne est traité par le gestionnaire "client_getFileDatesCompleted ()". Depuis une chaîne au format > 2-18.02.2009 12:32:23 est renvoyé du service Web, nous devons séparer le numéro du compteur au début et la date au milieu..
Lorsque cette procédure est terminée, la date finale ressemble à > 18.02.2009 et est affecté à la
Textblock
"imgDate" de l'image correspondante.
// gestionnaire d'événement pour extraire les noms de fichiers du dossier void privé client_getFileNamesCompleted (expéditeur d'objet, WallviewApp.WCFRef.getFileNamesCompletedEventArgs e) if (e.Result! = null) foreach (chaîne s dans e.Result) int pos = s.LastIndexOf ("\\"); string filename = s.Substring (pos + 1); int port = Application.Current.Host.Source.Port; Uri src = new Uri ("http: // localhost:" + port + imagedir + nom du fichier); BitmapImage bmi = new BitmapImage (src); image tmp = nouvelle image (bmi, nom du fichier); this.wvi.addImage (tmp); amountImages ++; getFileDate (s, amountImages - 1); else MessageBox.Show ("null retourné dans les fichiers terminés"); // méthode qui appelle le service Web asynch avec une chaîne de chemin de fichier et un nombre afin que nous puissions associer la chaîne de date renvoyée à une certaine image. private void getFileDate (String s, int i) this.client.getFileDatesAsync (s, i, ) // gestionnaire d'événement pour obtenir le contenu privé void client_getFileDatesCompleted (expéditeur d'objet, WallviewApp.WCFRef.getFileDatesCompletedEventArgs e) if (e.Result! = null) String dt = e.Result; int number = Convert.ToInt32 (dt.Remove (dt.LastIndexOf ("-"))); String date = dt.Remove (dt.LastIndexOf ("")); si (nombre < 10) date = date.Remove(0, 2); else if (number < 100) date = date.Remove(0, 3); else date = date.Remove(0, 4); this.wvi.imageList[number].imgDate.Text = date; else MessageBox.Show("returned null in dates completed");
Comme dans les autres fichiers source, l'espace de nom "BitmapImage" est introuvable. Pour réparer cela, cliquez sur le rectangle bleu et importez-le après avoir cliqué dans le texte de Image bitmap
, ou ajoutez manuellement la ligne suivante en haut du document:
using System.Windows.Media.Imaging;
Allez-y et exécutez le projet pour voir si tout fonctionne. Vous pouvez le faire en appuyant sur la touche "F5" de votre clavier, en cliquant sur le bouton avec une icône "Lecture" typique située sous le menu en haut de la barre d'icônes, ou en sélectionnant l'entrée "Démarrer le débogage" à l'intérieur du "débogage". sous-menu du menu tout en haut de Visual Studio:
Votre navigateur s'ouvre et vous obtiendrez ce message d'erreur:
Quel est le problème?
Nous avons demandé au service Web de vérifier le dossier "http: // localhost: port / image /" pour les fichiers * .jpg et, bien entendu, ni ce dossier ni aucune image de ce dossier n'existent encore..
Accédez au répertoire du projet avec votre explorateur Windows. Pour moi c'est le chemin suivant:
Ouvrez le dossier "WallviewApp.Web" et créez un nouveau dossier appelé "image" à l'intérieur..
Ouvrez maintenant le dossier "image" et collez-y des images * .jpg.
Une fois que vous avez placé quelques images dans le dossier images, appuyez sur Actualiser dans votre navigateur Web (s'il est toujours ouvert) ou exécutez simplement le projet à nouveau en appuyant sur la touche "F5" dans Visual Studio. En conséquence, vous devriez voir notre Wallview final:
Vous pouvez influencer la taille des images affichées avec le curseur de la barre de navigation..
Nous avons terminé pour le moment avec ce tutoriel et j'espère que vous avez apprécié et appris quelque chose aussi.
Le temps total approximatif qu'il m'a fallu pour développer cela à partir de zéro était d'environ 20 heures. La vision murale des albums que vous pouvez voir dans la vidéo ci-dessous m'a pris environ 15 heures et 10 heures supplémentaires pour combiner les deux types de vues..
Vous pourriez vous demander quel est l'intérêt de pouvoir sélectionner une ou plusieurs images. Pour le moment, cette fonctionnalité est inutile, mais je pourrais imaginer ajouter la possibilité de démarrer un diaporama ou de créer une liste de lecture à partir des images sélectionnées, par exemple. Et si vous vous demandez pourquoi nous avons ajouté les boutons "Tous les albums", "Album actuel", "<" and ">"dans la barre de navigation mais ne les a jamais utilisés ...
Mon intention est de développer un autre tutoriel qui génère automatiquement des albums photo en fonction des noms de fichiers des images. Bien entendu, ce tutoriel étendra le projet à partir du tutoriel que vous venez de terminer ici. J'aimerais vraiment faire ça si c'est populaire auprès du public. Pour avoir une idée de ce à quoi ressemblerait la vue murale pour les images que nous venons de créer, associée à une vue murale pour les albums photo, regardez la vidéo suivante:
Pour tout commentaire, suggestion ou préoccupation, veuillez laisser une note dans la section commentaire. Merci d'avoir lu!