Error en Listview

Iniciado por okik, 19 Enero 2019, 12:18 PM

0 Miembros y 2 Visitantes están viendo este tema.

okik

Hola

Hacía tiempo que no programaba con vb.net pero hoy me he puesto.

He creado un objeto ListView, le he puesto tres cabeceras (headers) y resulta que cuando quiero añadir un valor a una una celda me da error. Antes debo haber introducido algo mediante ADD, y luego si que puedo. ¿Esto porqué ocurre? Me parece una tontería. No se si es que hago un mal uso del objeto.    

Aquí un ejemplo donde primero y para evitar el error, debo añadir un valor nulo mediante Add y después introduzco el valor TEXT a la celda.

   
Código (vbnet) [Seleccionar]
    ListView1.Items(0).SubItems.Add("")
    ListView1.Items(0).SubItems(0).Text = "hola mundo"


Me da la impresión de que add, lo que hace es crear la celda, y no puedes cambiarle el valor text hasta que no esté creada.

Pero la cosa es que si has creado tres columnas y as añadido un valor a la primera celda de la primera columna, me parece tedioso tener que  crear la celda siguiente de la siguiente columna correspondiente a la primera celda, que ya tiene un valor en la primera celda.

Eleкtro

#1
Cita de: okik en 19 Enero 2019, 12:18 PMMe da la impresión de que add, lo que hace es crear la celda, y no puedes cambiarle el valor text hasta que no esté creada.

Tu mismo te has respondido a la pregunta, aunque sería más correcto decir que el método ListViewSubItemCollection.Add() crea un nuevo elemento en la colección, y luego el ListView genera la representación visual de la forma en que lo hace.




Cita de: okik en 19 Enero 2019, 12:18 PM¿Esto porqué ocurre? Me parece una tontería.

Lo que te parece una tontería, no tendría sentido que fuese de otra forma.

Recapitulemos:

Cuando llamas al método SubItems.Add, estás creando un nuevo subitem...
Citar
Código (vbnet) [Seleccionar]
ListView1.Items(0).SubItems.Add("")

y luego, como es lógico, puedes acceder a él mediante el indexer de la colección de subitems...
Citar
Código (vbnet) [Seleccionar]
ListView1.Items(0).SubItems(0).Text = "hola mundo"

Sinceramente, me cuesta entender que otro comportamiento distinto esperas que tenga. Por lo que creo entender, ¿pretendes poder escribir por ejemplo ListView1.Items(14).SubItems(85).Text y que se generen automaticamente los items de 0 al 14 y los subitems del 0 al 85?, eso si que no tendría sentido, piénsalo bien, jeje. Para acceder a un item o subitem mediante el indexer, el item o subitem en cuestión debe existir por haberlo creado antes mediante el método b de la colección en cuestión...




Cita de: okik en 19 Enero 2019, 12:18 PMPero la cosa es que si has creado tres columnas y as añadido un valor a la primera celda de la primera columna, me parece tedioso tener que  crear la celda siguiente de la siguiente columna correspondiente a la primera celda, que ya tiene un valor en la primera celda.

Entiendo que su utilización te resulte un procedimientos tedioso, pero eso es lo que conlleva la forma en la que estás haciendo las cosas.

Puedes simplificar bastante el procedimiento, especificando todos los items/celdas que quieras mediante el constructor de la clase ListViewItem, tal que así:
Código (vbnet) [Seleccionar]
Dim lvi As New ListViewItem({"item1", "item2", "item3"})

Me.ListView1.Items.Add(lvi)


O bien en lugar de usar un control de tipo ListView puedes usar un DataGridView y simplificar al máximo la adición de elementos mediante sus capacidades de enlace de datos (usando la propiedad DataGridView.DataSource).

Saludos.








okik

Gracias Eleкtro (sin pilas).

Pues eso no hay otra que crear el elemento en la colección antes.  

Claro y es que yo supongo no puedo evitar interpretarlo como un DataGridView. Es que yo le he dado a la propiedad GridLines  como True. Esto hace que visualmente tenga aspecto de DataGridView. Sin embargo desde código las celdas son inexistentes, ya que no son celdas realmente si no elementos de una colección como tu dices. Pero creo no voy mal encaminado de que se pudiera establecer una propiedad similar a un DataGridView, en cuanto a las "celdas" del Listview. Si creo tres columnas y creo un elemento de la colección mediante ADD, los elementos subitems de la misma file deberían crearse automáticamente.

Saludos

Eleкtro

#3
Cita de: okik en 19 Enero 2019, 21:56 PMPero creo no voy mal encaminado de que se pudiera establecer una propiedad similar a un DataGridView, en cuanto a las "celdas" del Listview.

