En la solución, tendremos dos proyectos. Uno para la aplicación real y otro para la abstracción de NAudio. NAudio es genial para abstraernos de los detalles, pero quiero hacer muy fácil para nosotros hacer todo con unos pocos métodos, en lugar de llamar a los códigos de NAudio para reproducir, pausar, detener, etc.
Sin embargo, hay una elección que tenemos que hacer cuando se trata del proyecto principal donde está la UI (Interfaz de Usuario): ¿usamos la arquitectura tradicional impulsada por eventos o usamos M odel V iew V iew M odel architecture (MVVM). Podrías pensar que usarías MVVM porque eso'tico es lo que todos los chicos guays usan hoy en día. Sin embargo, ambas arquitecturas tienen ventajas y desventajas, especialmente cuando se trata de desarrollar una aplicación en tiempo real como esta.
Desarrollé reproductores de medios usando ambas arquitecturas en dos proyectos diferentes:
- Si usas MVVM escribes mucho menos código. En este caso, sin embargo, la vinculación de la propiedad tiene el desagradable hábito de romperse y causar errores si se hace incorrectamente. Esto se vuelve problemático cuando se trata de implementar un control de barra de búsqueda en tiempo real de doble sentido.
- Si usas la vieja arquitectura de eventos, sin duda escribirás mucho más código de eventos UI. Pero también tendrás un control total sobre lo que ocurre durante esos eventos, por lo que es más fácil implementar un control en tiempo real como una barra de búsqueda.
En este tutorial, usaré la arquitectura MVVM. Sin embargo, como este no es un tutorial de MVVM, no entraré en detalles sobre cómo funciona la MVVM. Para más información sobre la MVVM, mira el tutorial de CodeProject's
Ahora que hemos elegido nuestra arquitectura, necesitamos generar los espacios de nombre adecuados en nuestro proyecto. Nuestra estructura de solución será así:
- SoluciónProyecto: NaudioPlayerModelsViewModelsViewsServiciosImágenesProyecto: NaudioWrapper
Creando la UI
Siempre me gusta empezar con la parte de la interfaz de usuario cuando se trata de proyectos WPF porque me proporciona una lista visual de las características que necesito implementar.
Imágenes, Espacios de Nombres y Mezcla
Sin embargo, antes de empezar con la UI, le daré el enlace de las imágenes que usé para los botones para que los tenga listos. Para los iconos usé los iconos de diseño de material libre de Google's. Pueden obtenerlos en la página de diseño de material de Google's. Después de que descargues los iconos, haz una búsqueda rápida de "play" o "pause" en el directorio de descargas para encontrar los iconos relevantes.
También necesitamos espacios de nombres de Interactividad del Sistema.Windows.y de Interacción de Microsoft.Expression para nuestros enlaces de eventos. Dije que no usaríamos arquitectura basada en eventos, pero a veces no podemos evitar los eventos. En este caso, los namespaces proporcionan eventos a la manera de MVVM. Añadir estos espacios de nombres puede ser complicado y puede que no siempre funcione como se espera. Estos namespaces en realidad vienen con Blend, una herramienta de desarrollo de interfaz de usuario para proyectos basados en XAML. Así que si tienes instalado Blend (viene con el instalador de Visual Studio), puedes encontrar esos archivos DLL (Dynamic Link-Library) de:
- Para archivos de programa (x86) Microsoft SDKs, Expression Blend, NETFramework, 4.5, bibliotecas (tixag 4).
- Para los archivos de programa de .NET 4.0 C:N- (x86)N-Microsoft SDKsN-Expression/BlendN- NETFrameworkNv4.0 Bibliotecas
Si no tienes instalado Blend, simplemente ejecuta el instalador de Visual Studio y modifícalo/añádelo a tu instalación.
Sin embargo, según mi experiencia, añadir los de Visual Studio no siempre funciona. Así que lo que suelo hacer:
- Crear el proyecto WPF en Visual Studio
- Añade xmlns_i="http://schemas.microsoft.com/expression/2010/interactivity" a la Ventana.
- Cerrar Visual Studio y abrir el proyecto en Blend.
- En el menú, haga clic en Project->Add Reference y añada las referencias de ese menú.
- Cerrar Blend y abrir el proyecto de nuevo en Visual Studio
Ahora todo está listo para nuestro código de identificación.
Código UI
Aquí está nuestra E x tensible A pplication M arkup L anguage (XAML) code for the UI:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798<Windowx:Class="NaudioPlayer. MainWindow "xmlns:x="http://schemas. microsoft.com/winfx/2006/xaml "xmlns:d="http://schemas.microsoft.com/expression/blend/2008 "xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006 "xmlns:local="clr-namespace:NaudioPlayer "xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity "xmlns:viewModels="clr-namespace:NaudioPlayer. ViewModels "mc:Ignorable="d "Title="{Título vinculante}"Altura="350 "Anchura="525"<Ventana.DataContext="viewModels:MainWindowViewModel/ Dock="Top"³;³;MenuItemHeader="Archivo"³;MenuItemHeader="Guardar Lista de Reproducción "Command="{Vincular GuardarLista de ReproducciónComando}"/³;MenuItemHeader="Cargar Lista de Reproducción "Command="{Vincular CargarLista de ReproducciónComando}"/³..; <MenuItemHeader="Salir "Comando="{Vincularse SalirComando de Aplicación}"/></MenuItem=;<MenuItemHeader="Medios de comunicación";MenuItemHeader="Agregar archivo a la lista de reproducción. .. "Command="{Enlazar AddFileToPlaylistCommand}"/><MenuItemHeader="Añadir carpeta a la lista de reproducción... "Command="{Enlazar AddFolderToPlaylistCommand}"/></MenuItem;</MenuItem;;;;GridDockPanel.Dock="Bottom "Height="30">Grid. ColumnDefinitions="30"/;ColumnaDefinitionWidth="30"/;ColumnaDefinitionWidth="30"/;ColumnaDefinitionWidth="30"/;ColumnaDefinitionWidth="30"/;ColumnaDefinitionWidth="*"/;ColumnaDefinitionWidth="30"/;/Rejilla. ColumnaDefinición="30"/"30"/"ButtonGrid".Columna="0 "Margen="3 "Comando="{Binding RewindToStartCommand}"³;<ImageSource="../Images/skip_previous.png "VerticalAlignment="Center "HorizontalAlignment="Center"/"Button";;ButtonGrid. Column="1 "Margin="3 "Command="{Vincular Comando IniciarReproducirComando}"<ImageSource="{Vincular ReproducirPausaImagenFuente}"Alineación Vertical="Centrar "Alineación Horizontal="Centrar"/"/Botón"/"ButtonGrid". Columna="2 "Margen="3 "Comando="{Vincular DetenerReproducciónComando}"-->Imagen="../Imágenes/parar.png "AlineaciónVertical="Centrar "AlineaciónHorizontal="Centrar"/"Botón". Columna="3 "Margen="3 "Comando="{Vincular AdelanteAlternativoComando}"-->ImagenFuente=". ./Imágenes/salto_siguiente.png "Alineación Vertical="Centro "Alineación Horizontal="Centro"/;</Botón;|;Columna.ButtonGrMargen="3 "Comando="{Vinculación BarajarComando}"-->;ImagenFuente="../Imágenes/Barajar. png "Alineación Vertical="Centro "Alineación Horizontal="Centro"/... ColumnaDefiniciones="3*"/;ColumnaDefiniciónAncho="20"/;ColumnaDefiniciónAncho="20"/;ColumnaDefiniciónAncho="*"/;/Rejilla. ColumnDefinitions><SliderGrid.Column="0 "Minimum="0 "Maximum="{Binding CurrentTrackLenght, Mode=OneWay}"Value="{Binding CurrentTrackPosition, Mode=TwoWay}"x:Name="SeekbarControl "VerticalAlignment="Center"-->;i:Interaction. Triggers=;i:EventTriggerEventName="PreviewMouseDown"->;i:InvokeCommandActionCommand="{Binding TrackControlMouseDownCommand}"->;i:InvokeCommandAction EventTriggerEventName="PreviewMouseUp"³;<i:InvokeCommandActionCommand="{Binding TrackControlMouseUpCommand}"³;</i:InvokeCommandAction Triggers...;/Slider...;/Imagen...Columna de la Imagen="2 "Fuente=".../Imagen/volumen.png"/Imagen.../Imagen.../SliderGrid. Columna="3 "Mínimo="0 "Máximo="1 "Valor="{Volumen Actual, Modo=Doble}"x:Nombre="Control de Volumen "Alineamiento Vertical="Centro";i:Interacción. Triggers=;i:EventTriggerEventName="ValueChanged"-->;i:InvokeCommandActionCommand="{Binding VolumeControlValueChangedCommand}"</i:InvokeCommandAction Triggers --> -->Slider --> -->Grid --> --> -->GridDockPanel.Dock="Bottom"--> -->Grid.ColumnDefinitions --> --> -->ColumnDefinitionWidth="70"/WhitneyWidth="Auto"/WhitneyWrap="Auto"/WhitneyGrid.ColumnDefinitions --> -->TextBlockGrid.Column="0 "Text="Now playing: "TextBlockGrid.Column="1 "Text="{Binding CurrentlyPlayingTrack. FriendlyName, Mode=OneWay}"/;</Grid;;ListViewx:Name="Playlist "ItemsSource="{Encuadernación de la lista de reproducción}"SelectedItem="{Encuadernación de la pista actualmente seleccionada, Mode=TwoWay}"<ListView.ItemTemplate ColumnDefinitions --> ColumnDefinition --> --> ColumnDefinition --> --> Grid.ColumnDefinitions --> TextBlockGrid. Column="0 "Text="{Camino de enlace=Nombre Amistoso, Modo=DeVuelta}"
xml
Comandos basados en UI
Así que mirando nuestro código XAML, en nuestro modelo de vista MainWindowViewModel, necesitamos implementar los siguientes comandos:
- Comandos del menú GuardarLista de reproducciónComando: Este comando guardará nuestra lista de reproducción en un archivo de texto, simplemente escribiendo la ruta de cada pista de la lista de reproducción como Este comando leerá el archivo .playlist de nuestra elección y generará una Playlist para nosotros.ExitApplicationCommand: Este comando dispondrá todos nuestros flujos de audio y cerrará la aplicación.AddFileToPlaylistCommand: Este comando añadirá un único archivo de audio a nuestra lista de reproducción.AddFolderToPlaylistCommand: Este comando agregará una carpeta de archivos a nuestra lista de reproducción.
- Comandos del jugador: «Rebobinar para iniciar el comando»: Este comando pondrá la posición de la pista actual a 0, saltando efectivamente a start.StartPlaybackCommand: Este comando iniciará la reproducción de la PistaActualmente Seleccionada. Si se pulsa durante la reproducción, se detendrá la reproducción.StopPlaybackCommand: Este comando detendrá la reproducción.ForwardToEndCommand: Este comando saltará al último segundo del archivo de audio que se está reproduciendo actualmente.ShuffleCommand: Este comando barajará nuestra lista de reproducción aleatoriamente.
- MVVM EventsTrackControlMouseDownCommand: Este comando se ejecutará cuando presionemos el botón del ratón en el control deslizante de la barra de búsqueda.TrackControlMouseUpCommand: Este comando se ejecutará cuando soltemos el botón del ratón del control deslizante de la barra de búsqueda.VolumeControlValueChangedCommand: Este comando se ejecutará cuando cambiemos el valor del deslizador del control de volumen.
y propiedades:
- Título: El título de la ventana.
- CurrentTrackPosition: Mientras se reproduce el audio, esta propiedad se utiliza para almacenar la posición actual en segundos.
- Volumen actual: Esta propiedad establece el volumen.
- Lista de reproducción: Esta propiedad representa nuestra lista de reproducción.
- Actualmente, la pista seleccionada: Esta propiedad representa la pista actualmente seleccionada en nuestra lista de reproducción.
- Actualmente, jugando a la pista: Esta propiedad representa la pista que se está reproduciendo actualmente en nuestra lista de reproducción.
- PlayPauseImageSource: Esta propiedad establece la reproducción o la pausa de las imágenes dependiendo de si el audio se reproduce o se pausa en nuestro botón de reproducción.