Toolbox en C#

Iniciado por Nolohagan, 28 Marzo 2017, 14:07 PM

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

Nolohagan

Hola,

cómo puedo hacer un toolbox como el de Visual Studio en C#? Que controles necesito?

Gracias y saludos

Eleкtro

#1
Basicamente es un control de tipo TreeView.

En la tecnología WinForms utilizarías el control TreeView:

Y en la tecnología WPF utilizarías el control TreeView también:

Si necesitas llevar a cabo personalizaciones drásticas en el diseño por defecto, entonces el control lo tomarías como base para heredar la clase y hacerte responsable de controlar todo (o parte de) el dibujado del control y el dibujado de los elementos del árbol/jerarquía de etiquetas.

PD: Las preguntas sobre C# / .NET van en el foro de programación de .NET. Por favor, deja de seguir publicando más preguntas sobre programación en el foro de Dudas Generales,

Saludos!








Nolohagan

Hola Elektro,

pero como hago para agregarle a la Treeview por ejemplo un ListBox y despues arrastrar ese ListBox a otra parte?

Gracias y saludos

Eleкtro

#3
Hola.

Ya que no has especiicado a que tecnología te refieres, voy a asumir que es WindowsForms.

Cita de: Nolohagan en 29 Marzo 2017, 10:08 AMpero como hago para agregarle a la Treeview por ejemplo un ListBox y despues arrastrar ese ListBox a otra parte?

Lo primero sería tan sencillo como declarar e instanciar un ListBox, y posteriórmente añadirlo a la colección de controles del TreeView:

Código (csharp) [Seleccionar]
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
using System.Security.Permissions;

