Problemas con objeto y listbox en vs 2015

Iniciado por Yaldabaot, 22 Marzo 2019, 22:25 PM

0 Miembros y 1 Visitante están viendo este tema.

Yaldabaot

Saludos amigos, soy yo nuevamente molestando, tengo un problema con un listbox.

Verán, estoy haciendo una aplicación dónde esta cargue 3 rutas de un archivo sobre un objeto, posteriormente cuando ese objeto esté "relleno" lo inserto en un listbox, el problema se inicia cuando quiero obtener el valor de ese listbox el cuál según el vs el valor es nothing pero curiosamente a la hora de depurarlo los valores me dice que se ha rellenado correctamente.

Este es el código del objeto

Código (vbnet) [Seleccionar]



Public Class Archivos

    'Atributos de la clase
    Private str_ruta_archivo_entradas As String = String.Empty
    Private str_ruta_archivo_valorizado As String = String.Empty
    Private str_ruta_archivo_salidas As String = String.Empty
    Private str_entradas_salidas_excluir As ArrayList

    'Métodos de acceso

    Public Property Str_Ruta_Archivo_E() As String
        Get
            Return Me.str_ruta_archivo_entradas

        End Get
        Set(ByVal Value As String)
            Me.str_ruta_archivo_entradas = Value
        End Set
    End Property

    Public Property Str_Ruta_Archivo_Val As String
        Get
            Return Me.str_ruta_archivo_valorizado
        End Get
        Set(ByVal Value As String)
            Me.str_ruta_archivo_valorizado = Value
        End Set
    End Property

    Public Property Str_Salidas As String
        Get
            Return Me.str_ruta_archivo_salidas
        End Get
        Set(ByVal Value As String)
            Me.str_ruta_archivo_salidas = Value
        End Set
    End Property


    Public Property Str_ES_Excluir As ArrayList
        Get
            Return Me.str_entradas_salidas_excluir
        End Get
        Set(ByVal Value As ArrayList)
            Me.str_entradas_salidas_excluir = Value
        End Set
    End Property

    'Constructor
    Public Sub New(ByVal str_ruta_e As String, ByVal str_ruta_archivo_val As String, ByVal str_rutas_array As ArrayList, ByVal str_archivo_salidas As String)

        str_ruta_archivo_entradas = str_ruta_e
        str_ruta_archivo_salidas = str_archivo_salidas
        str_ruta_archivo_valorizado = str_ruta_archivo_val
        str_entradas_salidas_excluir = str_rutas_array
    End Sub


    Public Sub New()

        str_ruta_archivo_entradas = String.Empty
        str_ruta_archivo_valorizado = String.Empty
        str_ruta_archivo_salidas = String.Empty
        str_entradas_salidas_excluir = Nothing
    End Sub

End Class




Aquí es dónde lo inserto mediante unos diálogos y un botón.

Código (vbnet) [Seleccionar]


  Try


            Dim operaciones As Archivos
            Dim str_ruta_archivo_E As String = String.Empty
            Dim str_ruta_archivo_S As String = String.Empty
            Dim str_ruta_archivo_Inv As String = String.Empty
            Dim obj_array As New ArrayList
            Dim int_cont As Integer = 0


            'Cargando archivo de entradas/salidas


            dlg_Abrir.Title = "Seleccione el archivo de excel (archivo de entradas) a procesar"
            dlg_Abrir.DefaultExt = ".xlsx"

            lbl_estado.Text = "Cargando datos del archivo de entradas..."


            If dlg_Abrir.ShowDialog() = System.Windows.Forms.DialogResult.OK Then

                str_ruta_archivo_E = dlg_Abrir.FileName()
            End If


            'Cargando archivo de salidas


            dlg_Abrir.Title = "Seleccione el archivo de excel (archivo de salidas) a procesar"
            dlg_Abrir.DefaultExt = ".xlsx"

            lbl_estado.Text = "Cargando datos del archivo de salidas..."


            If dlg_Abrir.ShowDialog() = System.Windows.Forms.DialogResult.OK Then

                str_ruta_archivo_S = dlg_Abrir.FileName()

            End If


            'Cargando archivo valorizado


            dlg_Abrir.Title = "Seleccione el archivo de excel (archivo valorizado correspondiente a esas entradas/salidas) a procesar"
            dlg_Abrir.DefaultExt = ".xlsx"

            lbl_estado.Text = "Cargando datos del archivo valorizado correspondiente a esas entradas/salidas..."


            If dlg_Abrir.ShowDialog() = System.Windows.Forms.DialogResult.OK Then

                str_ruta_archivo_Inv = dlg_Abrir.FileName()

            End If



            For Each valor In lt_salidas_entradas_excluir.Items

                obj_array.Add(valor)
            Next


            operaciones = New Archivos(str_ruta_archivo_E, str_ruta_archivo_Inv, obj_array, str_ruta_archivo_S)
            lt_Archivos.Items.Add(operaciones)


        Catch ex As Exception
            MsgBox("Hubo un error cargando el archivo del contenedor.")
        End Try




