Bienvenido a la segunda parte de la creación de un Wallview inspirado en iTunes. En esta parte, vamos a escribir el código completo en C # para los dos UserControls que creamos con Expression Blend en el tutorial anterior..
Eche un vistazo a la demostración en video del resultado final en el que trabajaremos (o simplemente consulte la demostración en línea más arriba):
Abra Visual Studio y haga clic en "Archivo"> "Abrir"> "Proyecto / Solución" en la barra de menú.
Luego busque el proyecto que creamos en la primera parte de este tutorial. Lo llamamos "WallviewApp".
En el lado derecho de Visual Studio se encuentra el Explorador de soluciones de forma predeterminada. Aquí puedes ver todos los archivos del proyecto. Continúe y abra los dos archivos * .cs "image.xaml.cs" y "wallview-img.xaml.cs" de los dos UserControls que creamos en el tutorial anterior en Blend, así como el "MainPage.xaml.cs" que se proporcionó automáticamente.
Una vez que haya abierto estos tres archivos, podrá ver que las tres clases están bastante vacías..
Vamos a empezar con la codificación de la clase de imagen. Asegúrese de que está editando el archivo "image.xaml.cs" y agregue las siguientes declaraciones justo encima del constructor "public image ()":
bool pública seleccionada; privado doble defaultSize; privado wallview_img wallview; privado SolidColorBrush colorDefault, colorSelected;
Ahora vamos a programar el constructor que tiene dos parámetros: un BitmapImage y un String. Además, las variables declaradas anteriores se inicializan, los parámetros del constructor se asignan a la fuente del "img" y al texto del bloque de texto "imgName". También registramos un controlador de eventos para el evento MouseLeftButtonDown del "img":
imagen pública (BitmapImage src, nombre de la cadena) // Necesario para inicializar las variables InitializeComponent (); seleccionado = falso; 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 = nombre; this.imgDate.TextAlignment = TextAlignment.Center; this.img.MouseLeftButtonDown + = new MouseButtonEventHandler (image_MouseLeftButtonDown);
El parámetro BitmapImage está subrayado con un color rojo porque Visual Studio no puede encontrar el espacio de nombres. Para corregirlo, simplemente haga clic en la palabra Imagen de mapa de bits y aparecerá un pequeño rectángulo azul debajo de la letra B:
Cuando mueva el mouse sobre el rectángulo pequeño, aparecerá un menú desplegable. Haga clic en la entrada "Utilizando System.Windows.Media.Imaging;":
Ahora Visual Studio sabe ese espacio de nombres, y el subrayado rojo desaparecerá..
Justo después del constructor, vamos a escribir un par de métodos que necesitaremos más adelante. Los métodos son bastante autodescriptivos a partir de sus nombres de métodos.. image_MouseLeftButtonDown
es el controlador de eventos de la MouseLeftButtonDown
evento del "img" que registramos en el constructor. Básicamente controla lo que sucede cuando haces clic en la imagen, dependiendo de su estado (ya esté seleccionado o no):
public void setWallview (wallview_img wv) wallview = wv; public void changeSize (doble 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; private void image_MouseLeftButtonDown (objeto remitente, System.Windows.Input.MouseButtonEventArgs e) wallview.imageSelected = true; if (wallview.ctrlPressed == true) if (selected == true) unselectImage (); else selectImage (); else wallview.unselectAllImages (); seleccionar imagen(); e.Handled = true;
Ahora hemos terminado con la clase de imagen..
No se preocupe por las partes subrayadas en rojo en su código. Estas variables y métodos aún no existen y es por eso que Visual Studio no los conoce pero vamos a cambiar eso pronto.
Una vez que hayamos terminado con la clase de imagen, abra el documento "wallview-img.xaml.cs". Al principio, escriba las declaraciones de variables justo encima del constructor "public wallview_img ()":
Lista públicaimageList; Lista privada panelList; public bool ctrlPressed, imageSelected; privado doble defaultSize, changeSize;
Al igual que antes con BitmapImage, Visual Studio no conoce el espacio de nombres de Lista
. Para solucionar esto, como antes, haga clic en una de las listas, luego en el rectángulo azul y seleccione "usando System.Collections.Generic;" desde el menú:
Agregue el siguiente código que inicializa las variables declaradas anteriormente, registra algunos eventos y desactiva los botones en la barra de navegación:
public wallview_img () // Necesario para inicializar las variables InitializeComponent (); ctrlPressed = falso; imageSelected = false; imageList = nueva lista(); panelList = nueva lista (); defaultSize = 200; changeSize = 1; // registrar todos los eventos MouseLeftButtonUp + = new MouseButtonEventHandler (wallviewMouseLeftButtonUp); SizeChanged + = new SizeChangedEventHandler (resizeScrollViewer); KeyDown + = new KeyEventHandler (keyDownEvent); KeyUp + = new KeyEventHandler (keyUpEvent); this.slider.ValueChanged + = new RoutedPropertyChangedEventHandler (sliderValueChanged); // botones que no necesitamos todavía this.btnAllAlbums.IsEnabled = false; this.btnCurrentAlbum.IsEnabled = false; this.btnNext.IsEnabled = false; this.btnPrev.IsEnabled = false;
Agregue los siguientes métodos debajo del constructor. El comentario antes de cada método explica qué está haciendo el método:
// agrega una imagen a la lista de imágenes y llama a resizeimages () que básicamente la agrega al último panel de pila public addidage (img de imagen) img.imgName.Width = 200; img.setWallview (esto); imageList.Add (img); resizeImages (); // borra todo el contenido dibujado, cada panel, lista de álbumes y panelista public void clearLists () imageList.Clear (); foreach (StackPanel x en panelList) x.Children.Clear (); this.content.Children.Clear (); panelList.Clear (); // calcula cuántos stackpanels = row se necesitan public void updatePanels () if (imageList.Count> 0) foreach (StackPanel sp en panelList) sp.Children.Clear (); panelList.Clear (); doble rejilla ancho = 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; doble proporción = gridWidth / (double) imageSize; int ratioInt = Convert.ToInt32 (ratio); if (ratioInt - ratio> 0) ratioInt - = 1; int newImageMargin = ((gridWidthInt - ratioInt * imageWidth) / ratioInt) / 2; doble 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();
En este paso, escribimos los controladores de eventos necesarios para los eventos que registramos anteriormente en el constructor:
// eventhandler para cuando se cambia el control deslizante void privado sliderValueChanged (objeto remitente, System.Windows.RoutedPropertyChangedEventArgse) changeImageSize (this.slider.Value); // eventhandler al que se llama cuando el tamaño de la ventana cambia el vacío privado resizeScrollViewer (objeto remitente, System.Windows.SizeChangedEventArgs e) resizeImages (); // eventhandler que deselecciona todas las imágenes cuando no hace clic en una imagen void wallviewMouseLeftButtonUp (objeto remitente, MouseButtonEventArgs e) if (! (! imageSelected) unselectAllImages (); else imageSelected = false; // eventhandler para presionar las teclas private void keyDownEvent (objeto emisor, System.Windows.Input.KeyEventArgs e) if (e.Key == Key.Ctrl) ctrlPressed = true; else if (e.Key == Key.A) if (ctrlPressed) selectAllImages (); // eventhandler para liberar claves private void keyUpEvent (objeto remitente, System.Windows.Input.KeyEventArgs e) if (e.Key == Key.Ctrl) ctrlPressed = false;
Ahora hemos terminado con el wallview-img
clase. Continuemos con la creación de un servicio web que necesitaremos para el Pagina principal
clase.
El servicio web que vamos a escribir básicamente nos proporciona las imágenes de una carpeta determinada. Para crear un servicio web, haga clic con el botón derecho en "WallviewApp.Web" en el Explorador de soluciones en el lado derecho de Visual Studio y seleccione "Agregar"> "Nuevo elemento" en el menú:
Desde la ventana emergente, seleccione "WCF Service Visual C #" habilitado para Silverlight e ingrese "WCF.svc" para un nombre, luego haga clic en "Agregar":
Como puede ver, obtuvimos otra clase llamada WCF con su propio documento de código, "WCF.svc.cs".
Agregue los siguientes dos métodos en la clase WCF justo debajo de la línea que dice "// Agregue más operaciones aquí y márquelas con [OperationContract]
":
// método para obtener todos los nombres de archivo dentro de una carpeta [OperationContract] public string [] getFileNames (String dir) try String tmp = HttpContext.Current.Request.MapPath (dir); return Directory.GetFiles (@tmp, "* .jpg"); catch (Exception) return null; // método que devuelve la fecha de creación de un archivo o carpeta [OperationContract] public String getFileDates (String file, int i) return i.ToString () + "-" + File.GetLastWriteTime (file) .ToString ( );
Corrija los espacios de nombres faltantes como hicimos anteriormente haciendo clic en los nombres afectados, luego en el rectángulo azul y en "importar ..." o agregando estas dos líneas manualmente en la parte superior del documento:
utilizando System.Web; utilizando System.IO;
Para poder utilizar el servicio web necesitamos agregar una referencia de servicio al proyecto principal. Antes de que podamos hacer esto con éxito, tenemos que construir el proyecto una vez. Por lo tanto, haga clic en "Crear" en el menú en la parte superior de Visual Studio y luego en "Crear WallviewApp":
Una vez que la compilación sea exitosa, haga clic con el botón derecho en "WallviewApp" en el lado derecho en el Explorador de soluciones y elija "Agregar referencia de servicio" en el menú:
En la próxima ventana emergente, haga clic en el botón "Descubrir" e ingrese "WCFRef" en el campo Espacio de nombres, luego haga clic en "Aceptar":
Sin compilar el proyecto antes de intentar agregar una referencia de servicio, habría recibido este mensaje de error:
Abra el archivo "MainPage.xaml.cs" y agregue las siguientes líneas de código sobre el constructor "Página principal pública ()
":
cliente privado WCFRef.WCFClient; cadena privada imagedir = "/ image /"; public wallview_img wvi; Imágenes de int privado;
El constructor de la Pagina principal
Se ve como esto. Inicializamos las declaraciones del paso anterior, registramos los manejadores de eventos del servicio web y agregamos el wallview_img
llamado "wvi
" al Cuadrícula
"LayoutRoot
" del Pagina principal
:
mainPage () InitializeComponent () pública; amountImages = 0; cliente = nuevo 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);
Agregue los siguientes dos manejadores de eventos y el método debajo del constructor de MainPage.
Los "client_getFileNamesCompleted ()
"obtiene una matriz de cadenas que el servicio web devuelve. La matriz se convierte en cadenas separadas de las que se extrae el nombre de archivo.
Utilizando la localhost
dirección, el puerto, el directorio de imágenes y el nombre de archivo, construimos un Uri
llamado "src". Ese Uri
se utiliza para crear un nuevo Imagen de mapa de bits
"bmi" que se necesita para crear una nueva imagen "tmp". La imagen "tmp" se agrega a la wallview_img
"wmi".
Posteriormente, el método que devuelve la fecha de creación de un archivo se llama junto con un número de contador. Cualquiera que sea el método que devuelve, es procesado por el controlador "client_getFileDatesCompleted ()". Desde una cadena en el formato > 2-18.02.2009 12:32:23 es devuelto desde el servicio web, tenemos que dividir el número de contador al principio y la fecha en el medio.
Cuando este procedimiento se completa, la fecha final parece > 18.02.2009 y está asignado a la
Bloque de texto
"imgDate" de la imagen correspondiente.
// controlador de eventos para obtener los nombres de archivo de la carpeta privada void client_getFileNamesCompleted (objeto remitente, WallviewApp.WCFRef.getFileNamesCompletedEventArgs e) if (e.Result! = null) foreach (string s in e.Result) int pos = s.LastIndexOf ("\\"); cadena nombre_archivo = s.Suststring (pos + 1); int port = Application.Current.Host.Source.Port; Uri src = new Uri ("http: // localhost:" + port + imagedir + filename); BitmapImage bmi = new BitmapImage (src); imagen tmp = nueva imagen (bmi, nombre de archivo); this.wvi.addImage (tmp); amountImages ++; getFileDate (s, amountImages - 1); else else MessageBox.Show ("devolvió nulo en archivos completados"); // método que llama al servicio web asynch con una cadena de ruta de archivo y un número para que podamos evaluar la cadena de fecha devuelta a una imagen determinada de nuevo privada void getFileDate (String s, int i) this.client.getFileDatesAsync (s, i ); // controlador de eventos para obtener los archivos privados anulados client_getFileDatesCompleted (objeto remitente, WallviewApp.WCFRef.getFileDatesCompletedEventArgs e) if (e.Result! = null) String dt = e.Result; número int = Convert.ToInt32 (dt.Remove (dt.LastIndexOf ("-"))); Fecha de cadena = dt.Remove (dt.LastIndexOf ("")); si < 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");
Como en los otros archivos de origen, el espacio de nombres "BitmapImage" no se puede encontrar. Para repararlo, haga clic en el rectángulo azul e impórtelo después de hacer clic en el texto de Imagen de mapa de bits
, o agregue la siguiente línea a la parte superior del documento manualmente:
utilizando System.Windows.Media.Imaging;
Sigue adelante y ejecuta el proyecto para ver si todo funciona. Puede hacer esto presionando "F5" en su teclado, haciendo clic en el botón con un ícono típico "Play" debajo del menú en la parte superior de la barra de iconos, o seleccionando la entrada "Iniciar depuración" dentro de "Debug" submenú del menú en la parte superior de Visual Studio:
Su navegador se abrirá y recibirá este mensaje de error:
Cuál es el problema?
Le dijimos al servicio web que revisara la carpeta "http: // localhost: port / image /" para los archivos * .jpg y, obviamente, ni esa carpeta ni ninguna imagen en esa carpeta existen todavía..
Navegue hasta el directorio del proyecto con su Explorador de Windows. Para mi es el siguiente camino:
Abra la carpeta "WallviewApp.Web" y cree una nueva carpeta llamada "imagen" dentro de ella.
Ahora abre la carpeta "imagen" y pega algunas imágenes * .jpg en ella.
Una vez que haya colocado un par de imágenes dentro de la carpeta de imágenes, presione actualizar dentro de su navegador web (si aún está abierto) o simplemente ejecute el proyecto nuevamente presionando la tecla "F5" en Visual Studio. Como resultado, deberías ver nuestro último Wallview:
Puede influir en el tamaño de las imágenes mostradas con el control deslizante en la barra de navegación.
Ya hemos terminado con este tutorial y espero que lo hayas disfrutado y que hayas aprendido algo..
El tiempo total aproximado que me tomó desarrollar esto desde cero fue de aproximadamente 20 horas. La vista de pared de los álbumes que se pueden ver en el video a continuación me llevó aproximadamente 15 horas y otras 10 horas para combinar ambos tipos de vista de pared..
Podría preguntarse cuál es el punto de poder seleccionar una o más imágenes. En este momento esa funcionalidad es inútil, pero podría imaginar agregar la posibilidad de comenzar una presentación de diapositivas o crear una lista de reproducción a partir de las imágenes seleccionadas, por ejemplo. Y si se está preguntando por qué agregamos los botones "Todos los álbumes", "Álbum actual",<" and ">"en la barra de navegación pero nunca los usé ...
Mi intención es desarrollar otro tutorial que genere automáticamente álbumes de fotos basados en los nombres de archivos de las imágenes. Por supuesto, ese tutorial ampliará el proyecto del tutorial que acaba de completar aquí. Definitivamente me gustaría hacer eso si es popular entre la audiencia. Para obtener una impresión de cómo se vería la vista de pared para las imágenes que acabamos de crear en combinación con una vista de pared para álbumes de fotos, eche un vistazo al siguiente video:
Para cualquier comentario, sugerencia o inquietud, por favor deje una nota en la sección de comentarios. Gracias por leer!