martes, 16 de febrero de 2010

El formulario para simular la clase OpenFileDialog en un Smartphone usando Visual Studio 2005

Introducción:

Voy a empezar mostrándote un par de capturas del formulario en tiempo de ejecución, con idea de que te hagas una idea de cómo "queda". Estas capturas están hechas en un emulador de Smartphone para Windows Mobile 6.0, que en realidad ahora se llama Windows Mobile 6.0 Standard.
En la figura 1 tienes el aspecto mostrando varias carpetas y varios ficheros.
Figura 1. El formulario OpenFileDialog en ejecución
Figura 1. El formulario OpenFileDialog en ejecución 
En la figura 2 puedes ver el menú de la derecha, en el que puedes comprobar que se tienen en cuenta las extensiones que se hayan indicado (aunque sin el texto descriptivo).
Figura 2. Las opciones del menú del formulario
Figura 2. Las opciones del menú del formulario

En ese menú además de poder indicar la extensión a mostrar (por ahora solo soporta mostrar ficheros de un tipo a la vez), tienes opciones para abrir (seleccionar) el fichero, (que también puedes seleccionar con el botón central), otra opción para cambiar de directorio, cancelar (y cerrar esa ventana) y varias opciones para ir directamente a 4 directorios predefinidos.
Las opciones de Abrir y Cambiar a se usarán para seleccionar un fichero o cambiar a un directorio.
Y solo estará habilitada una u otra. Esto se sabe según el elemento que está actualmente seleccionado.
Si ese elemento es un directorio, se habilita la opción Cambiar a, además de que al pulsar en el botón central se cambiará al directorio seleccionado, para ir al directorio anterior, pulsa en el primer directorio (en teoría también pulsando en el botón Arriba, pero por razones extrañas no siempre está habilitado... a ver si me pongo a averiguar porqué pasa eso).
Si el elemento selecciona es un fichero, la opción que estará habilitada es Abrir (o el texto que se haya indicado en la clase que llama a este formulario), y al igual que ocurre con la otra opción, al pulsar en el botón central, se seleccionará el fichero y ese será el valor que se devuelva en la propiedad FileName.

Como puedes ver en el código que te muestro más abajo, cuando se asigna el valor a la propiedad Filter, se crean los menús de forma dinámica, bueno, en realidad se crean los submenús del menú Filtro.
Como te comentaba, por ahora solo se tienen en cuenta las extensiones, pero hay que aceptar los valores a los que estamos ya acostumbrados que es indicando primero la descripción y después la extensión (o extensiones).
Aunque en este "cuadro de diálogo" no tiene la misma funcionalidad que el componente "normal", ya que si en la extensión se indica "*.mp3;*.wav", se agregarán dos opciones al menú Filtro; y por consiguiente, si quieres mostrar los ficheros que coinciden con las dos extensiones... pues... simplemente no puedes, o muestras los ficheros de un tipo o muestras los de otro.
De todas formas, no es complicado hacer ese cambio, pero como lo único que hará es retardar más el "relleno" del contenido del formulario, pues... he preferido dejar cada extensión de forma independiente.

El método leerDirs es el que se encarga de hacer todo el trabajo, ya que se encarga de leer los directorios del directorio que se ha indicado en el parámetro y también de mostrar todos los ficheros que haya en ese
directorio.
En esta versión para el .NET 2.0 (Visual Studio 2005/2008), se guarda el objeto del directorio o del fichero en la propiedad Tag del elemento del ListView. Ese objeto después se usará para acceder al elemento adecuado, según sea un directorio o un fichero (ver el código de selección de un fichero o de cambio de directorio).
El formulario también tiene un control imageList en el que están las imágenes a mostrar.
Actualmente solo tengo 4:
0- El icono para los ficheros de sonido (sonido)
1- El icono para los demás tipos (document)
2- El
icono de los directorios normales (no el actual) (folder closed)
3- El icono del directorio raíz (folder open)
Estas imágenes están el formato PNG y están sacadas del fichero de imágenes que se incluye con Visual Studio 2005 o superior. (Puedes copiar estas que te muestro, ya que son las mismas que yo he utilizado.)
Y básicamente esto es todo... cuando publique el código de ejemplo de la utilidad que reproduce los ficheros .mp3 podrás ver cómo usarlo, pero en realidad es muy sencill.

Espacios de nombres usados en el código de este artículo:

System.Windows.Forms
System.Drawing
System.IO