Mediante un menústrip de un contextmenú o menú contextual genero un pequeño dialogo y lo que hago es que quiero mostrar la información de ese objeto (que por cierto sería genial si alguno de uds sabe como ponerle texto más "bonito" a ese objeto en ese listbox sin alterar su valor como un combobox con sus propiedades de display member).



Código (vbnet) [Seleccionar]



Private Sub MostrarInformaciónToolStripMenuItem_Click(sender As Object, e As EventArgs) Handles MostrarInformaciónToolStripMenuItem.Click


        Dim obj As Archivos


        obj = lt_Archivos.SelectedValue
       MsgBox(obj.Str_Ruta_Archivo_E)

     

    End Sub




Curiosamente cuando lo depuro cómo les menciono arriba me dice que el objeto está correctamente insertado y tiene un valor pero a la hora de "jalarlo" no me sale nada, me preocupa porque necesito manipular ese objeto para el resto del proyecto, si uds saben algo se los agradecería demasiado.




Nunca me contestan -_-

Yaldabaot

Ya pude, lo dejo para que otros si tienen la duda puedan resolverlo...


Código (vbnet) [Seleccionar]


   Dim obj As Archivos
   obj = CType(lt_Archivos.SelectedItem, Archivos)



Y ya con la variable "obj" pueden jugar.


Ahora bien, lo que no he podido hacer aún es lo siguiente:

Quiero que cuando se inserte ese objeto en lugar de decir el nombre del objeto diga "Archivo1,Archivo2", lo que hice fue cambiar el método toString para que diga archivo pero quiero tener un contador para así el usuario pueda diferenciar entre los objetos del listbox.

Lo que hice fue esto:

Código (vbnet) [Seleccionar]



Public Overrides Function ToString() As String

       Return str_mostrar_texto & int_cont

   End Function

End Class




Lógicamente agregué el atributo "str_mostrar_texto" en la clase así como sus gets y sets.


Entonces no se si alguno tendrá alguna sugerencia? ya lo intenté con un integer global pero no suma el contador y en todas da 0.

Muchas gracias desde ya.
Nunca me contestan -_-

Eleкtro

#2
Carece de sentido que en el diseño de la clase "Archivos" implementes un contador de ningún tipo, ya que si no te he entendido mal, la clase archivos se supone que sirve para representar una serie de rutas de archivos que están relacionados entre si, pues bien, eso es correcto, pero en ese caso eso sería todo lo que debes hacer con esa clase...

Así que deberías dar el diseño de esa clase por finalizado, y a partir de ahí eres tú el que debe declarar un contador (fuera de la clase "Archivos") y añadir/mostrar ese contador al añadir cada uno de esos items al ListBox, no al revés, es decir, no debe ser la clase "Archivos" la que deba representar por si misma y mostrar un índice al ser representado como texto ( Archivos.ToString() ) en un control, eso es mezclar cosas que no tienen nada que ver, y por ende no tiene sentido productivo. No se si me he explicado suficientemente bien.

