Foro de elhacker.net

Programación => .NET (C#, VB.NET, ASP) => Mensaje iniciado por: okik en 19 Enero 2019, 12:18 pm



Título: Error en Listview
Publicado por: okik en 19 Enero 2019, 12:18 pm
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
  1.     ListView1.Items(0).SubItems.Add("")
  2.     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.


Título: Re: Error en Listview
Publicado por: Eleкtro en 19 Enero 2019, 14:45 pm
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.

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.



¿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
  1. 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
  1. 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...



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.

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
  1. Dim lvi As New ListViewItem({"item1", "item2", "item3"})
  2.  
  3. 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.


Título: Re: Error en Listview
Publicado por: okik en 19 Enero 2019, 21:56 pm
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


Título: Re: Error en Listview
Publicado por: Eleкtro en 20 Enero 2019, 01:51 am
Pero 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...



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.

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
  1. <DisplayName(NameOf(CustomListView))>
  2. <Description("A custom ListView control.")>
  3. <DesignTimeVisible(True)>
  4. <DesignerCategory(NameOf(DesignerCategoryAttribute.Default))>
  5. <ToolboxBitmap(GetType(ListView), "ListView.bmp")>
  6. <ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Require)>
  7. <ClassInterface(ClassInterfaceType.AutoDispatch)>
  8. <ComVisible(True)>
  9. <DefaultProperty(NameOf(CustomListView.Items))>
  10. <DefaultEvent(NameOf(CustomListView.SelectedIndexChanged))>
  11. <Docking(DockingBehavior.Ask)>
  12. <PermissionSet(SecurityAction.Demand, Name:="FullTrust")>
  13. Public Class CustomListView : Inherits ListView
  14.  
  15.    <DisplayName(NameOf(CustomListView.Items))>
  16.    <Description("The items in the ListView")>
  17.    <DesignerSerializationVisibility(DesignerSerializationVisibility.Content)>
  18.    <Localizable(True)>
  19.    <MergableProperty(False)>
  20.    <Browsable(True)>
  21.    Public Shadows ReadOnly Property Items As CustomListViewItemCollection
  22.  
  23.    Public Sub New()
  24.        MyBase.New()
  25.        Me.Items = New CustomListViewItemCollection(Me)
  26.    End Sub
  27.  
  28. End Class

Código
  1. <DefaultMember("Item")>
  2. <ListBindable(False)>
  3. Public Class CustomListViewItemCollection : Inherits ListViewItemCollection
  4.  
  5.    Private ReadOnly owner As ListView
  6.  
  7.    Public Sub New(owner As ListView)
  8.        MyBase.New(owner)
  9.        Me.owner = owner
  10.    End Sub
  11.  
  12.    Public Overrides Function Add(value As ListViewItem) As ListViewItem
  13.        Return Me.CreateAllSubItems(MyBase.Add(value))
  14.    End Function
  15.  
  16.    <DebuggerStepThrough>
  17.    Private Function CreateAllSubItems(value As ListViewItem) As ListViewItem
  18.        Dim diff As Integer = (Me.owner.Columns.Count - value.SubItems.Count)
  19.        If (diff > 0) Then
  20.            For i As Integer = 0 To (diff - 1)
  21.                value.SubItems.Add(String.Empty)
  22.            Next i
  23.        End If
  24.  
  25.        Return value
  26.    End Function
  27.  
  28. End Class

Modo de empleo:
Código
  1. Me.CustomListView1.View = System.Windows.Forms.View.Details
  2.  
  3. ' Creamos 5 columnas.
  4. For i As Integer = 1 To 5
  5.    Me.CustomListView1.Columns.Add(String.Format("Column {0}", i))
  6. Next i
  7.  
  8. ' Añadimos un item donde se crearán subitems o "celdas" vacías para las cinco columnas.
  9. Me.CustomListView1.Items.Add("")
  10.  
  11. ' Especificamos los valores de los cinco subitems
  12. ' sin necesidad de haber llamado al método SubItems.Add() para cada uno de ellos...
  13. Me.CustomListView1.Items(0).SubItems(0).Text = "Value 1"
  14. Me.CustomListView1.Items(0).SubItems(1).Text = "Value 2"
  15. Me.CustomListView1.Items(0).SubItems(2).Text = "Value 3"
  16. Me.CustomListView1.Items(0).SubItems(3).Text = "Value 4"
  17. Me.CustomListView1.Items(0).SubItems(4).Text = "Value 5"

(https://i.imgur.com/Pv1rLyr.png)

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.


Título: Re: Error en Listview
Publicado por: okik en 20 Enero 2019, 14:29 pm
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.