Introducción a Windows Forms
Windows Forms es la tecnología tradicional de Microsoft para crear aplicaciones de escritorio con interfaz gráfica de usuario (GUI) en el ecosistema .NET. Aunque han surgido tecnologías más modernas como WPF y WinUI, Windows Forms sigue siendo ampliamente utilizado debido a su simplicidad, madurez y la gran cantidad de aplicaciones existentes que lo emplean.
Esta tecnología permite crear aplicaciones nativas para Windows con una interfaz rica e interactiva, utilizando un modelo de programación orientada a eventos. Windows Forms proporciona un conjunto completo de controles visuales, desde botones y cajas de texto hasta componentes más complejos como grillas de datos y menús, todos ellos totalmente integrados con el sistema operativo Windows.
En este artículo exploraremos los fundamentos de Windows Forms, desde la creación de un proyecto básico hasta la comprensión de los conceptos esenciales que necesitas dominar para desarrollar aplicaciones de escritorio efectivas.
Arquitectura y conceptos fundamentales
Modelo de aplicación Windows Forms
Windows Forms se basa en un modelo de programación orientada a eventos donde la aplicación responde a las acciones del usuario y del sistema. Esta arquitectura se compone de varios elementos fundamentales:
Componente | Descripción | Propósito |
---|---|---|
Application | Clase principal que gestiona el ciclo de vida de la aplicación | Controlar inicio, cierre y bucle de mensajes |
Form | Ventana principal o secundaria de la aplicación | Contenedor visual para controles y lógica de interfaz |
Controls | Elementos visuales interactivos (botones, etiquetas, etc.) | Permitir interacción del usuario con la aplicación |
Events | Mecanismo de comunicación basado en acciones | Responder a clicks, cambios de texto, etc. |
Designer | Herramienta visual para diseñar interfaces | Crear interfaces gráficamente sin escribir código |
El bucle de mensajes y eventos
Windows Forms utiliza el sistema de mensajes de Windows para manejar la comunicación entre la aplicación y el sistema operativo:
using System;
using System.Windows.Forms;
namespace IntroduccionWindowsForms
{
// Clase principal de la aplicación
static class Program
{
/// <summary>
/// Punto de entrada principal para la aplicación.
/// </summary>
[STAThread]
static void Main()
{
// Configuración de la aplicación
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Iniciar el bucle de mensajes con el formulario principal
Application.Run(new FormularioPrincipal());
}
}
// Ejemplo de manejo del bucle de mensajes personalizado
public partial class FormularioPrincipal : Form
{
public FormularioPrincipal()
{
InitializeComponent();
// Suscribirse a eventos del formulario
this.Load += FormularioPrincipal_Load;
this.FormClosing += FormularioPrincipal_FormClosing;
}
private void FormularioPrincipal_Load(object sender, EventArgs e)
{
Console.WriteLine("Formulario cargado y listo para interacción");
}
private void FormularioPrincipal_FormClosing(object sender, FormClosingEventArgs e)
{
// Confirmar cierre de aplicación
var resultado = MessageBox.Show(
"¿Está seguro que desea cerrar la aplicación?",
"Confirmar cierre",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (resultado == DialogResult.No)
{
e.Cancel = true; // Cancelar el cierre
}
}
}
}
Creación del primer proyecto Windows Forms
Configuración inicial del proyecto
Para crear un proyecto Windows Forms en .NET 8, podemos utilizar tanto Visual Studio como la línea de comandos. El proceso implica configurar correctamente las referencias y la estructura básica:
<!-- Archivo de proyecto (.csproj) para Windows Forms -->
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
</Project>
Estructura básica de un formulario
Un formulario en Windows Forms hereda de la clase Form
y puede crearse tanto por código como mediante el diseñador visual:
using System;
using System.Drawing;
using System.Windows.Forms;
public partial class MiPrimerFormulario : Form
{
// Componentes de la interfaz
private Button botonSaludar;
private TextBox cajaTexto;
private Label etiquetaResultado;
private MenuStrip menuPrincipal;
private StatusStrip barraEstado;
public MiPrimerFormulario()
{
InitializeComponent();
ConfigurarFormulario();
CrearControles();
ConfigurarEventos();
}
private void ConfigurarFormulario()
{
// Propiedades básicas del formulario
this.Text = "Mi Primera Aplicación Windows Forms";
this.Size = new Size(400, 300);
this.StartPosition = FormStartPosition.CenterScreen;
this.MinimumSize = new Size(300, 200);
this.MaximizeBox = true;
this.MinimizeBox = true;
this.FormBorderStyle = FormBorderStyle.Sizable;
// Configurar icono (si está disponible)
try
{
this.Icon = new Icon("icono.ico");
}
catch
{
// Icono no disponible, usar el predeterminado
}
}
private void CrearControles()
{
// Crear y configurar la caja de texto
cajaTexto = new TextBox
{
Location = new Point(20, 20),
Size = new Size(200, 23),
PlaceholderText = "Introduce tu nombre aquí...",
Font = new Font("Segoe UI", 9F)
};
// Crear y configurar el botón
botonSaludar = new Button
{
Location = new Point(230, 20),
Size = new Size(100, 25),
Text = "Saludar",
UseVisualStyleBackColor = true,
Font = new Font("Segoe UI", 9F)
};
// Crear y configurar la etiqueta de resultado
etiquetaResultado = new Label
{
Location = new Point(20, 60),
Size = new Size(300, 50),
Text = "Haz clic en 'Saludar' para ver el mensaje",
ForeColor = Color.Blue,
Font = new Font("Segoe UI", 10F, FontStyle.Italic),
AutoSize = false,
TextAlign = ContentAlignment.MiddleLeft
};
// Crear barra de menú
menuPrincipal = new MenuStrip();
CrearMenu();
// Crear barra de estado
barraEstado = new StatusStrip();
var etiquetaEstado = new ToolStripStatusLabel("Listo");
barraEstado.Items.Add(etiquetaEstado);
// Agregar controles al formulario
this.Controls.Add(cajaTexto);
this.Controls.Add(botonSaludar);
this.Controls.Add(etiquetaResultado);
this.Controls.Add(menuPrincipal);
this.Controls.Add(barraEstado);
// Configurar el menú y la barra de estado
this.MainMenuStrip = menuPrincipal;
}
private void CrearMenu()
{
// Menú Archivo
var menuArchivo = new ToolStripMenuItem("&Archivo");
menuArchivo.DropDownItems.Add("&Nuevo", null, MenuNuevo_Click);
menuArchivo.DropDownItems.Add("&Abrir", null, MenuAbrir_Click);
menuArchivo.DropDownItems.Add(new ToolStripSeparator());
menuArchivo.DropDownItems.Add("&Salir", null, MenuSalir_Click);
// Menú Ayuda
var menuAyuda = new ToolStripMenuItem("&Ayuda");
menuAyuda.DropDownItems.Add("&Acerca de...", null, MenuAcercaDe_Click);
menuPrincipal.Items.AddRange(new ToolStripMenuItem[] { menuArchivo, menuAyuda });
}
private void ConfigurarEventos()
{
// Evento del botón
botonSaludar.Click += BotonSaludar_Click;
// Evento de la caja de texto (Enter para activar)
cajaTexto.KeyPress += CajaTexto_KeyPress;
// Establecer el botón por defecto
this.AcceptButton = botonSaludar;
// Configurar el foco inicial
this.Load += (sender, e) => cajaTexto.Focus();
}
// Manejadores de eventos
private void BotonSaludar_Click(object sender, EventArgs e)
{
string nombre = cajaTexto.Text.Trim();
if (string.IsNullOrEmpty(nombre))
{
MessageBox.Show(
"Por favor, introduce tu nombre primero.",
"Campo requerido",
MessageBoxButtons.OK,
MessageBoxIcon.Warning);
cajaTexto.Focus();
return;
}
etiquetaResultado.Text = $"¡Hola, {nombre}! Bienvenido a Windows Forms.";
etiquetaResultado.ForeColor = Color.Green;
// Actualizar barra de estado
if (barraEstado.Items.Count > 0)
{
((ToolStripStatusLabel)barraEstado.Items[0]).Text =
$"Último saludo: {DateTime.Now:HH:mm:ss}";
}
}
private void CajaTexto_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar == (char)Keys.Enter)
{
e.Handled = true; // Evitar el sonido de error
BotonSaludar_Click(sender, EventArgs.Empty);
}
}
// Manejadores de eventos del menú
private void MenuNuevo_Click(object sender, EventArgs e)
{
cajaTexto.Clear();
etiquetaResultado.Text = "Haz clic en 'Saludar' para ver el mensaje";
etiquetaResultado.ForeColor = Color.Blue;
cajaTexto.Focus();
}
private void MenuAbrir_Click(object sender, EventArgs e)
{
using (var dialogo = new OpenFileDialog())
{
dialogo.Filter = "Archivos de texto|*.txt|Todos los archivos|*.*";
dialogo.Title = "Seleccionar archivo de texto";
if (dialogo.ShowDialog() == DialogResult.OK)
{
try
{
string contenido = System.IO.File.ReadAllText(dialogo.FileName);
MessageBox.Show($"Archivo cargado:\n{contenido.Substring(0, Math.Min(100, contenido.Length))}...",
"Contenido del archivo",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
catch (Exception ex)
{
MessageBox.Show($"Error al leer el archivo:\n{ex.Message}",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
}
}
private void MenuSalir_Click(object sender, EventArgs e)
{
this.Close();
}
private void MenuAcercaDe_Click(object sender, EventArgs e)
{
MessageBox.Show(
"Mi Primera Aplicación Windows Forms\n" +
"Versión 1.0\n\n" +
"Una demostración básica de Windows Forms en C#",
"Acerca de",
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
Controles básicos y sus propiedades
Catálogo de controles esenciales
Windows Forms proporciona una amplia gama de controles para diferentes propósitos. Aquí están los más utilizados organizados por categoría:
Categoría | Control | Propósito principal | Propiedades clave |
---|---|---|---|
Entrada | TextBox | Entrada de texto simple | Text, Multiline, PasswordChar |
RichTextBox | Entrada de texto con formato | Rtf, SelectionFont, SelectionColor | |
NumericUpDown | Entrada numérica con controles | Value, Minimum, Maximum | |
MaskedTextBox | Entrada con formato específico | Mask, ValidatingType | |
Selección | ComboBox | Lista desplegable de opciones | Items, SelectedItem, DropDownStyle |
ListBox | Lista de elementos seleccionables | Items, SelectedItems, SelectionMode | |
CheckBox | Opción booleana | Checked, ThreeState | |
RadioButton | Selección exclusiva | Checked, GroupBox para agrupación | |
Navegación | Button | Acción mediante click | Text, Image, FlatStyle |
MenuStrip | Menú principal de aplicación | Items, MdiWindowListItem | |
ToolStrip | Barra de herramientas | Items, GripStyle | |
TabControl | Pestañas de navegación | TabPages, SelectedTab | |
Visualización | Label | Mostrar texto estático | Text, AutoSize, TextAlign |
PictureBox | Mostrar imágenes | Image, SizeMode | |
ProgressBar | Indicador de progreso | Value, Maximum, Style | |
Contenedores | Panel | Agrupación visual de controles | BorderStyle, AutoScroll |
GroupBox | Agrupación lógica con borde | Text como título del grupo | |
SplitContainer | División ajustable del espacio | Orientation, SplitterDistance |
Ejemplo práctico con múltiples controles
public partial class FormularioCompleto : Form
{
// Controles de entrada
private TextBox txtNombre;
private TextBox txtApellidos;
private NumericUpDown nudEdad;
private ComboBox cmbPais;
private CheckBox chkNewsletterr;
private RadioButton rbMasculino, rbFemenino, rbOtro;
// Controles de visualización
private Label lblResultado;
private ProgressBar progressBar;
private PictureBox picAvatar;
// Controles de navegación
private Button btnGuardar;
private Button btnLimpiar;
private Button btnCancelar;
// Contenedores
private GroupBox grpDatosPersonales;
private GroupBox grpGenero;
private Panel pnlBotones;
public FormularioCompleto()
{
InitializeComponent();
CrearInterfazCompleta();
}
private void CrearInterfazCompleta()
{
// Configuración del formulario
this.Text = "Registro de Usuario - Demostración Completa";
this.Size = new Size(500, 450);
this.StartPosition = FormStartPosition.CenterScreen;
this.FormBorderStyle = FormBorderStyle.FixedDialog;
this.MaximizeBox = false;
CrearControles();
ConfigurarLayout();
ConfigurarEventos();
CargarDatosIniciales();
}
private void CrearControles()
{
// Grupo de datos personales
grpDatosPersonales = new GroupBox
{
Text = "Datos Personales",
Location = new Point(10, 10),
Size = new Size(460, 150)
};
// Campos de texto
var lblNombre = new Label { Text = "Nombre:", Location = new Point(15, 25), Size = new Size(60, 23) };
txtNombre = new TextBox { Location = new Point(80, 22), Size = new Size(150, 23) };
var lblApellidos = new Label { Text = "Apellidos:", Location = new Point(250, 25), Size = new Size(60, 23) };
txtApellidos = new TextBox { Location = new Point(315, 22), Size = new Size(130, 23) };
var lblEdad = new Label { Text = "Edad:", Location = new Point(15, 55), Size = new Size(60, 23) };
nudEdad = new NumericUpDown
{
Location = new Point(80, 52),
Size = new Size(60, 23),
Minimum = 0,
Maximum = 120,
Value = 18
};
var lblPais = new Label { Text = "País:", Location = new Point(160, 55), Size = new Size(40, 23) };
cmbPais = new ComboBox
{
Location = new Point(205, 52),
Size = new Size(120, 23),
DropDownStyle = ComboBoxStyle.DropDownList
};
chkNewsletterr = new CheckBox
{
Text = "Suscribirse al boletín de noticias",
Location = new Point(15, 85),
Size = new Size(250, 23)
};
// Avatar
picAvatar = new PictureBox
{
Location = new Point(350, 52),
Size = new Size(80, 80),
BorderStyle = BorderStyle.FixedSingle,
SizeMode = PictureBoxSizeMode.Zoom,
BackColor = Color.LightGray
};
// Agregar controles al grupo
grpDatosPersonales.Controls.AddRange(new Control[]
{
lblNombre, txtNombre, lblApellidos, txtApellidos,
lblEdad, nudEdad, lblPais, cmbPais, chkNewsletterr, picAvatar
});
// Grupo de género
grpGenero = new GroupBox
{
Text = "Género",
Location = new Point(10, 170),
Size = new Size(200, 90)
};
rbMasculino = new RadioButton { Text = "Masculino", Location = new Point(15, 25), Checked = true };
rbFemenino = new RadioButton { Text = "Femenino", Location = new Point(15, 45) };
rbOtro = new RadioButton { Text = "Otro/Prefiero no decir", Location = new Point(15, 65) };
grpGenero.Controls.AddRange(new RadioButton[] { rbMasculino, rbFemenino, rbOtro });
// Barra de progreso y etiqueta de resultado
lblResultado = new Label
{
Location = new Point(220, 180),
Size = new Size(250, 60),
Text = "Complete el formulario y presione 'Guardar'",
ForeColor = Color.Blue,
Font = new Font("Segoe UI", 9F, FontStyle.Italic)
};
progressBar = new ProgressBar
{
Location = new Point(220, 245),
Size = new Size(250, 15),
Style = ProgressBarStyle.Continuous
};
// Panel de botones
pnlBotones = new Panel
{
Location = new Point(10, 280),
Size = new Size(460, 50),
BorderStyle = BorderStyle.FixedSingle
};
btnGuardar = new Button
{
Text = "Guardar",
Location = new Point(10, 10),
Size = new Size(80, 30),
BackColor = Color.LightGreen
};
btnLimpiar = new Button
{
Text = "Limpiar",
Location = new Point(100, 10),
Size = new Size(80, 30),
BackColor = Color.LightYellow
};
btnCancelar = new Button
{
Text = "Cancelar",
Location = new Point(190, 10),
Size = new Size(80, 30),
BackColor = Color.LightCoral
};
pnlBotones.Controls.AddRange(new Button[] { btnGuardar, btnLimpiar, btnCancelar });
// Agregar controles principales al formulario
this.Controls.AddRange(new Control[]
{
grpDatosPersonales, grpGenero, lblResultado, progressBar, pnlBotones
});
}
private void ConfigurarLayout()
{
// Configurar anclajes para redimensionamiento (aunque esté deshabilitado)
grpDatosPersonales.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
pnlBotones.Anchor = AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
// Configurar orden de tabulación
txtNombre.TabIndex = 0;
txtApellidos.TabIndex = 1;
nudEdad.TabIndex = 2;
cmbPais.TabIndex = 3;
chkNewsletterr.TabIndex = 4;
rbMasculino.TabIndex = 5;
btnGuardar.TabIndex = 6;
// Establecer botón por defecto
this.AcceptButton = btnGuardar;
this.CancelButton = btnCancelar;
}
private void ConfigurarEventos()
{
// Eventos de botones
btnGuardar.Click += BtnGuardar_Click;
btnLimpiar.Click += BtnLimpiar_Click;
btnCancelar.Click += BtnCancelar_Click;
// Eventos de validación
txtNombre.TextChanged += ValidarFormulario;
txtApellidos.TextChanged += ValidarFormulario;
nudEdad.ValueChanged += ValidarFormulario;
cmbPais.SelectedIndexChanged += ValidarFormulario;
// Evento para seleccionar avatar
picAvatar.Click += PicAvatar_Click;
}
private void CargarDatosIniciales()
{
// Cargar países
string[] paises = { "España", "México", "Argentina", "Colombia", "Chile", "Perú", "Venezuela", "Uruguay" };
cmbPais.Items.AddRange(paises);
cmbPais.SelectedIndex = 0; // España por defecto
// Imagen por defecto para el avatar
CrearImagenAvatar();
ValidarFormulario(null, null);
}
private void CrearImagenAvatar()
{
// Crear una imagen simple por código
var bitmap = new Bitmap(80, 80);
using (var g = Graphics.FromImage(bitmap))
{
g.Clear(Color.LightBlue);
g.FillEllipse(Brushes.Gray, 10, 10, 60, 60);
g.DrawString("Avatar", new Font("Arial", 8), Brushes.White, 20, 35);
}
picAvatar.Image = bitmap;
}
private void ValidarFormulario(object sender, EventArgs e)
{
bool formularioValido = !string.IsNullOrWhiteSpace(txtNombre.Text) &&
!string.IsNullOrWhiteSpace(txtApellidos.Text) &&
cmbPais.SelectedItem != null;
btnGuardar.Enabled = formularioValido;
// Actualizar progreso
int progreso = 0;
if (!string.IsNullOrWhiteSpace(txtNombre.Text)) progreso += 25;
if (!string.IsNullOrWhiteSpace(txtApellidos.Text)) progreso += 25;
if (nudEdad.Value > 0) progreso += 25;
if (cmbPais.SelectedItem != null) progreso += 25;
progressBar.Value = progreso;
if (formularioValido)
{
lblResultado.Text = "Formulario listo para guardar";
lblResultado.ForeColor = Color.Green;
}
else
{
lblResultado.Text = "Complete todos los campos requeridos";
lblResultado.ForeColor = Color.Red;
}
}
private void BtnGuardar_Click(object sender, EventArgs e)
{
string genero = rbMasculino.Checked ? "Masculino" :
rbFemenino.Checked ? "Femenino" : "Otro";
string mensaje = $"Datos guardados:\n\n" +
$"Nombre: {txtNombre.Text} {txtApellidos.Text}\n" +
$"Edad: {nudEdad.Value} años\n" +
$"País: {cmbPais.SelectedItem}\n" +
$"Género: {genero}\n" +
$"Newsletter: {(chkNewsletterr.Checked ? "Sí" : "No")}";
MessageBox.Show(mensaje, "Registro Completado", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
private void BtnLimpiar_Click(object sender, EventArgs e)
{
txtNombre.Clear();
txtApellidos.Clear();
nudEdad.Value = 18;
cmbPais.SelectedIndex = 0;
chkNewsletterr.Checked = false;
rbMasculino.Checked = true;
txtNombre.Focus();
}
private void BtnCancelar_Click(object sender, EventArgs e)
{
this.Close();
}
private void PicAvatar_Click(object sender, EventArgs e)
{
using (var dialogo = new OpenFileDialog())
{
dialogo.Filter = "Archivos de imagen|*.jpg;*.jpeg;*.png;*.gif;*.bmp";
dialogo.Title = "Seleccionar avatar";
if (dialogo.ShowDialog() == DialogResult.OK)
{
try
{
picAvatar.Image = Image.FromFile(dialogo.FileName);
}
catch
{
MessageBox.Show("Error al cargar la imagen", "Error",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
}
}
}
Manejo de eventos esenciales
Tipos de eventos más utilizados
En Windows Forms, los eventos son el mecanismo principal de interacción. Los eventos más importantes se clasifican en varias categorías:
Categoría | Evento | Cuándo se produce | Uso típico |
---|---|---|---|
Mouse | Click | Click simple del mouse | Activar acciones principales |
DoubleClick | Doble click del mouse | Edición rápida o apertura | |
MouseEnter/MouseLeave | Mouse entra/sale del control | Efectos visuales, tooltips | |
MouseDown/MouseUp | Presionar/soltar botón del mouse | Arrastrar elementos | |
Teclado | KeyPress | Tecla presionada (carácter) | Validación de entrada |
KeyDown/KeyUp | Tecla presionada/liberada (cualquiera) | Atajos de teclado | |
Formulario | Load | Formulario se ha cargado | Inicialización |
FormClosing | Antes de cerrar el formulario | Validación antes del cierre | |
Resize | Tamaño del formulario cambia | Ajustar layout | |
Controles | TextChanged | Texto de un control cambia | Validación en tiempo real |
SelectedIndexChanged | Selección en lista cambia | Actualizar controles relacionados | |
CheckedChanged | Estado de checkbox cambia | Habilitar/deshabilitar opciones |
Implementación práctica de eventos
public partial class FormularioEventos : Form
{
private Button btnEjemplo;
private TextBox txtMonitoreo;
private Label lblEstado;
private ListBox lstEventos;
public FormularioEventos()
{
InitializeComponent();
CrearInterfazEventos();
ConfigurarEventosDetallados();
}
private void CrearInterfazEventos()
{
this.Text = "Demostración de Eventos en Windows Forms";
this.Size = new Size(600, 400);
// Botón para demostrar eventos del mouse
btnEjemplo = new Button
{
Text = "Botón de Ejemplo",
Location = new Point(20, 20),
Size = new Size(120, 40),
BackColor = Color.LightBlue
};
// TextBox para eventos de teclado
txtMonitoreo = new TextBox
{
Location = new Point(20, 80),
Size = new Size(200, 23),
PlaceholderText = "Escribe aquí para ver eventos..."
};
// Label para mostrar estado actual
lblEstado = new Label
{
Location = new Point(20, 120),
Size = new Size(400, 30),
Text = "Estado: Listo",
Font = new Font("Segoe UI", 10F, FontStyle.Bold),
ForeColor = Color.Blue
};
// ListBox para mostrar historial de eventos
lstEventos = new ListBox
{
Location = new Point(20, 160),
Size = new Size(540, 150),
Font = new Font("Consolas", 8F)
};
// Agregar controles al formulario
this.Controls.AddRange(new Control[] { btnEjemplo, txtMonitoreo, lblEstado, lstEventos });
}
private void ConfigurarEventosDetallados()
{
// Eventos del botón
btnEjemplo.Click += (s, e) => RegistrarEvento("Botón: Click");
btnEjemplo.DoubleClick += (s, e) => RegistrarEvento("Botón: DoubleClick");
btnEjemplo.MouseEnter += (s, e) =>
{
btnEjemplo.BackColor = Color.LightGreen;
lblEstado.Text = "Estado: Mouse sobre el botón";
RegistrarEvento("Botón: MouseEnter");
};
btnEjemplo.MouseLeave += (s, e) =>
{
btnEjemplo.BackColor = Color.LightBlue;
lblEstado.Text = "Estado: Listo";
RegistrarEvento("Botón: MouseLeave");
};
btnEjemplo.MouseDown += (s, e) =>
{
btnEjemplo.BackColor = Color.Orange;
RegistrarEvento($"Botón: MouseDown - {e.Button}");
};
btnEjemplo.MouseUp += (s, e) =>
{
btnEjemplo.BackColor = Color.LightGreen;
RegistrarEvento($"Botón: MouseUp - {e.Button}");
};
// Eventos del TextBox
txtMonitoreo.TextChanged += (s, e) =>
{
lblEstado.Text = $"Estado: Texto cambiado - Longitud: {txtMonitoreo.Text.Length}";
RegistrarEvento($"TextBox: TextChanged - '{txtMonitoreo.Text}'");
};
txtMonitoreo.KeyPress += (s, e) =>
{
RegistrarEvento($"TextBox: KeyPress - Carácter: '{e.KeyChar}' (ASCII: {(int)e.KeyChar})");
// Ejemplo: bloquear números
if (char.IsDigit(e.KeyChar) && !char.IsControl(e.KeyChar))
{
e.Handled = true; // Cancelar el carácter
RegistrarEvento("TextBox: Número bloqueado");
}
};
txtMonitoreo.KeyDown += (s, e) =>
{
RegistrarEvento($"TextBox: KeyDown - Tecla: {e.KeyCode}");
// Ejemplo: atajo de teclado Ctrl+A para seleccionar todo
if (e.Control && e.KeyCode == Keys.A)
{
txtMonitoreo.SelectAll();
RegistrarEvento("TextBox: Seleccionar todo (Ctrl+A)");
}
};
txtMonitoreo.Enter += (s, e) =>
{
txtMonitoreo.BackColor = Color.LightYellow;
RegistrarEvento("TextBox: Enter (foco obtenido)");
};
txtMonitoreo.Leave += (s, e) =>
{
txtMonitoreo.BackColor = SystemColors.Window;
RegistrarEvento("TextBox: Leave (foco perdido)");
};
// Eventos del formulario
this.Load += (s, e) => RegistrarEvento("Formulario: Load");
this.Activated += (s, e) => RegistrarEvento("Formulario: Activated");
this.Deactivate += (s, e) => RegistrarEvento("Formulario: Deactivate");
this.Resize += (s, e) => RegistrarEvento($"Formulario: Resize - {this.Size}");
// Evento de cierre con confirmación
this.FormClosing += (s, e) =>
{
RegistrarEvento("Formulario: FormClosing");
var resultado = MessageBox.Show(
"¿Desea cerrar la aplicación de demostración?",
"Confirmar cierre",
MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
if (resultado == DialogResult.No)
{
e.Cancel = true;
RegistrarEvento("Formulario: Cierre cancelado");
}
};
// Eventos globales del mouse en el formulario
this.MouseMove += (s, e) =>
{
lblEstado.Text = $"Estado: Mouse en ({e.X}, {e.Y})";
// No registrar MouseMove para evitar spam en el log
};
}
private void RegistrarEvento(string mensaje)
{
string timestamp = DateTime.Now.ToString("HH:mm:ss.fff");
string eventoCompleto = $"[{timestamp}] {mensaje}";
lstEventos.Items.Insert(0, eventoCompleto);
// Limitar a 100 elementos para evitar consumo excesivo de memoria
if (lstEventos.Items.Count > 100)
{
lstEventos.Items.RemoveAt(lstEventos.Items.Count - 1);
}
// Mostrar el evento más reciente
lstEventos.TopIndex = 0;
}
}