De todas formas no tengo muy claro por que sientes la necesidad de usar una variable-contador que actue como índice de los items representados en el listbox, es decir, el índice del elemento lo puedes obtener directamente en la lista de elementos de dicho ListBox y mostrarlo si quieres junto al nombre del elemento, algo como por ejemplo:

Código (vbnet) [Seleccionar]
Me.ListBox1.BeginUpdate()
For i As Integer = 0 To (Me.ListBox1.Items.Count - 1)
   Me.ListBox1.Items(i) = String.Format("[{0:00}] {1}", i, Me.ListBox1.Items(i))
Next
Me.ListBox1.EndUpdate()


...o en su defecto siempre puedes añadir las instancias de la clase "Archivos" a un diccionario u otra colección apropiada para tus necesidades, en la que usar la "llave" como índice, y luego mostrarlo al añadir el valor/elemento en el listbox.

Pero en fin. Dices que ya lo intentaste con un "integer global" (imagino que te refieres a que usaste el modificador de visibilidad Public Shared) pero "no suma el contador y en todas da 0". Todo esto no se entiende mucho. Para empezar, no se sabe donde lo declaraste, ni cuando y como incrementas su valor, pero algo parece evidente, y es que si su valor siempre es 0, será que la unidad de código donde incrementas el valor nunca se llega a ejecutar, o si se ejecuta pero en realidad no llegas a incrementar el valor. No se pueden sacar otras conclusiones mientras no aportes más información.

Saludos.








Yaldabaot

Muchas gracias elektro por responder, siempre con mucho conocimiento por dar y aprendo mucho de tu persona.

Mira, lo único que quiero que cuando agregue ese objeto al listbox no aparezca como texto en cada item el valor del objeto, es decir NO quiero que aparezca como "nombredel proyecto.objeto" sino que en ese texto aparezca como archivo1, archivo2,archivo3 sin alterar lógicamente sus atributos.


La variable local la declaré tanto en la clase del form dónde estaba ese listbox como erroneamente tambien en ese objeto.

Lo intenté con el método toString() para en lugar de "nombredelproyecto.objeto" se mostrara Archivo pero queria concatenarle un contador que se fuera incrementando, pero no lo logré.

Nunca me contestan -_-

Yaldabaot

Luego de un montón de intentos lo logré!!  ;-).


En el método del constructor del objeto archivo lo agregué cómo parámetro:

Código (vbnet) [Seleccionar]



Public Sub New(ByVal str_ruta_e As String, ByVal str_ruta_archivo_val As String, ByVal str_rutas_array As ArrayList, ByVal str_archivo_salidas As String, ByVal int_cont As Integer)

        str_ruta_archivo_entradas = str_ruta_e
        str_ruta_archivo_salidas = str_archivo_salidas
        str_ruta_archivo_valorizado = str_ruta_archivo_val
        str_entradas_salidas_excluir = str_rutas_array
        int_contador = int_cont
    End Sub




Posteriormente en el form, declaré la variable como pública:

Código (vbnet) [Seleccionar]


Public int_contador




Modifiqué el método para que tuviera como parámetro la variable:

Código (vbnet) [Seleccionar]



Private Sub cargar_archivos(ByVal int_cont As Integer)
..
end sub




LLamé al método en el botón:


Código (vbnet) [Seleccionar]


Private Sub btn_Cargar_Archivos_Click(sender As Object, e As EventArgs) Handles btn_Cargar_Archivos.Click

        int_contador = int_contador + 1
        cargar_archivos(int_contador)





Agregándolo finalmente así al listbox:

Código (vbnet) [Seleccionar]


lt_Archivos.Items.Add(New Archivos(str_ruta_archivo_E, str_ruta_archivo_Inv, obj_array, str_ruta_archivo_S, int_cont))




Gracias por leerme.
Nunca me contestan -_-

Eleкtro

#5
Primero que nada, y disculpa que te lo diga pero es que realmene se me hace horrible ver tanto guión bajo junto. No se como tú te entiendes con eso, pero a mi se me hace muy dificil/tedioso la lectura de tanto guión bajo.