El código del formulario

'------------------------------------------------------------------------------
' fOpenFileDialog 
' Seleccionar ficheros
' Simula el OpenFileDialog, ya que en los Smartphone no está soportado ese control
'
'------------------------------------------------------------------------------
Option Strict On
 
Imports Microsoft.VisualBasic
Imports System
Imports System.Windows.Forms
Imports System.Drawing
Imports System.IO
 
Friend Class fOpenFileDialog
 
    Private dirArriba As DirectoryInfo = Nothing
 
    Private m_FileName As String = ""
    Private filtroActual As Integer = 0
    Private m_Filter As String = "*.*"
 
    ''' <summary>
    ''' Filtros a usar con los ficheros
    ''' El formato será:
    ''' Descripción|filtro[|Descripción|filtro]
    ''' Filtro será cualquier filtro válido
    ''' se pueden indicar varios separados por ;
    ''' por ejemplo: *.txt;*.doc
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Filter() As String
        Get
            Return m_Filter
        End Get
        Set(ByVal value As String)
            If String.IsNullOrEmpty(value) Then
                m_Filter = "(*.*)|*.*"
            Else
                m_Filter = value
            End If
            Dim filtros() As String = value.Split("|".ToCharArray)
            mnuFiltro.MenuItems.Clear()
            Dim mnu As New MenuItem()
            For i As Integer = 1 To filtros.Length - 1 Step 2
                ' Si hay varios filtros separados por ;
                If filtros(i).IndexOf(";") > -1 Then
                    Dim filtros2() As String = filtros(i).Split(";".ToCharArray)
                    For j As Integer = 0 To filtros2.Length - 1
                        mnu = New MenuItem()
                        mnu.Text = filtros2(j).Trim
                        mnuFiltro.MenuItems.Add(mnu)
                        AddHandler mnu.Click, AddressOf mnuFiltros1_Click
                    Next
                Else
                    mnu = New MenuItem()
                    mnu.Text = filtros(i).Trim
                    mnuFiltro.MenuItems.Add(mnu)
                    AddHandler mnu.Click, AddressOf mnuFiltros1_Click
                End If
            Next
            filtroActual = 0
            mnuFiltro.MenuItems(filtroActual).Checked = True
        End Set
    End Property
 
    ''' <summary>
    ''' El título de la ventana de selección
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property Title() As String
        Get
            Return Me.Text
        End Get
        Set(ByVal value As String)
            Me.Text = value
        End Set
    End Property
 
    ''' <summary>
    ''' El fichero seleccionado
    ''' </summary>
    ''' <value></value>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Property FileName() As String
        Get
            Return m_FileName
        End Get
        Set(ByVal value As String)
            m_FileName = value
            If String.IsNullOrEmpty(value) _
            OrElse File.Exists(value) = False Then
                dirArriba = New DirectoryInfo("\")
            Else
                Dim sDir As String = Path.GetDirectoryName(value)
                dirArriba = New DirectoryInfo(sDir)
                If dirArriba.Exists = False Then
                    dirArriba = New DirectoryInfo("\")
                End If
            End If
        End Set
    End Property
 
    ''' <summary>
    ''' Rellenar la lista de arriba con los directorios
    ''' del directorio indicado
    ''' </summary>
    ''' <param name="obj">
    ''' Directorio en el que se navegará
    ''' </param>
    ''' <remarks></remarks>
    Private Sub leerDirs(ByVal obj As Object)
        If (TypeOf obj Is DirectoryInfo) = False Then
            Exit Sub
        End If
        Dim di As DirectoryInfo = TryCast(obj, DirectoryInfo)
 
        Dim lvi As ListViewItem
        With Me.lvDirs.Items
            .Clear()
            Dim d2() As DirectoryInfo = di.GetDirectories()
            lvi = .Add(New ListViewItem(di.FullName))
            lvi.Tag = di
            dirArriba = di

            lvi.ImageIndex = 3
            For Each d As DirectoryInfo In d2
                lvi = .Add(New ListViewItem(d.Name))
                lvi.Tag = d
                lvi.ImageIndex = 2
            Next
            Dim fi2() As FileInfo = di.GetFiles(mnuFiltro.MenuItems(filtroActual).Text)
            For Each f As FileInfo In fi2
                lvi = .Add(New ListViewItem(f.Name))
                lvi.Tag = f
                Select Case f.Extension.ToLower
                    Case ".wav", ".mp3", ".m3u"
                        lvi.ImageIndex = 0
                    Case Else
                        lvi.ImageIndex = 1
                End Select
            Next
        End With
    End Sub
 
    Private Sub fOpenFileDialog_Load(ByVal sender As Object, _
                                     ByVal e As EventArgs) _
                                     Handles MyBase.Load
        If dirArriba Is Nothing Then
            dirArriba = New DirectoryInfo("\")
        End If
        leerDirs(dirArriba)
    End Sub
 
    Private Sub mnuDispositivo_Click(ByVal sender As Object, _
                                     ByVal e As EventArgs) _
                                     Handles mnuDispositivo.Click
        leerDirs(New DirectoryInfo("\"))
    End Sub
 
    Private Sub mnuDocuments_Click(ByVal sender As Object, _
                                   ByVal e As EventArgs) _
                                   Handles mnuDocuments.Click
        leerDirs(New DirectoryInfo("\My Documents"))
    End Sub
 
    Private Sub mnuAppData_Click(ByVal sender As Object, _
                                 ByVal e As EventArgs) _
                                 Handles mnuAppData.Click
        leerDirs(New DirectoryInfo("\Application Data"))
    End Sub
 
    Private Sub mnuWindows_Click(ByVal sender As Object, _
                                 ByVal e As EventArgs) _
                                 Handles mnuWindows.Click
        leerDirs(New DirectoryInfo("\Windows"))
    End Sub
 
    Private Sub mnuCancelar_Click(ByVal sender As Object, _
                                  ByVal e As EventArgs) _
                                  Handles mnuCancelar.Click
        Me.DialogResult = Windows.Forms.DialogResult.Cancel
    End Sub
 
    Private Sub mnuArriba_Click(ByVal sender As Object, _
                                ByVal e As EventArgs) _
                                Handles mnuArriba.Click
        ' Ir al directorio anterior
        If dirArriba.Parent Is Nothing Then
            leerDirs(dirArriba)
        Else
            leerDirs(dirArriba.Parent)
        End If
    End Sub
 
    Private Sub mnuSeleccionar_Click(ByVal sender As Object, _
                                     ByVal e As EventArgs) _
                                     Handles mnuSeleccionar.Click
        If lvDirs.FocusedItem Is Nothing Then
            Beep()
            Exit Sub
        End If
 
        If TypeOf lvDirs.FocusedItem.Tag Is FileInfo Then
            Me.FileName = TryCast(lvDirs.FocusedItem.Tag, FileInfo).FullName
            Me.DialogResult = Windows.Forms.DialogResult.OK
        End If
    End Sub
 
    Private Sub mnuCambiar_Click(ByVal sender As Object, _
                                 ByVal e As EventArgs) _
                                 Handles mnuCambiar.Click
        If lvDirs.FocusedItem Is Nothing Then
            Beep()
            Exit Sub
        End If
 
        With Me.lvDirs
            If TypeOf .Items(.SelectedIndices(0)).Tag Is DirectoryInfo Then
                leerDirs(TryCast(.Items(.SelectedIndices(0)).Tag, DirectoryInfo))
            End If
        End With
    End Sub
 
    Private Sub mnuMenu_Popup(ByVal sender As Object, _
                              ByVal e As EventArgs) _
                              Handles mnuMenu.Popup
        Dim lvi As ListViewItem = lvDirs.FocusedItem
        If lvi Is Nothing Then
            mnuSeleccionar.Enabled = False
            mnuCambiar.Enabled = False
        Else
            mnuSeleccionar.Enabled = (TypeOf lvi.Tag Is FileInfo)
            mnuCambiar.Enabled = (TypeOf lvi.Tag Is DirectoryInfo)
        End If
    End Sub
 
    ''' <summary>
    ''' Este es el evento que se produce al pulsar con el botón central (Intro)
    ''' </summary>
    ''' <param name="sender"></param>
    ''' <param name="e"></param>
    ''' <remarks></remarks>
    Private Sub lvDirs_ItemActivate(ByVal sender As Object, _
                                    ByVal e As EventArgs) _
                                    Handles lvDirs.ItemActivate
        If lvDirs.FocusedItem Is Nothing Then
            Beep()
            Exit Sub
        End If
 
        If TypeOf lvDirs.FocusedItem.Tag Is DirectoryInfo Then
            If lvDirs.FocusedItem Is lvDirs.Items(0) Then
                leerDirs(dirArriba)
            Else
                leerDirs(lvDirs.FocusedItem.Tag)
            End If
        ElseIf TypeOf lvDirs.FocusedItem.Tag Is FileInfo Then
            Me.FileName = TryCast(lvDirs.FocusedItem.Tag, FileInfo).FullName
            Me.DialogResult = Windows.Forms.DialogResult.OK
        End If
    End Sub
 
    Private Sub lvDirs_SelectedIndexChanged(ByVal sender As Object, _
                                            ByVal e As EventArgs) _
                                            Handles lvDirs.SelectedIndexChanged, _
                                                    lvDirs.LostFocus
        If dirArriba.Root.FullName.CompareTo(dirArriba.FullName) = 0 Then
            mnuArriba.Enabled = False
        Else
            mnuArriba.Enabled = True
        End If
    End Sub
 
    Private Sub mnuFiltros1_Click(ByVal sender As Object, _
                                  ByVal e As EventArgs) 'Handles mnuFiltros1.Click
        Dim mnu As MenuItem = TryCast(sender, MenuItem)
        If mnu Is Nothing Then Exit Sub
        mnuFiltro.MenuItems(filtroActual).Checked = False
        For i As Integer = 0 To mnuFiltro.MenuItems.Count - 1
            If mnuFiltro.MenuItems(i) Is mnu Then
                filtroActual = i
                mnu.Checked = True
                Exit For
            End If
        Next
        leerDirs(dirArriba)
    End Sub

El código del diseño del formulario

<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Friend Class fOpenFileDialog
    Inherits System.Windows.Forms.Form
 
    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing AndAlso components IsNot Nothing Then
            components.Dispose()
        End If
        MyBase.Dispose(disposing)
    End Sub
 
    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer
    Private mainMenu1 As System.Windows.Forms.MainMenu
 
    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Dim resources As System.ComponentModel.ComponentResourceManager = _
                New System.ComponentModel.ComponentResourceManager(GetType(fOpenFileDialog))
        Me.mainMenu1 = New System.Windows.Forms.MainMenu
        Me.mnuArriba = New System.Windows.Forms.MenuItem
        Me.mnuMenu = New System.Windows.Forms.MenuItem
        Me.mnuFiltro = New System.Windows.Forms.MenuItem
        Me.mnuFiltros1 = New System.Windows.Forms.MenuItem
        Me.mnuSep3 = New System.Windows.Forms.MenuItem
        Me.mnuSeleccionar = New System.Windows.Forms.MenuItem
        Me.mnuSep2 = New System.Windows.Forms.MenuItem
        Me.mnuCancelar = New System.Windows.Forms.MenuItem
        Me.mnuSep0 = New System.Windows.Forms.MenuItem
        Me.mnuCambiar = New System.Windows.Forms.MenuItem
        Me.mnuSep1 = New System.Windows.Forms.MenuItem
        Me.mnuDispositivo = New System.Windows.Forms.MenuItem
        Me.mnuDocuments = New System.Windows.Forms.MenuItem
        Me.mnuAppData = New System.Windows.Forms.MenuItem
        Me.mnuWindows = New System.Windows.Forms.MenuItem
        Me.lvDirs = New System.Windows.Forms.ListView
        Me.imageList1 = New System.Windows.Forms.ImageList
        Me.SuspendLayout()
        '
        'mainMenu1
        '
        Me.mainMenu1.MenuItems.Add(Me.mnuArriba)
        Me.mainMenu1.MenuItems.Add(Me.mnuMenu)
        '
        'mnuArriba
        '
        Me.mnuArriba.Text = "Arriba"
        '
        'mnuMenu
        '
        Me.mnuMenu.MenuItems.Add(Me.mnuFiltro)
        Me.mnuMenu.MenuItems.Add(Me.mnuSep3)
        Me.mnuMenu.MenuItems.Add(Me.mnuSeleccionar)
        Me.mnuMenu.MenuItems.Add(Me.mnuSep2)
        Me.mnuMenu.MenuItems.Add(Me.mnuCancelar)
        Me.mnuMenu.MenuItems.Add(Me.mnuSep0)
        Me.mnuMenu.MenuItems.Add(Me.mnuCambiar)
        Me.mnuMenu.MenuItems.Add(Me.mnuSep1)
        Me.mnuMenu.MenuItems.Add(Me.mnuDispositivo)
        Me.mnuMenu.MenuItems.Add(Me.mnuDocuments)
        Me.mnuMenu.MenuItems.Add(Me.mnuAppData)
        Me.mnuMenu.MenuItems.Add(Me.mnuWindows)
        Me.mnuMenu.Text = "Menú"
        '
        'mnuFiltro
        '
        Me.mnuFiltro.MenuItems.Add(Me.mnuFiltros1)
        Me.mnuFiltro.Text = "Filtro"
        '
        'mnuFiltros1
        '
        Me.mnuFiltros1.Text = "*.*"
        '
        'mnuSep3
        '
        Me.mnuSep3.Text = "-"
        '
        'mnuSeleccionar
        '
        Me.mnuSeleccionar.Text = "Seleccionar"
        '
        'mnuSep2
        '
        Me.mnuSep2.Text = "-"
        '
        'mnuCancelar
        '
        Me.mnuCancelar.Text = "Cancelar"
        '
        'mnuSep0
        '
        Me.mnuSep0.Text = "-"
        '
        'mnuCambiar
        '
        Me.mnuCambiar.Text = "Cambiar a"
        '
        'mnuSep1
        '
        Me.mnuSep1.Text = "-"
        '
        'mnuDispositivo
        '
        Me.mnuDispositivo.Text = "Mi Dispositivo"
        '
        'mnuDocuments
        '
        Me.mnuDocuments.Text = "My Documents"
        '
        'mnuAppData
        '
        Me.mnuAppData.Text = "Application Data"
        '
        'mnuWindows
        '
        Me.mnuWindows.Text = "Windows"
        '
        'lvDirs
        '
        Me.lvDirs.BackColor = System.Drawing.Color.AliceBlue
        Me.lvDirs.Dock = System.Windows.Forms.DockStyle.Fill
        Me.lvDirs.Location = New System.Drawing.Point(0, 0)
        Me.lvDirs.Name = "lvDirs"
        Me.lvDirs.Size = New System.Drawing.Size(176, 180)
        Me.lvDirs.SmallImageList = Me.imageList1
        Me.lvDirs.TabIndex = 0
        Me.lvDirs.View = System.Windows.Forms.View.SmallIcon
        Me.imageList1.Images.Clear()
        Me.imageList1.Images.Add(CType(resources.GetObject("resource"), System.Drawing.Image))
        Me.imageList1.Images.Add(CType(resources.GetObject("resource1"), System.Drawing.Image))
        Me.imageList1.Images.Add(CType(resources.GetObject("resource2"), System.Drawing.Image))
        Me.imageList1.Images.Add(CType(resources.GetObject("resource3"), System.Drawing.Image))
        '
        'fOpenFileDialog
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(96.0!, 96.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Dpi
        Me.AutoScroll = True
        Me.ClientSize = New System.Drawing.Size(176, 180)
        Me.Controls.Add(Me.lvDirs)
        Me.Menu = Me.mainMenu1
        Me.Name = "fOpenFileDialog"
        Me.Text = "fOpenFileDialog"
        Me.ResumeLayout(False)
 
    End Sub
    Friend WithEvents mnuMenu As System.Windows.Forms.MenuItem
    Friend WithEvents mnuDispositivo As System.Windows.Forms.MenuItem
    Friend WithEvents mnuDocuments As System.Windows.Forms.MenuItem
    Friend WithEvents mnuAppData As System.Windows.Forms.MenuItem
    Friend WithEvents mnuWindows As System.Windows.Forms.MenuItem
    Friend WithEvents mnuCancelar As System.Windows.Forms.MenuItem
    Friend WithEvents mnuSeleccionar As System.Windows.Forms.MenuItem
    Friend WithEvents mnuSep2 As System.Windows.Forms.MenuItem
    Private WithEvents mnuArriba As System.Windows.Forms.MenuItem
    Private WithEvents lvDirs As System.Windows.Forms.ListView
    Private WithEvents mnuCambiar As System.Windows.Forms.MenuItem
    Private WithEvents imageList1 As System.Windows.Forms.ImageList
    Private WithEvents mnuSep0 As System.Windows.Forms.MenuItem
    Private WithEvents mnuSep1 As System.Windows.Forms.MenuItem
    Private WithEvents mnuSep3 As System.Windows.Forms.MenuItem
    Private WithEvents mnuFiltro As System.Windows.Forms.MenuItem
    Private WithEvents mnuFiltros1 As System.Windows.Forms.MenuItem
End Class

No hay comentarios:

Publicar un comentario