[DisplayName("MyTreeView")]
[Description("A extended TreeView control.")]
[DesignTimeVisible(true)]
[DesignerCategory("UserControl")]
[ToolboxBitmap(typeof(TreeView), "TreeView.bmp")]
[ToolboxItem(true)]
[ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Require)]
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public class MyTreeView : TreeView, IDisposable {

   [Browsable(true)]
   [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
   [Category("Child Controls")]
   public ListBox ListBox {get { return this.listBoxB; }}
       private ListBox listBoxB; // Backing field.

   [DebuggerStepThrough()]
   public MyTreeView() {
       this.SuspendLayout();
       this.listBoxB = new ListBox();
       this.Controls.Add(this.listBoxB);
       this.listBoxB.Show();
       this.ResumeLayout(performLayout: false);
   }

   [DebuggerStepThrough()]
   protected override void Dispose(bool disposing) {
       if ((disposing)) {
           if ((this.listBoxB != null)) {
               this.listBoxB.Dispose();
               this.listBoxB = null;
           }
       }

       base.Dispose(disposing);

   }

}





Para llevar a cabo lo segundo, no puedo mostrarte un ejemplo, basicamente por que es algo que requiere horas, dias o incluso semanas de trabajo y dedicación (no voy a hacerle el trabajo a otra persona). Se necesita una comprensión mínima sobre la jerarquía de ventanas Win32, el sistema de mensajería de Windows, el dibujado mediante GDI+, y mucha práctica adquirida previamente si se quiere intentar crear un control de usuario persoanlizado que cumpla requisitos complejos, de lo contrario sería mejor no intentarlo hasta haber aprendido más sobre el tema.

En la MSDN tienes un montón de guías y ayudas como éstas de aquí abajo para aprender a crear un control de usuario (y controlar el dibujado):

De todas formas...¿por qué motivo exactamente es que quieres añadir un ListBox a un TreeView?, quizás no resultase necesario hacerlo, o quizás te bastase solo con utilizar/subclasear un ListBox..

Bueno, con respecto a lo de "arrastrar el control a otra parte", no sé que significa "a otra parte", no soy adivino, intenta dar explicaciones claras y concisas para no dar a lugar a posibles mal interpretaciones.
De todas formas te puedo decir que para implementar la funcionalidad de arrastrar y soltar necesitarías empezar por controlar los eventos del ListBox (OnMouseDown, OnMouseUp y OnMouseMove) para implementar la funcionalidad de poder arrastrar el control, y en realidad ya no habría mucho más que hacer. Luego, para "arrastrar a otra parte", imagino que a otra parte dentro del área cliente del control padre del ListBox, lo suyo tal vez sería interceptar y procesar por tu cuenta (algunos de) los mensajes de ventana del ListBox como del TreeView mediante el método WndProc para determinar la ubicación del ListBox, computar esa ubicación a las coordenadas del área cliente del TreeView, y por último decidir que hacer (e implementar algoritmos para poder hacerlo) en base a esas coordenadas y otros factores de evaluación que tú decidas. Suena complejo, lo es...un poco.

Te puedo ahorrar la tarea de implementar una funcionalidad de arrastrar y soltar en el ListBox, con esta clase de uso genérico que desarrollé hace un tiempo:


...No es necesario traducirlo a C#, siempre puedes compilarlo a una libreria dinámica o dll.
En caso de que decidas usar mi metodología, la que he compartido en esas clases, entonces es posible que la implementación de esas clases requiera que les hagas ciertas pequeñas modificaciones (ej. eliminar el namespace, eliminar imports) para poder adaptarlo, ya que esas clases las he extraido directamente de mi Framework de pago para .NET Framework, cuyo nombre es "ElektroKit", el cual se puede encontrar a la venta por un módico precio en https://codecanyon.net/ buscando por el nombre ElektroKit.... solo lo menciono para aclarar los motivos del por qué el código está así, y de paso por si esto resulta de tu interés o del interés de alguna ota persona...

¡Saludos!








Nolohagan

Hola Elektro,

muchas gracias por tu ayuda y aporte. Felicitarte por tus ganas de ayudar y amabilidad.

Si, me refiero a la tecnologia Windows Forms.

Citar
Para llevar a cabo lo segundo

A que te refieres con los segundo?

Lo que yo queria hacer era un compilador de un lenguaje de progrmación propio inspirado por
J2ME.

Citar
magino que a otra parte dentro del área cliente del control padre del ListBox, lo suyo tal vez sería interceptar y procesar por tu cuenta (algunos de) los mensajes de ventana del ListBox como del TreeView mediante el método WndProc para determinar la ubicación del ListBox, computar esa ubicación a las coordenadas del área cliente del TreeView, y por último decidir que hacer (e implementar algoritmos para poder hacerlo) en base a esas coordenadas y otros factores de evaluación que tú decidas.

Trabajas en wikipedia?  :o  Se nota que tienes anos de experiencia en C#...

Te mostrare una foto:



Como ves quiero arrastrar un Listbox desde Treeview hasta el panel.

Y tu dices que las clases de uso generico tuyas me seran de ayuda para lo que yo quiero hacer?

Gracias :)

Eleкtro

#5
Cita de: Nolohagan en 30 Marzo 2017, 13:37 PM
A que te refieres con los segundo?

quiero arrastrar un Listbox desde Treeview hasta el panel.

Entonces olvida lo que dije, yo supuse que querías arrastrar el listbox dentro del área cliente del treeview para "insertarlo" en un nodo, así que te advertí de lo que necesitarías o podrías necesitar controlar (como el procedimiento WndProc/mensajes de ventana por si ibas a hacer otro tipo de modificaciones al TreeView), pero si lo que quieres es arrastrar el control a un panel/contenedor externo entonces la cosa no requiere ni la mitad de esfuerzo. Por eso primero de nada siempre hay que aclarar bien lo que uno necesita hacer antes de preguntar en un foro de programación donde los detalles es lo más importante...

Cita de: Nolohagan en 30 Marzo 2017, 13:37 PMY tu dices que las clases de uso generico tuyas me seran de ayuda para lo que yo quiero hacer?