El caso es que no estás siguiendo las convenciones de nomenclaturas recomendadas para la programación .NET, y sin entrar mucho en detalle te puedo decir que basicamente consiste en usar Camel case para casi todos los tipos de miembros indiferentemente de su modificador de visibilidad (excepto algunos casos, pero ya dije que sin entrar en muchos detalles).

Aparte de eso, yo en tu lugar sellaría la clase Archivos, quitaría la asignación de un valor inicial (innecesario) en los campos str_*, y los constructores los dejaría así:

Código (vbnet) [Seleccionar]
Public NotInheritable Class Archivos

   Private str_ruta_archivo_entradas As String
   Private str_ruta_archivo_valorizado As String
   Private str_ruta_archivo_salidas As String
   Private str_entradas_salidas_excluir As ArrayList

   '...

   Public Sub New()
        ' Esta llamada es completamente opcional y solo lo muestro para proveer mayor flexibilidad de código (al poder especificar un valor inicial).
       ' Me.New(String.Empty, String.Empty, Nothing, String.Empty)
   End Sub

   Public Sub New(ByVal str_ruta_e As String, ByVal str_ruta_archivo_val As String, ByVal str_rutas_array As ArrayList, ByVal str_archivo_salidas As String)
       str_ruta_archivo_entradas = str_ruta_e
       str_ruta_archivo_valorizado = str_ruta_archivo_val
       str_entradas_salidas_excluir = str_rutas_array
       str_ruta_archivo_salidas = str_archivo_salidas
   End Sub

End Class


...eso suponiendo que realmente quieras declarar un constructor por defecto sin parámetros, de lo contrario:

Código (vbnet) [Seleccionar]
' ...
Private Sub New()
End Sub

Public Sub New(ByVal str_ruta_e As String, ByVal str_ruta_archivo_val As String, ByVal str_rutas_array As ArrayList, ByVal str_archivo_salidas As String)
   str_ruta_archivo_entradas = str_ruta_e
   str_ruta_archivo_valorizado = str_ruta_archivo_val
   str_entradas_salidas_excluir = str_rutas_array
   str_ruta_archivo_salidas = str_archivo_salidas
End Sub
' ...


Es más, esas 70 lineas que ocupa la clase Archivos lo puedes simplificar a 15 o 20 lineas declarando auto-propiedades, en lugar de declarar propiedades con su getter y setter y su campo de apoyo o backing field, resulta innecesario en ese diseño de clase Archivos, pero bueno, eso no te lo he mostrado por que ahora mismo no recuerdo si fue a partir de Visual Studio 2015 / VB.NET 14.0 o cuando se implementó esta característica, o fue a partir de Visual Studio 2017 / VB.NET 15.




Cita de: Yaldabaot en 22 Marzo 2019, 22:25 PM
Curiosamente cuando lo depuro cómo les menciono arriba me dice que el objeto está correctamente insertado y tiene un valor pero a la hora de "jalarlo" no me sale nada, me preocupa porque necesito manipular ese objeto para el resto del proyecto, si uds saben algo se los agradecería demasiado.

Debes usar la propiedad ListBox.SelectedItem en vez de ListBox.SelectedValue, ya que no especificaste ningún miembro para la propiedad ListBox.ValueMember, normal que te salte una excepción de referencia nula...

Te muestro un ejemplo reducido:
Código (vbnet) [Seleccionar]
Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
   Dim test As New Archivos("test", "test", New ArrayList(), "test")
   ListBox1.Items.Add(test)
End Sub

Private Sub ListBox1_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedIndexChanged
   Dim test As Archivos = DirectCast(Me.ListBox1.SelectedItem, Archivos)
   MsgBox(test .ToString)
End Sub


Saludos








Yaldabaot

Gracias elektro, tomaré en cuenta las recomendaciones, y no, no uso 2017, no lo tengo, el que estoy usando es el 2015.
Nunca me contestan -_-