Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Mensajes - Eleкtro

#551
.NET (C#, VB.NET, ASP) / Re: Error en Listview
20 Enero 2019, 01:51 AM
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.
#552
.NET (C#, VB.NET, ASP) / Re: Error en Listview
19 Enero 2019, 14:45 PM
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.
#553
No quiero parecer pedante ni condescendiente ni pesado, pero no hay nada que envidiar, son cosas muy sencillitas. La manipulación de arrays (o jagged arrays) uni o multidimensionales es de las primeras cosas que se aprende a hacer si se estudia siguiendo unos pasos correctos de aprendizaje. Y el resto que he podido mostrarte como la herencia de clases o el uso de tipos genéricos pues son conceptos fundamentales de la programación orientada a objetos.

No te he mostrado nada que no pudieras llegar a hacer por ti mismo con el debido aprendizaje y la posterior práctica, pero como eres un tio de familia pues se entiende que no tengas tiempo o ganas suficiente.

En fin. Un placer ayudar a personas así (de agradecidas).

Saludos.
#554
Cita de: Tazmania40 en 19 Enero 2019, 00:11 AM
Friend NotInheritable : porque empleas que la clase sea Friend y este modificador (es la clase base según he leido). He probado con Public (funciona y sin modificador) que siempre realizo cuando creo mis programas, claro dentro de una clase externa. Me imagino que Friend es para que no se pueda acceder externamente, aunque ahi yo suelo emplear Private, siempre he tenido un lio con estas cosas que son sencillas.

Realmente no tiene mucha importancia. El modificador de visibilidad de clase Friend hace que la clase solamente sea accesible desde tu proyecto/executable. Simplemente consideré que era la visibilidad de clase más acertada para tu código, puesto que el modificador Public permite acceder a la clase desde cualquier otra clase y no creo que vayas a necesitar hacer eso.

El modificador de clase NotInheritable (sealed en C#) lo que hace es "sellar" la clase para que no se pueda heredar (usando el keyword Inherits como en la clase del CustomPictureBox), es decir, para que no se pueda usar como una clase base.
Este sellado resulta en una pequeña optimización, así que si no tienes necesidad de heredar una clase entonces no hay problema en sellarla usando NotInheritable, pero tampoco pasa nada por no hacerlo...

Aquí te dejo info acerca de las optimizaciones de usar NotInheritable:

Y las guías de diseño que recomienda Microsoft sobre el sellado de clases:

Ojo, esas recomendaciones de Microsoft parecen estar orientadas a escenarios profesionales (ej. el desarrollo de una API pública), ya que sugieren cosas como: "Sellar una clase porque no se puede pensar en un escenario de extensibilidad no es una buena razón" - pero evidentemente no puede existir un escenario de extensibilidad de tu clase "TestClass" puesto que en principio el código de esa clase sellada es solo para que lo uses tú en tu programa, así que aquí pasa a ser más que una buena razón para sellar la clase, y por ello no debes hacerle mucho caso a ciertas recomendaciones en ese sentido.

Saludos.
#555
Cita de: Tazmania40 en 18 Enero 2019, 10:10 AM
Como bien dices la propiedad Tag podemos guardar esas coordenadas, pero lamentablemente la utilizo para guardar valores. Otra posibilidad es agregar otra propiedad personal al control PictureBox (Como Tag, aunque claro serían otras 2 más Matriz(F, C) guardar F y C) , pero sería muy engorroso y alargaría mucho el código, además de que no se.

La propiedad Tag es de tipo Object, lo que permite asignarle cualquier tipo de objeto, y esto quiere decir que puedes diseñar una clase como la siguiente, en la que almacenarías los datos que tu quisieras, y luego asignar una instancia de esa clase a al propiedad Tag...

Código (vbnet) [Seleccionar]
Friend NotInheritable Class TestClass

   Public Property TestProperty1 As Object
   Public Property TestProperty2 As Object

   Public Sub New()
   End Sub

End Class


No hace falta mencionar que en esa clase añadirías la cantidad de propiedades que realmente necesites (donde asignarías los índices del array multidimensional, entre otras cosas que desees), y del tipo que realmente sean, no necesariamente del tipo Object. Y entonces podrías hacer:

Código (vbnet) [Seleccionar]

For A = 0 To 4
   ...
   Dim obj As New TestClass()
   obj.TestProperty1 = A ' Indice.
   obj.TestProperty2 = asignar otra cosa distinta...
   Lista(A).Tag = obj
   ...
Next A

(o lo mismo pero en el búcle del array bidimensional)

...
Código (vbnet) [Seleccionar]
Private Sub Evento1(sender As Object, e As EventArgs)
   Dim pcb As PictureBox = DirectCast(sender, PictureBox)
   Dim obj As TestClass = DirectCast(pcb.Tag, TestClass)
   ...
End Sub


¿Eso no te sirve para las intenciones que tengas?. Esto sería más rápido que iterar los elementos de un array para hallar el control en cuestión.

De todas formas, si realmente quieres encontrar el índice del control en un array multidimensional, en este ejemplo bidimensional, tan solo debes recorrer sus dimensiones, y lo puedes hacer de la siguiente manera:

Código (vbnet) [Seleccionar]
Public Shared Function IndicesOf(Of T)(ByVal [array] As T(,), ByVal value As T) As Integer()

   For i As Integer = [array].GetLowerBound(0) To [array].GetUpperBound(0)
       For j As Integer = [array].GetLowerBound(1) To [array].GetUpperBound(1)
           If [array](i, j)?.Equals(value) Then
               Return {i, j}
           End If
       Next j
   Next i

   Return Nothing

End Function

...
Código (vbnet) [Seleccionar]
Private Sub Evento1(sender As Object, e As EventArgs)
   Dim indices As Integer() = IndicesOf(Matriz, DirectCast(sender, PictureBox))
   Dim pcb As PictureBox = Matriz(indices(0), indices(1))
   ...
End Sub


Saludos.




EDITO:

Casi se me olvida mostrarte la alternativa que mencionaste de añadirle una segunda propiedad "Tag" a la clase PictureBox...

Es tan simple como heredar la clase PictureBox y declarar una propiedad personalizada:

Código (vbnet) [Seleccionar]
Public Class CustomPictureBox : Inherits PictureBox

   Public Property Tag2 As Object

End Class


pero ten en cuenta que esto es un "overkill" puesto que con un propiedad tag es más que suficiente al poderle asignar cualquier tipo de objeto, y este puede ser una clase o estructura que contenga múltiples valores como ya mostré en el ejemplo de arriba. Lo que intento decir es que el pensamiento de "2 siempre es mejor que 1" en realidad resulta algo innecesario por lo que acabo de mencionar, por que la solución óptima no sería crear múltiples propiedades similares a Tag, sino en su lugar crear un tipo pesonalizado donde almacenar múltiples valores, y asignar una instancia de ese tipo a la propiedad Tag.

Y por último, aquí tienes lo mismo pero con una personalización más sofisticada o cuidada para la manipulación de este PictureBox personalizado en el diseñador de forms:

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

   <DisplayName(NameOf(CustomPictureBox.Tag2))>
   <Description("Additional user-defined data associated with the object.")>
   <Category("Data")>
   <Browsable(True)>
   <Bindable(True)>
   <DefaultValue(DirectCast(Nothing, Object))>
   <Localizable(False)>
   <TypeConverter(GetType(StringConverter))>
   Public Property Tag2 As Object

End Class

#556
He escrito una solución más genérica:

Código (vbnet) [Seleccionar]

<hidemodulename>
Public module TextFieldParserExtensions

''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' Converts the source <see cref="TextFieldParser"/> to <see cref="DataTable"/>.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
''' <param name="sender">
''' The source <see cref="TextFieldParser"/>.
''' </param>
'''
''' <param name="useFirstRowAsColumns">
''' If set to <see langword="True"/>, use the items of the first row of
''' the source <see cref="TextFieldParser"/> to create the columns of
''' the resulting <see cref="DataTable"/>.
''' </param>
''' ----------------------------------------------------------------------------------------------------
''' <returns>
''' The resulting <see cref="DataTable"/>.
''' </returns>
''' ----------------------------------------------------------------------------------------------------
<DebuggerStepThrough>
<Extension>
<EditorBrowsable(EditorBrowsableState.Always)>
Public Function ToDataTable(ByVal sender As TextFieldParser, ByVal useFirstRowAsColumns As Boolean) As DataTable

   Dim dt As New DataTable() With {.CaseSensitive = False}
   Dim customColumnsCreated As Boolean
   Dim fields As String() = Nothing

   Do Until sender.EndOfData
       Try
           fields = sender.ReadFields()

       Catch ex As MalformedLineException
           Throw

       End Try

       If Not (customColumnsCreated) AndAlso (useFirstRowAsColumns) Then
           For Each field As String In fields
               dt.Columns.Add(field)
           Next field
           customColumnsCreated = True
           Continue Do
       End If

       Try
           dt.Rows.Add(fields)

       Catch ex As ArgumentException When Not (useFirstRowAsColumns) AndAlso (ex.HResult = -2147024809) ' Input array is longer than the number of columns in this table.
           For i As Integer = 0 To ((fields.Count - dt.Columns.Count) - 1)
               dt.Columns.Add()
           Next i
           dt.Rows.Add(fields)

       End Try

   Loop

   Return dt
End Function

end module


Modo de empleo:
Código (vbnet) [Seleccionar]
Dim csvTable As New DataTable()

Dim csvText As String =
   <csv>
        Name; Last Name; Age
        Michael; Johnson Phillips; 26
        William; Lee Williams; 34
        Susan; Parker Evans; 32
        Matilda; Garcia Martinez; 28
   </csv>.Value

Using csvReader As New StringReader(csvText),
     csvParser As New TextFieldParser(csvReader) With {
     .Delimiters = {";"c},
     .HasFieldsEnclosedInQuotes = False,
     .TextFieldType = FieldType.Delimited
}

   csvTable = TextFieldParserExtensions.ToDataTable(csvParser, useFirstRowAsColumns:=True)
End Using

Me.DataGridView1.DataSource = csvTable


PD: todo esto y mucho más en mi librería comercial DevCase para .NET Framework en la página de CodeCanyon.net...
#557
Lo mejor que puedes hacer si no dominas la manipulación del registro de Windows, es dejarlo como está.

Los posibles rastros que existan en el registro de Windows despues de una desinstalación satisfactoria de un software (usando el desinstalador específico para dicho software), no van a causar ningún tipo de daño en tu sistema operativo, ni tampoco van a ocasionar ningún problema de rendimiento por que existan un par de claves sin borrar de las cientos de miles que suelen haber en un sistema operativo, así que despreocúpate.

Cita de: jandres en 15 Enero 2019, 18:50 PMQue se hace en esos casos? Se borra la clave aunque tenga otro nombre, asi eliminando todos lo valores incluidos los no tachados? O simplemente se borra el valor premarcado en morado dejando la clave y demas tal como esta?

Como comprenderás, no hay respuesta a esta duda, pues no se sabe a que clave te refieres en específico.

Insisto en que dejes el registro de Windows como está, y limítate a utilizar programas de limpieza como por ejemplo CCleaner, o programas que detectan rastros de desinstalación, como por ejemplo Uninstall Tool o Revo Uninstaller.

Un saludo.
#558
Cita de: Tazmania40 en 17 Enero 2019, 13:12 PMal hacer click en cualquiera de ellos obtenemos el índice del
que hemos pulsado y así podemos utilizar las propiedades de cada uno de ellos.

No entiendo tu planteamiento. Si el objetivo realmente es obtener un índice con el que poder obtener acceso al control y usar sus propiedades, entonces la obtención del índice carece de sentido puesto que el objeto sender es una referencia de dicho control, pudiendo hacer algo así:

Código (vbnet) [Seleccionar]
Private Sub Evento1(sender As Object, e As EventArgs)
   Dim pcb As PictureBox = DirectCast(sender, PictureBox)
   ' Hacer aquí lo que quieras con este PictureBox...
End Sub


Para todo lo demás, una forma simple de almacenar datos adicionales (que en este caso ayuden a la identificación del control dentro de un array) sería usar la propiedad Control.Tag que hereda la clase PictureBox, ahí puedes especificar el índice y dimensión del Array o lo que tú quieras al momento de crear la instancia de dicho control en los búcles esos que tienes...

Código (vbnet) [Seleccionar]
For A = 0 To 4
    ...
   Lista(A).Tag = A ' Índice.
    ...
Next A


Pero como ya digo esto en principio no es necesario, puesto que en el controlador de eventos "Evento1" ya tienes acceso al control mediante el objeto sender.

Saludos.
#559
Foro Libre / Re: Que opináis de VOX
17 Enero 2019, 22:11 PM
Lo que voy a decir es ua obviedad, pero parece que a los adultos hay que recordarles cosas como si fueran bebés. La política está llena de engaños y manipulación, creando enemigos donde no los hay precisamente por la cobardía de los partidos a perder su poder de control hacia esa partte de la sociedad que manipulan para que le entreguemos nuestro voto. Eso es más o menos lo que opino de VOX, o mejor dicho, de sus atacantes.

[youtube=640,360]https://www.youtube.com/watch?v=TDQD36-1Km8[/youtube]

Si a vosotros os parece normal que una cadena de televisión de España haga un reportaje especial con la premisa de ir en busca de los 4 o 6 votantes de VOX en un pueblucho para preguntarle por que han votado a VOX, como si estos fuesen delincuentes que deben dar explicaciones por sus delitos, ir hasta allá para encontrarlos e intentar ridiculizarlos para señalarlos con el dedo... es lamentable.

Manipulación.
#560
Un libro que de por si se titula "aprende X en 21 días", no merece la pena ser leido. Además, según Amazon ese libro fue publicado 2004 ( https://www.amazon.com/Aprendiendo-Visual-Basic-Net-Spanish/dp/970260379X ), eso significa que está completamente desfasado. Ese libro está limitado a enseñanzas para la versión 1.0 - 1.1 de .NET Framework, versiones antiguas de la sintaxis de Visual BASIC.NET, y de una versión de Visual Studio que directamente no vas a poder instalar ni usar en tu sistema operativo moderno.
Si quieres perder el tiempo en aprender cosas que ya no se hacen, o técnicas que se hacen de manera mucho más simple y optimizada que en esos tiempos remotos, adelante, pero estás avisado por mi parte.

Cualquier otro libro reciente será más instructivo que ese libro de los 21 días, cualquiera, aunque sea de peor calidad, mientras el contenido de la enseñanza sea reciente. Y si tienes tiempo y ganas, yo te diría de visualizar videotutoriales de pago profesionales y recientes, como los de pluralsight.com., de .NET, C# y Visual Studio en general, no solo VB.NET.

Un saludo