como posicionar los controles agregados en tiempo de ejecucion de un UserControl WPF VB.net

Iniciado por juanedwin, 4 Diciembre 2021, 04:03 AM

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

juanedwin

saludos
Estoy creando un userControl(WPF) para usarlo en mi windowsform, el asunto es que ya pude agregar un boton al user control en tiempo de ejecucion; bueno basicamente el proyecto de prueba que tengo es un form en el que agrego el usercontrol y un pequeño boton, este pequeño boton al presionarlo añade en tiempo de ejecucion un boton al usercontrol, pero me lo muestra en el centro, quisiera poder moverlo ya sea con el mouse o al momento de crearlo darle una posicion left o top algo asi, pero no encuentro los left y top o que otro comando es, soy casi nuevo en esto , por favor estoy haciendo bien  asi , o que ruta debo seguir... saludos

Mohicano

En WPF puedes probar lo siguiente:

Private Function GetBoundingBox(ByVal element As FrameworkElement, ByVal containerWindow As Window) As Rect
   Dim transform As GeneralTransform = element.TransformToAncestor(containerWindow)
   Dim topLeft As Point = transform.Transform(New Point(0, 0))
   Dim bottomRight As Point = transform.Transform(New Point(element.ActualWidth, element.ActualHeight))
   Return New Rect(topLeft, bottomRight)
End Function


CÓDIGO MEJORADO:

    Private Function GetBoundingBox(element As FrameworkElement) As Rect
        Dim containerWindow As Window = Window.GetWindow(element)
        Dim transformer As GeneralTransform = element.TransformToAncestor(containerWindow)
        Dim topLeft As Point = transformer.Transform(New Point())
        Dim bottomRight As Point = transformer.Transform(element.RenderSize)
        Return New Rect(topLeft, bottomRight)
    End Function


EJEMPLO:
Dim element As FrameworkElement = Me.Button1
Dim rc As Rect = GetBoundingBox(element)
Console.WriteLine($"Size: {{Width:{rc.Size.Width}, Height:{rc.Size.Height}}}; Location: {{X:{rc.Location.X}, Y:{rc.Location.Y}}}")


Código en C#:
https://social.msdn.microsoft.com/Forums/en-US/ce88562e-4195-45f2-ac1c-4571279a84a3/wpf-equivalent-for-windows-forms-controlclientrectangle-property?forum=wpf

Y otra posible solución:
https://stackoverflow.com/a/11079520/1248295
(lee los comentarios de esa respuesta si no te funciona)

Para Windowsforms puedes utilizar la propiedad Control.Bounds que contiene el tamaño (Control.Size) y la ubicación relativa (Control.Location):

https://docs.microsoft.com/es-es/dotnet/api/system.windows.forms.control.bounds?view=windowsdesktop-6.0

Otras propiedades de interés y utilidad son Control.ClientRectangle y Control.DisplayRectangle:

https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.control.clientrectangle?view=windowsdesktop-6.0
https://docs.microsoft.com/es-es/dotnet/api/system.windows.forms.control.displayrectangle?view=windowsdesktop-6.0

juanedwin

saludos, mi xaml esta vacio solo tiene el Grid...
codigo del usercontrol
Public Class UserControl1
    Public Sub AgregarControl(ByVal Objeto As String) ' la variable objeto es para poner distintos controles segun la peticion
        Dim b As New Button With {.Background = Brushes.Crimson, .Width = 20, .Height = 10, .Tag = 1}
        b.VerticalAlignment = Rnd(2)
        Grid1.Children.Add(b)
    End Sub
End Class


Aqui en el boton del formulario
Public Class Form1
    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        UserControl11.AgregarControl("w")
    End Sub
End Class


al presionar clic en el boton añade un boton al usercontrol pero quisiera darle ubicacion y/o despues creare un evento que permita arrastrar los controles añadidos con el mouse, recien estoy empezando, no entendi mucho tu respuesta,  mi proyecto de prueba seria similar o parecido a un editor grafico super ultra basico, en este caso tengo un UserControl WPF, un Form en este form tengo dos controles añadidos un boton y el UserControl, al hacer clic en el boton se añaden controles al usercontrol, pero quisera darles posicion..... no se si con la forma que comenze este bien, saludos y gracias anticipadas por tu respuesta   

Mohicano

Cita de: juanedwinno entendi mucho tu respuesta

Cita de: juanedwin"al momento de crearlo darle una posicion left o top algo asi, pero no encuentro los left y top o que otro comando es"

Mi respuesta (el código que te mostré) pretendía darte la solución a esa duda para poder obtener la ubicación (left, top) del elemento en tiempo de ejecución. Pero haciéndolo desde WPF.

Al Grid que tienes actualmente podrías añadirle un Canvas, ya que este te facilitaría y simplificaría la tarea de posicionar controles como lo indica en la propia descripción: "Defines an area within which you can explicitly position child elements by using coordinates that are relative to the Canvas area."

Es decir:
Public Class UserControl1

   Public Sub AgregarControl(ByVal Objeto As String) ' la variable objeto es para poner distintos controles segun la peticion
       Dim b As New Button With {.Background = Brushes.Crimson, .Width = 20, .Height = 10, .Tag = 1}
       b.VerticalAlignment = Rnd(2)
       ' Grid1.Children.Add(b)
       Canvas1.Children.Add(b)
   End Sub

End Class


Y entonces, para posicionar el user-control desde WindowsForms:
...
ElementHost1.Child = wpfButton
...

Dim element As UIElement = wpfButton
Dim position As New System.Drawing.Point(10, 10)
System.Windows.Controls.Canvas.SetLeft(element, CDbl(position.X))
System.Windows.Controls.Canvas.SetTop(element, CDbl(position.Y))


Ten en cuenta que ese código no te va a funcionar sin un Canvas.

Si prefieres no usar un Canvas y mantener el código actual de tu grid, entonces puedes usar la propiedad FrameworkElement.Margin, aunque no la he probado en todos los escenarios posibles...

He escrito un par de métodos / extensiones reutilizables para simplificarlo:

Public Module FrameworkElementExtensions

   ' Gets the coordinates of the source <see cref="FrameworkElement"/> element relative to its <see cref="ElementHost"/> container.
   <Extension>
   Public Function GetLocation(element As FrameworkElement) As System.Drawing.Point
       Return New System.Drawing.Point(element.Margin.Left, element.Margin.Top)
   End Function

   ' Sets the coordinates of the source <see cref="FrameworkElement"/> element relative to its <see cref="ElementHost"/> container.
   <Extension>
   Public Sub SetLocation(element As FrameworkElement, position As System.Drawing.Point)
       element.Margin = New Thickness(position.X, position.Y, element.Margin.Right, element.Margin.Bottom)
   End Sub

End Module


Esos métodos asumen que la propiedad Margin siempre devolverá el valor esperado, pero como ya digo no estoy del todo convencido de que vaya a ser así, dependiendo de factores que desconozco de la composición y alineación de los componentes de un Grid (yo prácticamente no programo nada en WPF).

Ejemplo desde WindowsForms:
...
ElementHost1.Child = wpfButton
wpfButton.SetLocation(New System.Drawing.Point(10, 10))
Debug.WriteLine(wpfButton.GetLocation())
...

juanedwin

Gracias, la opcion mas adecuada para este trabajo es canvas, puesto que asi es mas facil el manejo de las posiciones que deseo. el grid era un poco complicado por las filas y las columnas, con el canvas se asemeja a un panel windows from.... gracias lo estare probando