Hay un problema con ese tipo de pensamiento, y es que estás viendo el control ListView como si fuese similar a un DataGridView, a modo de columnas y celdas, pero el control ListView tiene varias vistas distintas, entre ellas la de tipo tabla/grid (más conocida como vista de detalles), sí, pero el control ListView no necesariamente tiene por que tener columnas creadas, y además, no hay límite de subitems que puedes crear para un item (más allá de los límites virtuales de memoria) indiferentemente de la cantidad de columnas que se haya creado, y estos subitems solo serán representados visualmente si el control tiene columnas creadas. Por estos motivos, pretender que automaticamente exista la misma cantidad de subitems que de columnas no tiene mucho sentido, ni aun usando la vista de detalles...




Cita de: okik en 19 Enero 2019, 21:56 PMSi creo tres columnas y creo un elemento de la colección mediante ADD, los elementos subitems de la misma file deberían crearse automáticamente.

Desde el primer momento te he dejado clara mi postura: esto me parece totalmente innecesario. Pero si quieres seguir con este enfoque, y por no dejarte sin una respuesta que te resulte satisfactoria pues aquí te muestro una solución que escrito donde implemento un ListView personalizado en el que sustituyo la colección base de items por una colección personalizada en la que reimplemento las funciones "Add" que se encargan de añadir el item en la colección...

Código (vbnet) [Seleccionar]
<DisplayName(NameOf(CustomListView))>
<Description("A custom ListView control.")>
<DesignTimeVisible(True)>
<DesignerCategory(NameOf(DesignerCategoryAttribute.Default))>
<ToolboxBitmap(GetType(ListView), "ListView.bmp")>
<ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Require)>
<ClassInterface(ClassInterfaceType.AutoDispatch)>
<ComVisible(True)>
<DefaultProperty(NameOf(CustomListView.Items))>
<DefaultEvent(NameOf(CustomListView.SelectedIndexChanged))>
<Docking(DockingBehavior.Ask)>
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")>
Public Class CustomListView : Inherits ListView

   <DisplayName(NameOf(CustomListView.Items))>
   <Description("The items in the ListView")>
   <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
   <Localizable(True)>
   <MergableProperty(False)>
   <Browsable(True)>
   Public Shadows ReadOnly Property Items As CustomListViewItemCollection

   Public Sub New()
       MyBase.New()
       Me.Items = New CustomListViewItemCollection(Me)
   End Sub

End Class


Código (vbnet) [Seleccionar]
<DefaultMember("Item")>
<ListBindable(False)>
Public Class CustomListViewItemCollection : Inherits ListViewItemCollection

   Private ReadOnly owner As ListView

   Public Sub New(owner As ListView)
       MyBase.New(owner)
       Me.owner = owner
   End Sub

   Public Overrides Function Add(value As ListViewItem) As ListViewItem
       Return Me.CreateAllSubItems(MyBase.Add(value))
   End Function

   <DebuggerStepThrough>
   Private Function CreateAllSubItems(value As ListViewItem) As ListViewItem
       Dim diff As Integer = (Me.owner.Columns.Count - value.SubItems.Count)
       If (diff > 0) Then
           For i As Integer = 0 To (diff - 1)
               value.SubItems.Add(String.Empty)
           Next i
       End If

       Return value
   End Function

End Class


Modo de empleo:
Código (vbnet) [Seleccionar]
Me.CustomListView1.View = System.Windows.Forms.View.Details

' Creamos 5 columnas.
For i As Integer = 1 To 5
   Me.CustomListView1.Columns.Add(String.Format("Column {0}", i))
Next i

' Añadimos un item donde se crearán subitems o "celdas" vacías para las cinco columnas.
Me.CustomListView1.Items.Add("")

' Especificamos los valores de los cinco subitems
' sin necesidad de haber llamado al método SubItems.Add() para cada uno de ellos...
Me.CustomListView1.Items(0).SubItems(0).Text = "Value 1"
Me.CustomListView1.Items(0).SubItems(1).Text = "Value 2"
Me.CustomListView1.Items(0).SubItems(2).Text = "Value 3"
Me.CustomListView1.Items(0).SubItems(3).Text = "Value 4"
Me.CustomListView1.Items(0).SubItems(4).Text = "Value 5"




Esa sería la idea, ahora, el comportamiento que debería tener la clase CustomListView al eliminar una columna o añadir una nueva despues de que un item ya haya sido añadido, sería cosa tuya.

Saludos.








okik

Cita de: Eleкtro (sin pilas) en 20 Enero 2019, 01:51 AM
reimplemento las funciones "Add" que se encargan de añadir el item en la colección...

Vaya, eso no lo sabía hacer yo...  :-\

Bueno gracias, eso justo sería lo que digo.