Hola amigos
Hasta ahora he estado usando Windows Forms, pero para conseguir un aspecto gráfico más bonito en mi aplicación he decidido usar WPF. El problema es que cambian algunos eventos y propiedades y otras cosas y tengo que ir investigando.
Me ha pasado que ya tenía una apliación hecha en Windows Forms y he ido pasado el código a WPF pero resulta que concretamente esto no lo he sabido resolver.
En Windows Forms creé un Panel y un array de controles con Labels. El panel se crea desde un módulo que he llamado (modCrearPanel). El módulo también tiene eventos y más cosas pero no viene a cuento. La cuestión es poder crear los Labels dentro de un control StackPanel en WPF.
- Primero: Creo un Panel o StackPanel en el Windows Forms y en MainWindow en WPF
- Segundo paso:
EN WINDOWS FORMS
(no es el código original, es una simplificación)
Module Module1
Dim Etiqueta As New Label
Dim lblEtiqueta(4) As Label
Sub CrearPanel()
Dim Y As Integer = 20
Dim X As Integer
Form1.Panel1.BackColor = Color.DarkGray
X = 10 'valor X inicial
For I as Integer = 0 To 3
lblEtiqueta(I) = New Label
lblEtiqueta(I).Width = 15
lblEtiqueta(I).Height = 15
lblEtiqueta(I).BackColor = Color.Gray
lblEtiqueta(I).Location = New Point(X, Y) 'posición X e Y del cuadro
Form1.Panel1.Controls.Add(lblEtiqueta(I)) 'Crea el label
X = X + 20
Next
End Sub
End Module
CON WPF (NO FUNCIONA)
Module Module1
Dim Etiqueta As New Label
Dim lblEtiqueta(4) As Label
Dim Main As MainWindow
Public Sub CrearPanel()
Dim Y As Integer = 10
Dim X As Integer
Main.StackPanel1.Background = Brushes.DarkGray
X = 10
For i As Integer = 0 To 3
lblEtiqueta(i) = New Label
lblEtiqueta(i).Background = Brushes.Gray
lblEtiqueta(i).Width = 15
lblEtiqueta(i).Height = 15
lblEtiqueta(i).Margin = New Thickness(0, X, Y, 0)
X = X + 20
Main.StackPanel1.Children.Add(lblEtiqueta(i))
Next i
Main.Show()
End Sub
End Module
Para crear el Penel se llama desde el Load o Loaded en WPF a CrearPanel.
Con toda seguridad el problema está en la forma de poder hacer referencia al StackPanel1 que se encuentra en MainWindow. No se como se hace.
Gracias por ayuda
Encontré la forma :laugh:
Module Module1
Dim Etiqueta As New Label
Dim lblEtiqueta(4) As Label
Private app As Application
Private Main As MainWindow
Public Sub CrearPanel()
Dim Y As Integer = 10
Dim X As Integer
app = System.Windows.Application.Current
Main = CType(app.MainWindow, MainWindow)
Main.StackPanel1.Background = Brushes.DarkGray
X = 10
For i As Integer = 0 To 3
lblEtiqueta(i) = New Label
lblEtiqueta(i).Background = Brushes.Gray
lblEtiqueta(i).Width = 15
lblEtiqueta(i).Height = 15
lblEtiqueta(i).Margin = New Thickness(0, X, 0, Y)
X = X + 20
Main.StackPanel1.Children.Add(lblEtiqueta(i)) 'Crea el label
Next i
End Sub
End Module
Esto es lo que había que añadir al código para poder hacer referencia a objetos creados en MainWindow
Private app As Application
Private Main As MainWindow
Public Sub CrearPanel()
app = System.Windows.Application.Current
Main = CType(app.MainWindow, MainWindow)
Main.StackPanel1.Background = Brushes.DarkGray
End Sub
Encontré la solución aquí:
https://msdn.microsoft.com/es-es/library/vstudio/ms750944%28v=vs.100%29.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1 (https://msdn.microsoft.com/es-es/library/vstudio/ms750944%28v=vs.100%29.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1)
Ahora que lo he conseguido hacer solo falta colocar correctamente los labels ya que en susitución a "Location" he usado "Margin" y no funciona igual. Veré a ver :-\
Saludos
Respecto al código que has mostrado para WindowsForms, yo evitaría el uso de un módulo en el cual supuestamente defines eventos y los disparas o pones en escucha algún event-handlers despreocupándote de su tiempo de vida, donde además declaras objetos (controles) que probablemente nunca liberarás maunálmente (hasta finalizar la app), pues yo lo haría más o menos así ...dentro de lo que cabe para este ejemplo en particular, en una Class que implementa la interfáz IDisposable:
Public Class TestClass : Implements IDisposable
Private ReadOnly lbl As Label
Private ReadOnly lblArray(3) As Label
Private ReadOnly pnl As Panel
<DebuggerStepThrough>
Public Sub New(ByVal pnl As Panel)
Me.pnl = pnl
Me.lbl = New Label
For index As Integer = 0 To (Me.lblArray.Length - 1)
Me.lblArray(index) = New Label
Next index
Me.CrearPanel()
End Sub
Private Sub New()
End Sub
Private Sub CrearPanel()
Dim startPos As New Point(x:=10, y:=20)
Dim margin As Integer = 20
Me.pnl.BackColor = Color.DarkGray
For Each lbl As Label In Me.lblArray
With lbl
.Width = 15
.Height = 15
.BackColor = Color.Gray
.Location = startPos 'posición X e Y del cuadro
startPos.X += margin
End With
Next lbl
If Not Me.pnl.InvokeRequired Then
Me.pnl.Controls.AddRange(Me.lblArray)
Else
Me.pnl.Invoke(Sub() Me.pnl.Controls.AddRange(Me.lblArray))
End If
End Sub
#Region "IDisposable Support"
' To detect redundant calls when disposing.
Private isDisposed As Boolean = False
''' <summary>
''' Releases all the resources used by this instance.
''' </summary>
Public Sub Dispose() Implements IDisposable.Dispose
Me.Dispose(isDisposing:=True)
GC.SuppressFinalize(obj:=Me)
End Sub
Protected Sub Dispose(ByVal isDisposing As Boolean)
If Not Me.isDisposed Then
If isDisposing Then
' Dispose managed objects here...
If Me.lbl IsNot Nothing Then
Me.lbl.Dispose()
End If
For Each lbl As Label In Me.lblArray
If lbl IsNot Nothing Then
lbl.Dispose()
End If
Next lbl
End If
End If
Me.isDisposed = True
End Sub
#End Region
End Class
Modo de empleo:
Dim cosa As New TestClass(Me.Panel1)
' cosa.Dispose()
Sobre WPF, asumiré que el control que has elegido cómo equivalente de un panel es un Canvas, en caso contrario hazlo (es lo recomendable por la MSDN).
La respuesta corta es que debes asignar el margen del control con el uso de la propiedad Margin:
Label.Margin = New Thickness(Point.X, Point.Y, 0, 0)
También puedes utilizar las funciones Canvas.SetLeft y Canvas.SetTop para asignar el margen de un control hijo:
Canvas.Children.Add(Label)
Canvas.SetLeft(label, Point.X)
Canvas.SetTop(label, Point.Y)
La respuesta larga es que, si te sientes más agusto con la familiaridad de la tecnología WindowsForms, entonces podrías heredar un label para definir la propiedad personalizada Location y usarla cómo la solias usar antes:
Public Class CustomLabel : Inherits Label
Public Property Location() As Point
Get
Return New Point(MyBase.Margin.Left, MyBase.Margin.Top)
End Get
Set(ByVal value As Point)
' La lógica del método "Set" se podría mejorar para que realmente se pueda considerar un "Location".
MyBase.Margin = New Thickness(value.X, value.Y, 0, 0)
End Set
End Property
End Class
Y este código sería el equivalente para WPF de la class de WinForms que mostré arriba, donde aquí como puedes ver no implemento la interfáz IDisposable, ya que a diferencia de WinForms, la mayoría de controles realmente no tienen ningún recurso que liberar.
Public NotInheritable Class TestClass
Private ReadOnly lbl As Label
Private ReadOnly lblArray(3) As Label
Private ReadOnly pnl As Canvas
<DebuggerStepThrough>
Public Sub New(ByVal pnl As Canvas)
Me.pnl = pnl
Me.lbl = New Label
For index As Integer = 0 To (Me.lblArray.Length - 1)
Me.lblArray(index) = New Label
Next index
Me.CrearPanel()
End Sub
Private Sub New()
End Sub
Private Sub CrearPanel()
Dim startPos As New Point(x:=10, y:=20)
Dim margin As Integer = 20
Me.pnl.Background = Brushes.Gray
For Each lbl As Label In Me.lblArray
With lbl
.Width = 15
.Height = 15
.Background = Brushes.Red
.Margin = New Thickness(startPos.X, startPos.Y, 0, 0)
startPos.X += margin
End With
Me.pnl.Children.Add(lbl)
Next lbl
End Sub
End Class
Modo de empleo:
Dim cosa As New TestClass(Me.Canvas1)
Saludos
Gracias muy buena respuesta, me has resuelto todas las dudas.;-)
Y lo del canvas es lo que buscaba, creía que el equivalente en WPF era el stackpanel :P
Cita de: Lekim en 23 Septiembre 2015, 15:54 PMY lo del canvas es lo que buscaba, creía que el equivalente en WPF era el stackpanel :P
Esto te podría servir de ayuda para futuras dudas respecto a otros controles...
➢
Windows Forms Controls and Equivalent WPF Controls - MSDN (https://msdn.microsoft.com/en-us/library/vstudio/ms750559%28v=vs.100%29.aspx?f=255&MSPPError=-2147217396)
Saludos!
Ok, gracias Elektro
Por curiosidad he probado de hacer algo parecido con el código que expuse al principio. A ver que te parece ::)
Module Module1
Dim lblEtiqueta(4) As Label
Sub CrearPanel(ByVal pnl As Object, ByVal Disponible As Boolean)
Dim Starlbl As New Point(x:=10, y:=20)
pnl.backcolor = Color.DarkGray
If Disponible Then
For I As Integer = 0 To 3
lblEtiqueta(I) = New Label
lblEtiqueta(I).Width = 15
lblEtiqueta(I).Height = 15
lblEtiqueta(I).BackColor = Color.Gray
lblEtiqueta(I).Location = Starlbl 'posición X e Y del cuadro
pnl.Controls.Add(lblEtiqueta(I)) 'Crea el label
Starlbl.X += 20
Next
Else
Try
For Index As Integer = 0 To 3
lblEtiqueta(Index).Dispose()
Next Index
Catch ex As Exception
End Try
End If
End Sub
End Module
Para llamar uso:
(para mostrar los Labels)
CrearPanel(Panel1, True)
(para quitar los labels)
CrearPanel(Panel1, False)