Hola,
hice un listBox en donde se ponen todos los nombres de las canciones que agrego mediante el control button. Pero cuando termina la cancion no se reproduce la siguiente.
Les muestro como trate de que se reproduciera la siguiente cancion cuando termine una con este codigo:
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 8)
{
index = index + 1;
if (index - 1 < listBox1.Items.Count)
{
axWindowsMediaPlayer1.URL = list2[list1.IndexOf(listBox1.Items[index].ToString())];
}
}
}
Se supone que deberia funcionar. Pero para evitar confusiones les mostrare todo el codigo:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Player
{
public partial class Form1 : Form
{
List<string> list1 = new List<string>();
List<string> list2 = new List<string>();
List<string> list3 = new List<string>();
Timer timer1 = new Timer();
int index = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();
ofd.Multiselect = true;
ofd.ShowDialog();
foreach (var file in ofd.SafeFileNames)
{
listBox1.Items.Add(file);
list1.Add(file);
listBox1.Sorted = true;
}
foreach (var file in ofd.FileNames)
{
list2.Add(file);
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)
{
index = listBox1.SelectedIndex;
axWindowsMediaPlayer1.URL = list2[list1.IndexOf(listBox1.GetItemText(listBox1.SelectedItem))];
}
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 8)
{
index = index + 1;
if (index - 1 < listBox1.Items.Count)
{
axWindowsMediaPlayer1.URL = list2[list1.IndexOf(listBox1.Items[index].ToString())];
}
}
}
}
}
Alguien me puede ayudar por favor?
Gracias y saludos
1. No estás liberando la instancia de una clase que implementa la interfaz
IDisposable...
CitarOpenFileDialog ofd = new OpenFileDialog();
2. Estás usando una colección genérica de tipo
List para almacenar las rutas absolutas de unos archivos, y luego otra lista adicional para almacenar los nombres de archivo. Tener dos colecciones distintas para practicamente la misma finalidad (puesto que los nombres de archivo son parte de la ruta absoluta del archivo) es algo completamente innecesario con lo que solo conseguirás escribir un código espagueti (confuso y destructurado) más si les asignas nombres como "list1", "list2" y "list3"...
Hay que mejorar las nomenclaturas de los miembros.
3. Debido a que estás representando una colección de elementos (nombres de archivos), en lugar de utilizar el método
ListBox.Add() deberías utilizar el método
ListBox.AddRange() para mejorar el rendimiento de la aplicación y la respuesta de la UI. Con cada llamada individual que haces a
ListBox.Add() el control envia mensajes de ventana para redibujarse, y eso para añadir 20 canciones no pasa nada, pero si fuesen muchas más pues...acabarías bloqueando la UI por momentos.
4. Estás reasignando el mismo valor a la propiedad
ListBox.Sorted en el controlador
button1_Click, esto son instrucciones de más, algo innecesario. Con asignarle el valor a la propiedad una única vez al cargar el control es suficiente.
5..
No estás comprobando el resultado del diálogo cuando seleccionas archivos... ¿qué ocurre si el usuario cancela la selección?. debes comprobarlo...
6..
Cita de: TickTack en 12 Octubre 2017, 09:51 AMcuando termina la cancion no se reproduce la siguiente.
Prueba a invocar la funcionalidad de reproducir...
this.axWindowsMediaPlayer1.Ctlcontrols.play();
- AxWindowsMediaPlayer.URL property (https://msdn.microsoft.com/en-us/library/windows/desktop/dd562470(v=vs.85).aspx)
- AxWindowsMediaPlayer.Ctlcontrols property (https://msdn.microsoft.com/en-us/library/windows/desktop/dd562401(v=vs.85).aspx)
7..
Citarint index = 0;
...
void ... {
index = index + 1;
if (index - 1 < listBox1.Items.Count) {
axWindowsMediaPlayer1.URL = list2[list1.IndexOf(listBox1.Items[index].ToString())];
}
}
En lugar de la necesidad de declarar un contador y comprobar el estado del reproductor e ir reasignando a cada rato el valor de la propiedad URL para reproducir la siguiente canción, en lugar de todo eso algo más simple sería que añadieses los elementos del
ListBox (las rutas completas de los archivos a reproducir) en una lista de reproducción ( playlist.m3u ) para que el WMP las vaya reproduciendo una tras otra y no tengas que hacer más...
Tienes dos opciones para ello, puedes escribir un archivo de lista de reproducción m3u (no es complicado, es un formato muy sencillo):
- https://en.wikipedia.org/wiki/M3U (https://en.wikipedia.org/wiki/M3U)
O bien puedes puedes crear una lista de manera guiada para usarlo en la instancia actual del WMP mediante la interfáz
IWMPPlaylist
- AxWindowsMediaPlayer.newPlaylist method | MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd562448(v=vs.85).aspx)
- IWMPPlaylist interface | MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd563581(v=vs.85).aspx)
8..
Citarif (e.newState == 8)
¿Has verificado que el valor de la propiedad
NewState sea realmente 8 al terminar de reproducir la canción?. La documentación oficial en la MSDN no recomienda que un algoritmo se base en la "predicción" de los estados del reproductor debido a que al parecer son un poco...impredecibles.
Cita de: MSDNRemarks
Windows Media Player states are not guaranteed to occur in any particular order. Furthermore, not every state necessarily occurs during a sequence of events. You should not write code that relies upon state order.
- AxWindowsMediaPlayer.PlayStateChange Event | MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/dd562460(v=vs.85).aspx)
Nota: En la página de la MSDN tienes un ejemplo extendido para depurar/testear el estado actual del reproductor.
En general todo el código que tienes ahora mismo lo puedes mejorar y simplificar / refactorizar a algo parecido a esto:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
public sealed class Form1 : Form {
const int WMP_MediaEnded = 0x8;
private readonly SortedList<string, string> files; // { Key=file_name, Value=full_path }
private void Form_Load(object sender, EventArgs e) {
this.files = new SortedList<string, string>(StringComparer.Ordinal);
this.listBox1.ValueMember = "key"; // file names
}
private void Button1_Click(object sender, EventArgs e) {
using (OpenFileDialog ofd = new OpenFileDialog { Multiselect = true }) {
ofd.ShowDialog();
DialogResult result = ofd.ShowDialog();
if (result == DialogResult.OK) {
foreach (string filepath in ofd.FileNames) {
this.files.Add(Path.GetFileName(filepath), filepath);
}
this.listBox1.BeginUpdate();
this.listBox1.DataSource = this.files.ToList();
this.listBox1.EndUpdate();
} // if
} // using
}
private void ListBox1_DoubleClick(object sender, EventArgs e) {
this.PlaySongFile(((ListBox)sender).SelectedIndex);
}
private void PlaySongFile(int fileIndex) {
ListBox lb = this.listBox1;
lb.SetSelected(fileIndex, true); // Select the item/song name that is being played.
KeyValuePair<string, string> file = (KeyValuePair<string, string>)lb.SelectedItem;
this.axWindowsMediaPlayer1.URL = file.Value; // full file path
this.axWindowsMediaPlayer1.Ctlcontrols.play();
}
private void AxWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e) {
if (e.newState == WMP_MediaEnded) {
int selectedIndex = this.listBox1.SelectedIndex;
if (this.files.Count < (selectedIndex - 1)) {
this.PlaySongFile(selectedIndex + 1); // Play next item/song file.
}
}
}
}
Nota: Es solo un código de ejemplo para que lo adaptes a tus necesidades, falta que asocies los controladores de evento en el código, no he comprobado que funcione lo de reproducir canciones en el WMP, y tampoco he implementado la funcionalidad de la lista de reproducción ya que lo he propuesto como una mejora opcional y bueno... no voy a hacer yo todo el trabajo, jeje.
Saludos.
Hola Elektro,
1. No es lo mismo OpenFileDialog ofd = new OpenFileDialog(); que System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();?
2. Es necesario que lo que haga de esta manera ya que necesito por un lado mostrar los nombres de las canciones en el listBox y por el otro lado guardar las rutas para reproducir esas canciones. Y aunque los nombres sean partes de las rutas... separarlos, segun yo, lleva mas tiempo que el codigo espagueti.
3. Bueno eso tendre que cambiarlo. Gracias por la informacion. :)
4. Yo no veo ninguna instruccion de mas. Solamente le asigne una vez una valor a ListBox.Sorted.
5. Ay si... eso me olvide... jeje
6. Ya lo probe antes de hacer este post.
7. Ok. Quiero ir por ese camino...
8. Eso tampoco lo supe. Pero no se me da la posibilidad de escribir if (e.newState == WMP_MediaEnded) { ya que me larga error con WMP_MediaEnded. Me dice que no existe.
Si te diste cuenta del error por favor informame. Te estare my agradecido
Gracias y saludos
PD.: Tu codigo se me hizo dificil de harmonizarlo con el mio pero igual muchas gracias. (Es que tienes una forma complicada de escribir codigos, quiza por los grandes programas o codigos comerciales que ya hiciste, osea esa por esa experiencia).
Cita de: TickTack en 12 Octubre 2017, 18:31 PM1. No es lo mismo OpenFileDialog ofd = new OpenFileDialog(); que System.Windows.Forms.OpenFileDialog ofd = new System.Windows.Forms.OpenFileDialog();?
Si, por supuesto, simplemente borré el nombre del namespace al citar tu código, y lo cité solamente para hacer referencia a la instrucción de tú código a la que me estaba refiriendo, pero a lo que me refería es a que debes utilizar la sentencia
using para asegurarte de que el
GC (
Garbage Collector) libere cualquier recurso administrado y no administrado que haya sido utilizado por "X" instancia
IDisposable... y así tener (o al menos intentarlo) una aplicación libre de las indeseadas fugas de consumo RAM.
Es decir:
using ( OpenFileDialog ofd = new OpenFileDialog() ) {
// ...
}
- using Statement (C# Reference) | docs.microsoft.com (https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement)
...o en su defecto puedes usar el método
IDisposable.Dispose() (
OpenFileDialog.Dispose() ).
- IDisposable.Dispose Method | MSDN (https://msdn.microsoft.com/en-us/library/system.idisposable.dispose(v=vs.110).aspx)
Cita de: TickTack en 12 Octubre 2017, 18:31 PM2. Es necesario que lo que haga de esta manera ya que necesito por un lado mostrar los nombres de las canciones en el listBox y por el otro lado guardar las rutas para reproducir esas canciones. Y aunque los nombres sean partes de las rutas... separarlos, segun yo, lleva mas tiempo que el codigo espagueti.
No, no es necesario ni tampoco lleva más tiempo en términos de esfuerzo. En mi última respuesta te mostré un código en el que utilizo una colección genérica de tipo
SortedList para almacenar ambos datos... y cuyos elementos se mantienen ordenados por orden alfabético según el nombre de cada archivo agregado en o eliminado de la colección...
Como ves, es una mejora que simplifica tres funcionalidades del código original, en una sola.
Cita de: TickTack en 12 Octubre 2017, 18:31 PM3. Bueno eso tendre que cambiarlo. Gracias por la informacion. :)
Si sigues la solución que te indiqué (vease el código que compartí en mi última respuesta) entonces no necesitas usar el método
Add /
AddRange ya que en su lugar se utiliza la colección
SortedList como
datasource. Pero de todos modos la utilización del método
AddRange es una mejora significativa que siempre deberías tener en cuenta cuando necesites agregar elementos manualmente a un control de tipo Lista (ListBox, ListView, DataGridView, etc).
Cita de: TickTack en 12 Octubre 2017, 18:31 PM4. Yo no veo ninguna instruccion de mas. Solamente le asigne una vez una valor a ListBox.Sorted.
Citar foreach (var file in ofd.SafeFileNames)
{
listBox1.Items.Add(file);
list1.Add(file);
listBox1.Sorted = true;
}
Fíjate bien, le estás reasignando el valor en cada iteración del búcle
foreach, es decir, 'listBox1.Sorted = true' por cada elemento en 'ofd.SafeFileNames'.
Cita de: TickTack en 12 Octubre 2017, 18:31 PM
6. Ya lo probe antes de hacer este post.
7. Ok. Quiero ir por ese camino...
De acuerdo, entonces por si te sirve de algo te muestro un algoritmo que desarrollé hace un par de años para construir listas de reproducción en formato M3U y PLS de forma sencilla. El código es un poco feo, lo escribí hace varios años, se puede refactorizar para perfeccionarlo de muchas formas para representarlo de forma más abstracta y llevar a cabo todas las modificaciones en la memoria sin realizar operaciones de lectura/escritura en el archivo, pero bueno, así lo escribí en su día cuando todavía no dominaba muchas cosas en la progamación .NET, y el caso es que funciona, que es lo importante...
NOTA INFORMATIVA:
--- EL SIGUIENTE CÓDIGO HA SIDO EXTRAIDO Y OFRECIDO DE FORMA GRATUITA A PARTIR DE MI FRAMEWORK COMERCIAL ELEKTROKIT FRAMEWORK , EL CUAL CONTIENE UNA INFINIDAD DE UTILIDADES ENFOCADAS A UNA AMPLIA VARIEDAD DE TEMÁTICAS Y ESCENARIOS EN LA PROGRAMACIÓN .NET, COMO ÉSTE. SI QUIEREN CONOCER MÁS ACERCA DEL PRODUCTO, MIREN MI FIRMA DE USUARIO EN EL FORO. ---
---
ESTE CÓDIGO SE PUEDE USAR DE FORMA LIBRE COMO DESEEN.Nota: Debido a que el foro tiene un límite muy reducido de caracteres, me he visto obligado a eliminar gran parte de la documentación XML ( descripciones de parámetros, etc).
#Region " Playlist Type "
Namespace ElektroKit.Core.Multimedia.Enums
''' <summary>
''' Specifies the type of a multimedia playlist.
''' </summary>
Public Enum PlaylistType As Integer
''' <summary>
''' M3U Playlist.
''' <para></para>
''' <see href="http://en.wikipedia.org/wiki/M3U"/>
''' </summary>
M3U = 0I
''' <summary>
''' PLS Playlist.
''' <para></para>
''' <see href="http://en.wikipedia.org/wiki/PLS_%28file_format%29"/>
''' </summary>
PLS = 1I
End Enum
End Namespace
#End Region
#Region " Playlist TrackInfo "
Namespace ElektroKit.Core.Multimedia.Types
''' <summary>
''' Represents a track of a multimedia playlist.
''' </summary>
Public Structure PlaylistTrackInfo
#Region " Properties "
''' <summary>
''' Gets the track index.
''' <para></para>
''' This value is automatically set by some of the <see cref="PlaylistEditor"/> class members,
''' and has none effect if you change it manually.
''' </summary>
Public Property Index As Integer
''' <summary>
''' Gets or sets the file path.
''' </summary>
Public Property Path As String
''' <summary>
''' Gets or sets the track title.
''' </summary>
Public Property Title As String
''' <summary>
''' Gets or sets the track length.
''' </summary>
Public Property Length As TimeSpan
#End Region
End Structure
End Namespace
#End Region
#Region " Imports "
Imports System.Collections.ObjectModel
Imports System.IO
Imports System.Text
Imports ElektroKit.Core.Multimedia.Enums
#End Region
#Region " Playlist Editor "
Namespace ElektroKit.Core.Multimedia.Types
''' <summary>
''' Contains methods to create and or manage the tracks defined in a multimedia playlist file.
''' </summary>
Public NotInheritable Class PlaylistEditor
#Region " Properties "
''' <summary>
''' Gets the playlist filepath.
''' </summary>
Public ReadOnly Property FilePath As String
<DebuggerStepThrough>
Get
Return Me.filepathB
End Get
End Property
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' ( Backing field )
''' The playlist filepath.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Private ReadOnly filepathB As String
''' <summary>
''' Gets the playlist type.
''' </summary>
Public ReadOnly Property PlaylistType As PlaylistType
Get
Return Me.playlistTypeB
End Get
End Property
Private ReadOnly playlistTypeB As PlaylistType
''' <summary>
''' Gets the text encoding of the playlist file.
''' </summary>
Public ReadOnly Property FileEncoding As Encoding
Get
Return Me.encodingB
End Get
End Property
Private ReadOnly encodingB As Encoding
''' <summary>
''' Gets a value indicating whether the text will be appended at the bottom of the playlist file.
''' </summary>
Public ReadOnly Property Append As Boolean
<DebuggerStepThrough>
Get
Return Me.appendB
End Get
End Property
Private ReadOnly appendB As Boolean
''' <summary>
''' Gets a collection that represents the tracks defined (if any) in the playlist.
''' </summary>
Public ReadOnly Property Tracks As ReadOnlyCollection(Of PlaylistTrackInfo)
<DebuggerStepThrough>
Get
Return New ReadOnlyCollection(Of PlaylistTrackInfo)(Me.GetTracks)
End Get
End Property
''' <summary>
''' Gets the amount of tracks defined in the playlist.
''' </summary>
Public ReadOnly Property Count As Integer
<DebuggerStepThrough>
Get
Return Me.GetTracks.Count
End Get
End Property
#End Region
#Region " Constructors "
<DebuggerNonUserCode>
Private Sub New()
End Sub
''' <summary>
''' Initializes a new instance of the <see cref="PlaylistEditor"/> class.
''' </summary>
'''
''' <param name="playlistFile">
''' The playlist file path.
''' </param>
''' <param name="playlistType">
''' The type of the playlist.
''' </param>
''' <param name="createNew">
''' If set to <see langword="True"/>,
''' the <see cref="PlaylistEditor"/> instance will assume that the playlist file already exist,
''' and it will append any new track entries to the bottom of the playlist file.
''' <para></para>
''' If set to <see langword="False"/>,
''' the <see cref="PlaylistEditor"/> instance will assume that the playlist file does not exist,
''' so then it will create a new playlist file.
''' </param>
''' <param name="fileEncoding">
''' Optionally indicates the file encoding to perform write and read operations to the playlist file.
''' <para></para>
''' Default value is: <see cref="Encoding.Default"/>
''' </param>
<DebuggerStepThrough>
Public Sub New(ByVal playlistFile As String,
ByVal playlistType As PlaylistType,
ByVal createNew As Boolean,
Optional ByVal fileEncoding As Encoding = Nothing)
Me.filepathB = playlistFile
Me.playlistTypeB = playlistType
Me.encodingB = If(fileEncoding IsNot Nothing, fileEncoding, Encoding.Default)
Me.appendB = Not createNew
If Not (appendB) Then
Me.AddHeaders()
End If
End Sub
#End Region
#Region " Public Methods "
''' <summary>
''' Adds a new track entry in the playlist.
''' </summary>
<DebuggerStepThrough>
Public Sub Add(ByVal filepath As String,
Optional ByVal throwOnDuplicate As Boolean = False)
If Not (throwOnDuplicate) AndAlso Me.Exist(filepath) Then
Throw New ArgumentException("The specified file path already exists in the playlist.",
paramName:="filepath")
End If
Dim sb As New StringBuilder
Select Case Me.playlistTypeB
Case PlaylistType.M3U
sb.AppendLine()
sb.AppendLine(filepath)
File.AppendAllText(Me.filepathB, sb.ToString(), Me.encodingB)
Case PlaylistType.PLS
Dim tacksCount As Integer = Me.GetPlsTrackCount()
sb.AppendLine(File.ReadAllText(Me.filepathB, Me.encodingB).
Replace("NumberOfEntries=" & CStr(tacksCount),
"NumberOfEntries=" & CStr(tacksCount + 1)))
sb.AppendLine(String.Format("File{0}={1}", CStr(tacksCount + 1), filepath.Replace("\", "/")))
File.WriteAllText(Me.filepathB, sb.ToString(), Me.encodingB)
End Select
sb.Clear()
End Sub
''' <summary>
''' Adds a new track in the playlist, with extended track information.
''' </summary>
<DebuggerStepThrough>
Public Sub Add(ByVal filepath As String, ByVal title As String, ByVal length As TimeSpan,
Optional ByVal throwOnDuplicate As Boolean = False)
If Not (throwOnDuplicate) AndAlso Me.Exist(filepath) Then
Throw New ArgumentException("The specified file path already exists in the playlist.",
paramName:="filepath")
End If
Dim sb As New StringBuilder
Select Case Me.playlistTypeB
Case PlaylistType.M3U
sb.AppendLine()
sb.AppendLine(String.Format("#EXTINF:{0},{1}", CStr(Math.Truncate(length.TotalSeconds)), title))
sb.AppendLine(filepath)
File.AppendAllText(Me.filepathB, sb.ToString(), Me.encodingB)
Case PlaylistType.PLS
Dim tacksCount As Integer = Me.GetPlsTrackCount()
sb.AppendLine(File.ReadAllText(Me.filepathB, Me.encodingB).
Replace("NumberOfEntries=" & CStr(tacksCount),
"NumberOfEntries=" & CStr(tacksCount + 1I)))
sb.AppendLine(String.Format("File{0}={1}", CStr(tacksCount + 1I), filepath.Replace("\", "/")))
sb.AppendLine(String.Format("Title{0}={1}", CStr(tacksCount + 1I), title))
sb.AppendLine(String.Format("Length{0}={1}", CStr(tacksCount + 1I), CStr(Math.Truncate(length.TotalSeconds))))
File.WriteAllText(Me.filepathB, sb.ToString(), Me.encodingB)
End Select
sb.Clear()
End Sub
''' <summary>
''' Adds a new track in the playlist, with extended track information.
''' </summary>
<DebuggerStepThrough>
Public Sub Add(ByVal trackInfo As PlaylistTrackInfo,
Optional ByVal throwOnDuplicate As Boolean = False)
Me.Add(trackInfo.Path, trackInfo.Title, trackInfo.Length, throwOnDuplicate)
End Sub
''' <summary>
''' Removes the specified track from the playlist.
''' </summary>
<DebuggerStepThrough>
Public Sub RemoveTrack(ByVal filepath As String)
If Not Me.Exist(filepath) Then
Throw New ArgumentException("The specified file path does not exists in the playlist.",
paramName:="filepath")
End If
Dim playlistContent As List(Of String) = File.ReadLines(Me.filepathB, Me.encodingB).ToList()
Select Case Me.playlistTypeB
Case PlaylistType.M3U
Dim entryIndex As Integer =
playlistContent.FindIndex(
Function(item As String)
Return item.Equals(filepath, StringComparison.OrdinalIgnoreCase)
End Function)
playlistContent.RemoveAt(entryIndex)
If playlistContent(entryIndex - 1).StartsWith("#EXTINF", StringComparison.OrdinalIgnoreCase) Then
playlistContent.RemoveAt(entryIndex - 1)
End If
File.WriteAllLines(Me.filepathB, playlistContent, Me.encodingB)
Case PlaylistType.PLS
Dim entryIndex As Integer =
playlistContent.FindIndex(
Function(item As String)
Return item.ToLower Like "file#*" & filepath.Replace("\", "/").ToLower
End Function)
Dim trackIndexDelimStartIndex As Integer =
playlistContent(entryIndex).IndexOf("e", StringComparison.OrdinalIgnoreCase) + 1I
Dim trackIndexDelimEndIndex As Integer =
playlistContent(entryIndex).IndexOf("=", StringComparison.OrdinalIgnoreCase)
Dim trackIndex As Integer =
CInt(playlistContent(entryIndex).Substring(trackIndexDelimStartIndex,
trackIndexDelimEndIndex - trackIndexDelimStartIndex))
playlistContent.RemoveAt(entryIndex)
Dim titleEntryIndex As Integer =
playlistContent.FindIndex(Function(item As String)
Return item.ToLower Like String.Format("title{0}=*", CStr(trackIndex))
End Function)
If titleEntryIndex <> -1 Then
playlistContent.RemoveAt(titleEntryIndex)
End If
Dim lengthEntryIndex As Integer =
playlistContent.FindIndex(Function(item As String)
Return item.ToLower Like String.Format("length{0}=*", CStr(trackIndex))
End Function)
If lengthEntryIndex <> -1I Then
playlistContent.RemoveAt(lengthEntryIndex)
End If
Dim numberOfEntriesEntryIndex As Integer =
playlistContent.FindIndex(Function(item As String)
Return item.ToLower Like "numberofentries=#*"
End Function)
playlistContent(numberOfEntriesEntryIndex) =
String.Format("NumberOfEntries={0}", CStr(Me.GetPlsTrackCount() - 1))
File.WriteAllLines(Me.filepathB, playlistContent, Me.encodingB)
Me.FixPlsTrackIndices()
End Select
End Sub
''' <summary>
''' Removes the specified track from the playlist.
''' </summary>
<DebuggerStepThrough>
Public Sub RemoveTrack(ByVal trackIndex As Integer)
Dim track As PlaylistTrackInfo = Me.GetTrackInfo(trackIndex)
If track IsNot Nothing Then
Me.RemoveTrack(track.Path)
Else
Throw New IndexOutOfRangeException("Track index is out of range") With {.Source = "trackIndex"}
End If
End Sub
''' <summary>
''' Sets the track info of the specified track.
''' </summary>
<DebuggerStepThrough>
Public Sub SetTrackInfo(ByVal filepath As String, ByVal trackInfo As PlaylistTrackInfo)
If Not Me.Exist(filepath) Then
Throw New ArgumentException("The specified file path does not exists in the playlist.",
paramName:="filepath")
End If
Dim track As PlaylistTrackInfo = Me.GetTrackInfo(filepath)
With track
.Path = trackInfo.Path
.Title = trackInfo.Title
.Length = trackInfo.Length
End With
Dim playlistContent As List(Of String) = File.ReadLines(Me.filepathB, Me.encodingB).ToList()
Select Case Me.playlistTypeB
Case PlaylistType.M3U
Dim trackIndex As Integer =
playlistContent.FindIndex(
Function(item As String)
Return item.Equals(filepath, StringComparison.OrdinalIgnoreCase)
End Function)
playlistContent(trackIndex) = String.Format("#EXTINF:{0},{1}",
CStr(Math.Truncate(track.Length.TotalSeconds)),
track.Title) & Environment.NewLine & track.Path
If playlistContent(trackIndex - 1I).StartsWith("#EXTINF", StringComparison.OrdinalIgnoreCase) Then
playlistContent.RemoveAt(trackIndex - 1I)
End If
File.WriteAllLines(Me.filepathB, playlistContent, Me.encodingB)
Case PlaylistType.PLS
track.Path = track.Path.Replace("\", "/")
Dim trackIndex As Integer =
playlistContent.FindIndex(
Function(item As String)
Return item.ToLower Like "file#*" & filepath.Replace("\", "/").ToLower
End Function)
playlistContent(trackIndex) = String.Format("File{0}={1}", CStr(track.Index), track.Path) & Environment.NewLine &
String.Format("Title{0}={1}", CStr(track.Index), track.Title) & Environment.NewLine &
String.Format("Length{0}={1}", CStr(track.Index), CStr(Math.Truncate(track.Length.TotalSeconds)))
If playlistContent.Count > (trackIndex + 1) Then
If playlistContent(trackIndex + 2).StartsWith("Title", StringComparison.OrdinalIgnoreCase) _
OrElse playlistContent(trackIndex + 2).StartsWith("Length", StringComparison.OrdinalIgnoreCase) Then
playlistContent.RemoveAt(trackIndex + 2)
End If
End If
If playlistContent.Count > trackIndex Then
If playlistContent(trackIndex + 1).StartsWith("Title", StringComparison.OrdinalIgnoreCase) _
OrElse playlistContent(trackIndex + 1).StartsWith("Length", StringComparison.OrdinalIgnoreCase) Then
playlistContent.RemoveAt(trackIndex + 1)
End If
End If
File.WriteAllLines(Me.filepathB, playlistContent, Me.encodingB)
End Select
End Sub
''' <summary>
''' Sets the track info of the specified track.
''' </summary>
<DebuggerStepThrough>
Public Sub SetTrackInfo(ByVal trackIndex As Integer, ByVal trackInfo As PlaylistTrackInfo)
If Not Me.Exist(trackIndex) Then
Throw New IndexOutOfRangeException("Track index is out of range.") With {.Source = "trackIndex"}
End If
Me.SetTrackInfo(Me.GetTrackInfo(trackIndex).Path, trackInfo)
End Sub
''' <summary>
''' Finds the specified track in the playlist and returns a
''' <see cref="PlaylistTrackInfo"/> instance that represents the track.
''' </summary>
<DebuggerStepThrough>
Public Function GetTrackInfo(ByVal filepath As String) As PlaylistTrackInfo
Dim playlistContent As List(Of String) = File.ReadLines(Me.filepathB, Me.encodingB).ToList()
Dim tInfo As New PlaylistTrackInfo
Select Case Me.playlistTypeB
Case PlaylistType.M3U
Dim trackIndex As Integer = playlistContent.FindIndex(
Function(item As String)
Return item.Equals(filepath, StringComparison.OrdinalIgnoreCase)
End Function) - 1
If playlistContent(trackIndex).StartsWith("#EXTINF", StringComparison.OrdinalIgnoreCase) Then
Dim titleDelimIndex As Integer = playlistContent(trackIndex).IndexOf(","c) + 1
Dim lengthDelimIndex As Integer = playlistContent(trackIndex).IndexOf(":"c) + 1
With tInfo
.Index = trackIndex
.Path = filepath
.Title = playlistContent(trackIndex).Substring(titleDelimIndex)
.Length = TimeSpan.FromSeconds(CDbl(playlistContent(trackIndex).Substring(lengthDelimIndex, (titleDelimIndex - lengthDelimIndex))))
End With
End If
Case PlaylistType.PLS
filepath = filepath.Replace("\", "/")
Dim entry As String = (From Item As String In playlistContent
Where Item.ToLower Like String.Format("file#*={0}", filepath.ToLower())).SingleOrDefault
If Not String.IsNullOrEmpty(entry) Then
Dim indexDelimStartIndex As Integer =
entry.IndexOf("e", StringComparison.OrdinalIgnoreCase) + 1I
Dim indexDelimEndIndex As Integer =
entry.IndexOf("=", StringComparison.OrdinalIgnoreCase)
Dim trackIndex As Integer = CInt(entry.Substring(indexDelimStartIndex,
indexDelimEndIndex - indexDelimStartIndex))
Dim titleEntry As String = (From Item As String In playlistContent
Where Item.StartsWith(String.Format("Title{0}=", CStr(trackIndex)), StringComparison.OrdinalIgnoreCase)).
FirstOrDefault
Dim lengthEntry As String = (From Item As String In playlistContent
Where Item.StartsWith(String.Format("Length{0}=", CStr(trackIndex)), StringComparison.OrdinalIgnoreCase)).
FirstOrDefault
With tInfo
.Index = trackIndex
.Path = filepath
.Title = If(Not String.IsNullOrEmpty(titleEntry),
titleEntry.Substring(titleEntry.IndexOf("=") + 1),
Nothing)
.Length = If(Not String.IsNullOrEmpty(titleEntry),
TimeSpan.FromSeconds(CDbl(lengthEntry.Split("="c).LastOrDefault)),
Nothing)
End With
End If
End Select
Return tInfo
End Function
''' <summary>
''' Finds the specified track in the playlist and returns a
''' <see cref="PlaylistTrackInfo"/> instance that represents the track.
''' </summary>
<DebuggerStepThrough>
Public Function GetTrackInfo(ByVal trackIndex As Integer) As PlaylistTrackInfo
Dim playlistContent As List(Of String) = File.ReadLines(Me.filepathB, Me.encodingB).ToList()
Select Case Me.playlistTypeB
Case PlaylistType.M3U
Dim trackCount As Integer = 0
For index As Integer = 0 To (playlistContent.Count - 1)
If Not String.IsNullOrEmpty(playlistContent(index)) _
AndAlso Not playlistContent(index).StartsWith("#EXT", StringComparison.OrdinalIgnoreCase) Then
trackCount += 1
If (trackCount = trackIndex) Then
Dim tInfo As PlaylistTrackInfo = Me.GetTrackInfo(playlistContent(index))
With tInfo
.Index = trackIndex
.Path = playlistContent(index)
End With
Return tInfo
End If
End If
Next index
Case PlaylistType.PLS
For index As Integer = 0 To (playlistContent.Count - 1)
If playlistContent(index).StartsWith(String.Format("File{0}=", CStr(trackIndex)),
StringComparison.OrdinalIgnoreCase) Then
Return Me.GetTrackInfo(playlistContent(index).Substring(playlistContent(index).IndexOf("="c) + 1I))
End If
Next index
End Select
Return Nothing
End Function
''' <summary>
''' Determines whether the specified track exists in the playlist.
''' </summary>
<DebuggerStepThrough>
Public Function Exist(ByVal filepath As String) As Boolean
Dim returnValue As Boolean = False
Select Case Me.playlistTypeB
Case PlaylistType.M3U
returnValue = (From Item As String In File.ReadLines(Me.filepathB, Me.encodingB)
Where Item.StartsWith(filepath, StringComparison.OrdinalIgnoreCase)).
Any()
Case PlaylistType.PLS
returnValue = (From Item As String In File.ReadLines(Me.filepathB, Me.encodingB)
Where Item.ToLower() Like "file#*" & filepath.Replace("\", "/").ToLower()).
Any()
End Select
Return returnValue
End Function
''' <summary>
''' Determines whether the specified track exists in the playlist.
''' </summary>
<DebuggerStepThrough>
Public Function Exist(ByVal trackIndex As Integer) As Boolean
If (trackIndex <= 0) Then
Throw New IndexOutOfRangeException("TrackIndex should be greater than 0.") With {.Source = "trackIndex"}
End If
Return (Me.Count >= trackIndex)
End Function
#End Region
#Region " Private Methods "
''' <summary>
''' Collects all the tracks defined in a playlist file and returns a <see cref="List(Of PlaylistTrackInfo)"/>.
''' </summary>
<DebuggerStepThrough>
Private Function GetTracks() As List(Of PlaylistTrackInfo)
Dim playlistContent As List(Of String) = File.ReadLines(Me.filepathB, Me.encodingB).ToList()
Dim tInfo As New List(Of PlaylistTrackInfo)
Dim trackCount As Integer = 0
Select Case Me.playlistTypeB
Case PlaylistType.M3U
For index As Integer = 0 To (playlistContent.Count - 1)
If Not String.IsNullOrEmpty(playlistContent(index)) _
AndAlso Not playlistContent(index).StartsWith("#EXT", StringComparison.OrdinalIgnoreCase) Then
trackCount += 1
tInfo.Add(Me.GetTrackInfo(trackCount))
End If
Next
Case PlaylistType.PLS
For index As Integer = 0 To (playlistContent.Count - 1)
If playlistContent(index).StartsWith("File", StringComparison.OrdinalIgnoreCase) Then
trackCount += 1
tInfo.Add(Me.GetTrackInfo(trackCount))
End If
Next index
End Select
Return tInfo
End Function
''' <summary>
''' Adds the playlist headers at the top of the playlist file.
''' <para></para>
''' This method should always be called before adding the very first entry in a new (empty) playlist.
''' </summary>
<DebuggerStepThrough>
Private Sub AddHeaders()
Dim sb As New StringBuilder
Select Case Me.playlistTypeB
Case PlaylistType.M3U
sb.AppendLine("#EXTM3U")
Case PlaylistType.PLS
With sb
.AppendLine("[playlist]")
.AppendLine("NumberOfEntries=0")
.AppendLine("Version=2")
End With
End Select
File.WriteAllText(Me.filepathB, sb.ToString(), Me.encodingB)
sb.Clear()
End Sub
''' <summary>
''' Gets the amount of total tracks defined in a PLS playlist file.
''' </summary>
<DebuggerStepThrough>
Private Function GetPlsTrackCount() As Integer
Dim playlistContent As String = File.ReadAllText(Me.filepathB, Me.encodingB)
Dim startIndex As Integer =
playlistContent.IndexOf("=") + 1I
Dim endIndex As Integer =
playlistContent.IndexOf(ControlChars.NewLine, startIndex) - startIndex
Return CInt(playlistContent.Substring(startIndex, playlistContent.IndexOf(String.Empty, endIndex)))
End Function
''' <summary>
''' Fixes the track indices of a PLS playlist file.
''' <para></para>
''' This method shoould always be called after removing a track from the playlist.
''' </summary>
<DebuggerStepThrough>
Private Sub FixPlsTrackIndices()
Dim playlistContent As List(Of String) = File.ReadLines(Me.filepathB, Me.encodingB).ToList()
Dim trackCount As Integer = 0I
For index As Integer = 0 To (playlistContent.Count - 1I)
If playlistContent(index).StartsWith("File", StringComparison.OrdinalIgnoreCase) Then
trackCount += 1I
playlistContent(index) = String.Format("File{0}={1}",
CStr(trackCount),
playlistContent(index).Substring(playlistContent(index).IndexOf("="c) + 1I))
ElseIf playlistContent(index).StartsWith("Title", StringComparison.OrdinalIgnoreCase) Then
playlistContent(index) = String.Format("Title{0}={1}",
CStr(trackCount),
playlistContent(index).Substring(playlistContent(index).IndexOf("="c) + 1I))
ElseIf playlistContent(index).StartsWith("Length", StringComparison.OrdinalIgnoreCase) Then
playlistContent(index) = String.Format("Length{0}={1}",
CStr(trackCount),
playlistContent(index).Substring(playlistContent(index).IndexOf("="c) + 1I))
End If
Next index
Dim numberOfEntriesEntryIndex As Integer =
playlistContent.FindIndex(Function(item As String)
Return item.ToLower Like "numberofentries=#*"
End Function)
playlistContent(numberOfEntriesEntryIndex) =
String.Format("NumberOfEntries={0}", CStr(trackCount))
File.WriteAllLines(Me.filepathB, playlistContent, Me.encodingB)
End Sub
#End Region
End Class
End Namespace
#End Region
El código de arriba puedes tomarlo como ejemplo y nada más para saber como sería una posible manera de poder hacerlo, o bien puedes copiar y pegarlo en una nueva clase de VB.NET para compilarlo en una dll y usarlo en C#, o también puedes convertir directamente el código a C# por ejemplo usando mi conversor de código gratuito (
todos los créditos y copyright para Telerik xD ):
- [SOURCE-CODE] Telerik Code Converter Client for Windows - by Elektro Studios (http://foro.elhacker.net/net/sourcecode_telerik_code_converter_client_for_windows_by_elektro_studios-t474580.0.html)
Modo de empleo:
PlaylistEditor editor = new PlaylistEditor(@"C:\playlist.m3u", PlaylistType.M3U, createNew: true);
editor.Add("C:\\File 1.mp3");
editor.Add("C:\\File 2.mp3");
O bien:
PlaylistEditor editor = new PlaylistEditor(@"C:\playlist.m3u", PlaylistType.M3U, createNew: true);
PlaylistTrackInfo trackInfo = new PlaylistTrackInfo();
trackInfo.Path = "C:\\File.mp3";
trackInfo.Title = {Track Title or Display Name};
trackInfo.Length = {Track Duration};
editor.Add(trackInfo);
Saludos
Hola Elektro,
1. Muchas gracias por tu consejo. Ya lo hize. Pero me gustaria saber como es que estas siempre
informado de que esto produce fugas de consume RAM y lo otro envia mensajes de ventana para
redibujarse y que este otro produce esto? Es increible tu conocimiento!!
2. Ahh si. De esto queria hablar. Es que tu codigo que mostraste se complica con mi proyecto
porque para empezar me da problemas con public souled class. Me dice que no se puede dejarlo
asi porque hay otra clase que ya esta asi. Ni idea? Luego me dice que no se puede acceder
a files por motivos de seguridad y son todas cosas con las que nunca me tope por la falta de
experiencia.....
4. Noooooooooooooooo. Que idiota que soy. Ni me di cuenta. Perdon por lo bruto que soy.. jejej.
5. Pero entonces cual me dices que es mas recomendable usar? Tu codigo 1 o tu codigo 2
(posteaste dos codigos tuyos aca). Porque si me dices codigo 1 entonces vere que puedo hacer
con el problema de public souled class y lo demas. Pero si me dices codigo 2 entonces
podre pegar el codigo en una nueva clase de VB.NET para compilarlo en una dll y
posteriormente usarlo en C#. Finalmente si me dices que investigue los dos codigos lo hare
(por supuesto, solamente si me lo recomiendas).
Para terminar te muestro como quedo el codigo hasta ahora segun tu:
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using WMPLib;
namespace Player
{
public partial class Form1 : Form
{
List<string> list1 = new List<string>();
List<string> list2 = new List<string>();
List<string> list3 = new List<string>();
Timer timer1 = new Timer();
int index = 0;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
using (OpenFileDialog ofd = new OpenFileDialog())
{
ofd.Multiselect = true;
if (ofd.ShowDialog() == DialogResult.OK)
{
listBox1.Sorted = true;
foreach (var file in ofd.SafeFileNames)
{
listBox1.Items.Add(file);
list1.Add(file);
}
foreach (var file in ofd.FileNames)
{
list2.Add(file);
}
}
}
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)
{
index = listBox1.SelectedIndex;
axWindowsMediaPlayer1.URL = list2[list1.IndexOf(listBox1.GetItemText(listBox1.SelectedItem))];
}
private void axWindowsMediaPlayer1_PlayStateChange(object sender, AxWMPLib._WMPOCXEvents_PlayStateChangeEvent e)
{
if (e.newState == 8)
{
index = index + 1;
if (index - 1 < listBox1.Items.Count)
{
axWindowsMediaPlayer1.URL = list2[list1.IndexOf(listBox1.Items[index].ToString())];
}
}
}
}
}
Gracias y saludos
Cita de: TickTack en 13 Octubre 2017, 11:16 AM1. me gustaria saber como es que estas siempre informado de que esto produce fugas de consume RAM y lo otro envia mensajes de ventana para
redibujarse y que este otro produce esto? Es increible tu conocimiento!!
Te agradezco el reconocimiento pero en realidad en mi opinión no son cosas avanzadas que se merezcan " "admiración" " hacia alguien, o al menos yo creo que deberían ser cosas básicas que se deben aprender estudiando el lenguaje, documentándose sobre como se administran los recursos, o como trabaja el sistema de mensajería, GDI/GDI+, WinForms, etc...
Siempre he sostenido que no hay mejor manera de aprender .NET que leyendo la MSDN (aunque sea un coñazo), por que en los libros suelen explicar los conceptos más "internos" de forma superficial, y luego pasa lo que pasa, que uno aprende a manejar C#/VB.NET pero eso no es suficiente ya que no aprende como funciona el sistema operativo (Windows) ni la tecnología que esté usando (WinForms, WPF, etc).
Te dejo unos enlaces de interés:
Administración de recursos:
- Cleaning Up Unmanaged Resources | docs.microsoft.com (https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/unmanaged)
- Using objects that implement IDisposable | docs.microsoft.com (https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/using-objects)
- Garbage Collection | docs.microsoft.com (https://docs.microsoft.com/en-us/dotnet/standard/garbage-collection/)
- Garbage Collector Basics and Performance Hints | MSDN (https://msdn.microsoft.com/en-us/library/ms973837.aspx)
Mensajería
- About Messages and Message Queues | MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx)
- Window Messages | MSDN (https://msdn.microsoft.com/en-us/library/windows/desktop/ms644927(v=vs.85).aspx)
Painting
- About Painting and Drawing | MSDN (https://msdn.microsoft.com/en-us/library/dd183315(v=VS.85).aspx)
ListBox
- ListBox.BeginUpdate() Method | MSDN (https://msdn.microsoft.com/en-us/library/system.windows.forms.listbox.beginupdate(v=vs.110).aspx)
Con respecto a lo que te expliqué de usar el método AddRange, en ese último enlace está documentado también:
Cita de: MSDNRemarks
The preferred way to add multiple items to the ListBox is to use the AddRange method of the ListBox.ObjectCollection class (through the Items property of the ListBox). This enables you to add an array of items to the list in a single operation. However, if you want to add items one at a time using the Add method of the ListBox.ObjectCollection class, you can use the BeginUpdate method to prevent the control from repainting the ListBox each time an item is added to the list. Once you have completed the task of adding items to the list, call the EndUpdate method to enable the ListBox to repaint. This way of adding items can prevent flickered drawing of the ListBox when a large number of items are being added to the list.
En fin, si llegas a leer todos los enlaces que voy poniendo a la MSDN y docs.microsoft.com (no me refiero solo a los que he compartido ahora, sino en general), aprenderías mucho sobre .NET a "nivel gurú" o casi xD. :P
- Manuales de .NET (http://foro.elhacker.net/net/manuales_de_net-t122607.0.html;msg1960666#msg1960666)
Analizar el código fuente de .NET Framework también ayuda mucho a comprender como funciona a nivel "interno":
- https://referencesource.microsoft.com/
Cita de: TickTack en 13 Octubre 2017, 11:16 AM
2. tu codigo que mostraste se complica con mi proyecto
porque para empezar me da problemas con public souled class. Me dice que no se puede dejarlo
asi porque hay otra clase que ya esta asi. Ni idea?
Cita de: Eleкtro en 12 Octubre 2017, 13:50 PM
En general todo el código que tienes ahora mismo lo puedes mejorar y simplificar / refactorizar a algo parecido a esto:
public sealed class Form1 : Form {
// código relevante aquí ...
}
Lo de "
public sealed class Form1 : Form" es así por que yo escribí el código en un nuevo proyecto, pero te dije que lo tienes que adaptar, no tienes que copiar los modificadores (sealed) ni tampoco el nombre de la clase (Form1), sino el resto del código (código relevante) que está definido dentro de esa clase.
En tu código imagino que lo tendrás escrito así:
public partial class Form1
...no necesitas cambiarlo.
Cita de: TickTack en 13 Octubre 2017, 11:16 AM
5. Pero entonces cual me dices que es mas recomendable usar? Tu codigo 1 o tu codigo 2
(posteaste dos codigos tuyos aca).
Porque si me dices codigo 1 entonces vere que puedo hacer
con el problema de public souled class y lo demas. Pero si me dices codigo 2 entonces
podre pegar el codigo en una nueva clase de VB.NET para compilarlo en una dll y
posteriormente usarlo en C#. Finalmente si me dices que investigue los dos codigos lo hare
(por supuesto, solamente si me lo recomiendas).
Son códigos para cosas distintas.
El primer código que puse en C# es una refactorización del primer código que tu compartiste, es un
fix por así decirlo que corrige varios malos hábitos de programación en .NET ( los que te estuve explicando y enumerando 1., 2., 3. etc... ) y que en teoría debería servirte para corregir el problema de no poder reproducir la siguiente canción (solo en teoría, ya que como dije no probé lo del WMP).
La idea era que reemplazases (todo) tú código por el que yo te mostré y decir si con esos cambios arreglaste por fin el problema. Pero sin lo de "public sealed class Form1 : Form", eso déjalo como lo tengas escrito en tu clase Form1.
El segundo código en VB.NET es una implementación para administrar listas de reproducción en formato m38 o pls, eso lo puedes usar si quieres o no usarlo xD, puedes hacer basicamente lo mismo con la interfáz COM que te dije de WMP (IWMPPlaylist). Ese código te lo puse por que tú dijiste que "
querías ir por ese camino" y pues... con ese código te estaba dando "el camino hecho".
saludos