La clase ControlDragger implementa la funcionalidad de mover "X" control por la colección de controles donde dicho control se encuentre; para hacer lo que pides habria que adaptarlo (y sería un coñazo). Pero olvida ese código que te mostré, por que si tan solo quieres arrastrar el control adentro de otra colección de controles entonces no necesitas implementar la funcionalidad de mover el control, lo que necesitas es hacer uso de la funcionalidad Drag&Drop (arrastrar y soltar) que proveen los controles de WindowsForms.




Lo primero de todo que debes tener en cuenta sería activar la propiedad AllowDrop del Panel para permitir soltar objetos/controles adentro:
Código (csharp) [Seleccionar]
this.panel1.AllowDrop = true;

Luego, tomando como ejemplo la clase que te mostré del TreeView, añadirías el siguiente controlador del evento MouseDown:
Código (csharp,30,36,37,38,39,45) [Seleccionar]
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Security.Permissions;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {

   [DisplayName("MyTreeView")]
   [Description("A extended TreeView control.")]
   [DesignTimeVisible(true)]
   [DesignerCategory("UserControl")]
   [ToolboxBitmap(typeof(TreeView), "TreeView.bmp")]
   [ToolboxItem(true)]
   [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Require)]
   [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
   public class MyTreeView : TreeView, IDisposable {

       [Browsable(true)]
       [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
       [Category("Child Controls")]
       public ListBox ListBox { get { return this.listBoxB; } }
       private ListBox listBoxB; // Backing field.

       [DebuggerStepThrough()]
       public MyTreeView(){
           this.SuspendLayout();
           this.listBoxB = new ListBox();
           this.listBoxB.MouseDown += this.ListBox_MouseDown;
           this.Controls.Add(this.listBoxB);
           this.listBoxB.Show();
           this.ResumeLayout(performLayout: false);
       }

       private void ListBox_MouseDown(object sender, MouseEventArgs e) {
           ListBox lb = (ListBox)sender;
           lb.DoDragDrop(lb, DragDropEffects.Move);
       }

       [DebuggerStepThrough()]
       protected override void Dispose(bool disposing) {
           if ((disposing)) {
               if ((this.listBoxB != null)) {
                   this.listBoxB.MouseDown -= ListBox_MouseDown;
                   this.listBoxB.Dispose();
                   this.listBoxB = null;
               }
           }
           base.Dispose(disposing);
       }

   }
}


Y por último, en el Form donde hayas colocado el panel, añadirías los siguientes controladores de evento para controlar el arrastre y el soltar/inserción del ListBox:
Código (csharp,13,14,15,18,19,20,21,22,23,24,25,26,28,29,30,31,32,33,34,35,36,37,39,40,41,42,43,44) [Seleccionar]
using System;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsFormsApplication1 {
   public partial class Form1 : Form {
       public Form1() {
           InitializeComponent();
       }

       private void Form1_Load(object sender, EventArgs e) {
           this.panel1.AllowDrop = true;
           this.panel1.DragEnter += this.Panel1_DragEnter;
           this.panel1.DragOver += this.Panel1_DragOver;
           this.panel1.DragDrop += this.Panel1_DragDrop;
       }

       private void Panel1_DragEnter(object sender, DragEventArgs e) {
           Control ctrl = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
           Panel pan = (Panel)sender;

           if (ctrl != null) {
               ctrl.Location = pan.PointToClient(new Point(e.X, e.Y));
               pan.Controls.Add(ctrl);
           }
       }

       private void Panel1_DragOver(object sender, DragEventArgs e) {
           Control ctrl = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
           Panel pan = (Panel)sender;

           if (ctrl != null) {
               ctrl.Location = pan.PointToClient(new Point(e.X, e.Y));
           }

           e.Effect = DragDropEffects.Move;
       }

       private void Panel1_DragDrop(object sender, DragEventArgs e) {
           Control ctrl = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
           if (ctrl != null) {
               // ...
           }
       }

   }
}


Nota: Una vez arrastrado el ListBox adentro del Panel, ten presente que el Panel se convertirá en el contenedor padre (parent) del ListBox.

¡Saludos!




EDITO: ¿Ralmente quieres arrastrar un ListBox en tiempo de ejecución, o más bien lo que quieres es arrastrar una etiqueta donde pone "ListBox" y que se genere un nuevo ListBox allá en donde hayas soltado esa etiqueta?, por que vaya, serían dos cosas complétamente distintas y hasta ahora tú has dicho "quiero arrastrar un ListBox" no "quiero arrastrar una etiqueta y que se cree un ListBox". Intenta dar DETALLES ESPECÍFICOS Y PRECISOS.








Nolohagan

#6
Hola Elektro,

este codigo... adonde va?

Código (csharp) [Seleccionar]

   using System;
   using System.ComponentModel;
   using System.Diagnostics;
   using System.Drawing;
   using System.Security.Permissions;
   using System.Windows.Forms;
   
   namespace WindowsFormsApplication1 {
   
       [DisplayName("MyTreeView")]
       [Description("A extended TreeView control.")]
       [DesignTimeVisible(true)]
       [DesignerCategory("UserControl")]
       [ToolboxBitmap(typeof(TreeView), "TreeView.bmp")]
       [ToolboxItem(true)]
       [ToolboxItemFilter("System.Windows.Forms", ToolboxItemFilterType.Require)]
       [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
       public class MyTreeView : TreeView, IDisposable {
   
           [Browsable(true)]
           [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
           [Category("Child Controls")]
           public ListBox ListBox { get { return this.listBoxB; } }
           private ListBox listBoxB; // Backing field.
   
           [DebuggerStepThrough()]
           public MyTreeView(){
               this.SuspendLayout();
               this.listBoxB = new ListBox();
               this.listBoxB.MouseDown += this.ListBox_MouseDown;
               this.Controls.Add(this.listBoxB);
               this.listBoxB.Show();
               this.ResumeLayout(performLayout: false);
           }
   
           private void ListBox_MouseDown(object sender, MouseEventArgs e) {
               ListBox lb = (ListBox)sender;
               lb.DoDragDrop(lb, DragDropEffects.Move);
           }
   
           [DebuggerStepThrough()]
           protected override void Dispose(bool disposing) {
               if ((disposing)) {
                   if ((this.listBoxB != null)) {
                       this.listBoxB.MouseDown -= ListBox_MouseDown;
                       this.listBoxB.Dispose();
                       this.listBoxB = null;
                   }
               }
               base.Dispose(disposing);
           }
   
       }
   }


Porque si le doy doble click al evento MouseDown el evento se me va Form1.cs*. Pero ese codigo, que es tuyo, no contiene un InitializeComponent como el Form1.cs*.

No entiendo.

Ah. Lo que queria hacer es arrastrar un Listbox desde el TreeView hasta el panel y que cuando se termino de arrastrar en el panel, que se genere un ListBox en el panel.

Tengo que aprender a explicarme mejor. Tienes razon


Gracias y saludos

Eleкtro

#7
Cita de: Nolohagan en  2 Abril 2017, 19:56 PMeste codigo... adonde va?

El código iría en un archivo de clase individual, "MyTreeView.cs" por ejemplo.

Cita de: Nolohagan en  2 Abril 2017, 19:56 PMese codigo, que es tuyo, no contiene un InitializeComponent como el Form1.cs*.

La clase "Form1.cs" contiene un método llamado InitializeComponent el cual no es más que un código de inicialización auto generadop por Visual Studio, ese método está en la clase Form1.Designer.cs.

La clase MyTreeView no es un Form, sino un control de usuario. Cuando compilas la clase MyTreeView (y solo cuando la hayas compilado) se agregará un nevo control al ToolBox de controles de VisualStudio, arriba del todo del ToolBox, donde podrás ver ese nuevo TreeView que has compilado.

Cita de: Nolohagan en  2 Abril 2017, 19:56 PMNo entiendo.

En Visual Studio puedes crear controles, puedes tomar como base el aspecto y el comportamiento de un TreeView y añadirle modificaciones (modificaciones estéticas, o de lo que sea), a esto se le llama Class Inheritance o Herencia de Clases.

Pues bien, la clase "MyTreeView" hereda de la clase System.Windows.Forms.TreeView, ¿por qué, cual es el propósito?, pues basicamente por que tu pregunta inicial fue "¿Cómo crear un TreeView que tenga un ListBox adentro?", y para ello hay que tomar como base un TreeView para añadirle un control de tipo ListBox adentro de su colección de controles...

...Pero ya no estoy seguro de que realmente eso es lo que quieres hacer. Siento decirlo y espero no ofender pero no te estás explicando nada bien, creo que ese código de la clase "MyTreeView" y las explicaciones que he estado dándote hasta ahora al final lo hice para nada por que creo que realmente no quieres crear un TreeView con un ListBox adentro, sino más bien un TreeView normal y corriente de toda la vida y simplemente añadirle un nodo con el texto "ListBox".




Cita de: Nolohagan en  2 Abril 2017, 19:56 PMLo que queria hacer es arrastrar un Listbox desde el TreeView hasta el panel y que cuando se termino de arrastrar en el panel, que se genere un ListBox en el panel.

Eso no concuerda con la imagen que pusiste:

Cita de: NoLoHagan

En ese TreeView no hay ningún control de tipo ListBox hablando literálmente, tan solo una etiqueta/nodo con el texto "ListBox".

Lo vuelvo a preguntar: ¿Realmente quieres arrastar un ListBox, o lo que quieres hacer es arrastrar una nodo del TreeView?.

Me la voy a jugar para decir que yo creo que lo que tú realmente quieres hacer no es arrastrar un ListBox como has estado diciendo hasta ahora, sino arrastrar etiquetas/nodos del Treeview, tal que así:



...Y que lo del ListBox lo has dicho por no saber explicar mejor lo que querías hacer.

Bien, pues si estoy en lo correcto entonces para llevar a cabo esa tarea se puede aprovechar parte del código que te enseñé arriba. Si eso es lo que realmente quieres hacer, entonces primero de todo elimina la clase "MyTreeView", por que entonces esa clase no te sirve para nada.

Este sería el código del Form, he dejado comentarios explicando el propósito de cada cosa:

Código (csharp) [Seleccionar]
// Los nodos hijos de controles.
static TreeNode[]  childControlNodes = {
   new TreeNode("Label") { Tag = typeof(Label) },
   new TreeNode("ListBox") { Tag = typeof(ListBox) },
   new TreeNode("ListView") { Tag = typeof(ListView) },
   new TreeNode("TextBox") { Tag = typeof(TextBox) }
};

// El nodo principal de controles.
static TreeNode controlsNode = new TreeNode("Controls", childControlNodes);

private void Form1_Load(object sender, EventArgs e)
{
   this.panel1.AllowDrop = true; // Permitir soltar objetos en el panel.
   this.treeView1.Nodes.Add(controlsNode); // Añadir el nodo de controles al TreeView.
   // Asociación de eventos en tiempo de ejecución:
   this.treeView1.MouseDown += this.TreeView1_MouseDown;
   this.panel1.DragEnter += this.Panel1_DragEnter;
   this.panel1.DragOver += this.Panel1_DragOver;
   this.panel1.DragDrop += this.Panel1_DragDrop;
}

private void TreeView1_MouseDown(object sender, MouseEventArgs e) {
 
   // Obtenemos el control TreeView que disparé este evento.
   TreeView tree = (TreeView)sender;

   // Asigname el nodo seleccionado, el nodo en el que hemos echo click.
   tree.SelectedNode = tree.GetNodeAt(e.Location);

   // Si el nodo no es nulo...
   if ((tree.SelectedNode != null)) {

       // Obtenemos una referencia del nodo.
       TreeNode node = tree.SelectedNode;

       // Si el nodo contiene un Tag...
       if (node.Tag != null)
       {
           // Determinamos el tipo de control del tag.
           Type t = (Type)node.Tag;
           // Creamos una instancia del tipo de control.
           Control ctrl = (Control)Activator.CreateInstance(t);
           ctrl.Text = node.Text;
           // Iniciamos la operación de arrastrar y soltar del control.
           DragDropEffects result = tree.DoDragDrop(ctrl, DragDropEffects.Move);
           // Si el control no se movió...
           if ((result == DragDropEffects.None))
           {
               // Liberamos los recursos del control.
               ctrl.Dispose();
               // Anulamos la referencia del control,
               // para que el recolector de basura (Garbage Collector) lo deseche cuanto antes.
               ctrl = null;
           }

       }

   }

}

private void Panel1_DragEnter(object sender, DragEventArgs e)
{
   Control ctrl = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
   Panel pan = (Panel)sender;
   if (ctrl != null)
   {
       ctrl.Location = pan.PointToClient(new Point(e.X, e.Y));
       pan.Controls.Add(ctrl);
   }
}

private void Panel1_DragOver(object sender, DragEventArgs e)
{
   Control ctrl = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
   Panel pan = (Panel)sender;
   if ((ctrl != null))
   {
       ctrl.Location = pan.PointToClient(new Point(e.X, e.Y));
   }
   e.Effect = DragDropEffects.Move;
}

// Cuando el control se soltó en el panel...
private void Panel1_DragDrop(object sender, DragEventArgs e)
{
   Control ctrl = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
   // ...
   if ((ctrl != null))
   {
       // ctrl.BackColor = Control.DefaultBackColor;
       ctrl.ForeColor = Control.DefaultForeColor;
   }
}


Te dejo aquí el proyecto en C# para que te sea todavía más facil:


¡Saludos!








Nolohagan

Citar
creo que ese código de la clase "MyTreeView" y las explicaciones que he estado dándote hasta
ahora al final lo hice para nada por que creo que realmente no quieres crear un TreeView con
un ListBox adentro

No, no. Todo lo que escribiste lo lei. No importa si no me servia. Lo lei aunque tengo que
que algunas cosas estan escritas complicadas aunque bueno; asi lo es.


Citar
En ese TreeView no hay ningún control de tipo ListBox hablando literálmente, tan solo una
etiqueta/nodo con el texto "ListBox".

Bueno. No sabia como hacer el control. El archivo que subiste a mediafire tampoco se le veria
un control si le sacases una foto nada mas.

Lo que yo queria era exactamente lo que hiciste. Muchisimas gracias!!

Por supuesto tengo muchisimas preguntas acerca del codigo. Pero como ya aportaste mucho y
hasta hiciste el trabajo que en realidad deberia haberlo hecho yo no quiero molestar mas.
Aunque los comentarios que incluiste en el codigo me son de mucha ayuda.
Pasa que es la primera vez que hago una cosa asi en visual studio.
Si realmente no encuentro respuesta a mis preguntas las publicare aca. De otro modo
muchas gracias por tu gran aporte :)

Eleкtro

Cita de: Nolohagan en  4 Abril 2017, 09:10 AM
Por supuesto tengo muchisimas preguntas acerca del codigo. Pero como ya aportaste mucho y
hasta hiciste el trabajo que en realidad deberia haberlo hecho yo no quiero molestar mas.
Aunque los comentarios que incluiste en el codigo me son de mucha ayuda.
Pasa que es la primera vez que hago una cosa asi en visual studio.
Si realmente no encuentro respuesta a mis preguntas las publicare aca. De otro modo
muchas gracias por tu gran aporte :)

Nadie molesta por hacer preguntas, el foro está para eso, y a mi ME ENCANTA poder ayudar a resolver las dudas de los demás y que vayan aprendiendo como hacer "X" cosa. Si tienes dudas, siéntete libre de preguntar.

¡Saludos!