Introducción
La idea de este articulo surge con la necesidad de implementar código común para los formulario.
El requerimiento apunta a que los formularios después de cierto tiempo deben deshabilitar sus controles.
Definición del Form Base
todo el truco en esta implementación esta en la definición del la clase Base, la cual será usada por todos los formularios de la aplicación para controlar las actividades.
[C#]
public class FormBase : Form { private Timer _timer; protected override void OnLoad(EventArgs e) { base.OnLoad(e); HandlerActitivy(this.Controls); _timer = new Timer(); _timer.Interval = 5000; //se establecen 5 seg _timer.Tick += new EventHandler(_timer_Tick); _timer.Start(); } void _timer_Tick(object sender, EventArgs e) { _timer.Stop(); DisableControls(); } public void Restart() { EnableControls(); _timer.Start(); } protected virtual void DisableControls() { } protected virtual void EnableControls() { } private void HandlerActitivy(Control.ControlCollection col) { foreach (Control ctrl in col) { if (ctrl is TextBox) { TextBox txt = ctrl as TextBox; txt.TextChanged += new EventHandler(txt_TextChanged); } if (ctrl is ComboBox) { ComboBox cmb = ctrl as ComboBox; cmb.SelectedIndexChanged += new EventHandler(cmb_SelectedIndexChanged); } if (ctrl is CheckBox) { CheckBox chk = ctrl as CheckBox; chk.CheckedChanged += new EventHandler(chk_CheckedChanged); } if (ctrl is GroupBox) { if (ctrl.HasChildren) { HandlerActitivy(ctrl.Controls); } } } } void chk_CheckedChanged(object sender, EventArgs e) { TimerRestart(); } void cmb_SelectedIndexChanged(object sender, EventArgs e) { TimerRestart(); } void txt_TextChanged(object sender, EventArgs e) { TimerRestart(); } private void TimerRestart() { _timer.Stop(); _timer.Start(); } }
[VB.NET]
Public Class FormBase Inherits Form Private _timer As Timer Protected Overloads Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) HandlerActitivy(Me.Controls) _timer = New Timer() _timer.Interval = 5000 'se establecen 5 seg AddHandler _timer.Tick, AddressOf _timer_Tick _timer.Start() End Sub Private Sub _timer_Tick(sender As Object, e As EventArgs) _timer.Stop() DisableControls() End Sub Public Sub Restart() EnableControls() _timer.Start() End Sub Protected Overridable Sub DisableControls() End Sub Protected Overridable Sub EnableControls() End Sub Private Sub HandlerActitivy(ByVal col As Control.ControlCollection) For Each ctrl As Control In col If TypeOf ctrl Is TextBox Then Dim txt As TextBox = TryCast(ctrl, TextBox) AddHandler txt.TextChanged, AddressOf txt_TextChanged End If If TypeOf ctrl Is ComboBox Then Dim cmb As ComboBox = TryCast(ctrl, ComboBox) AddHandler cmb.SelectedIndexChanged, AddressOf cmb_SelectedIndexChanged End If If TypeOf ctrl Is CheckBox Then Dim chk As CheckBox = TryCast(ctrl, CheckBox) AddHandler chk.CheckedChanged, AddressOf chk_CheckedChanged End If If TypeOf ctrl Is GroupBox Then If ctrl.HasChildren Then HandlerActitivy(ctrl.Controls) End If End If Next End Sub Private Sub chk_CheckedChanged(sender As Object, e As EventArgs) TimerRestart() End Sub Private Sub cmb_SelectedIndexChanged(sender As Object, e As EventArgs) TimerRestart() End Sub Private Sub txt_TextChanged(sender As Object, e As EventArgs) TimerRestart() End Sub Private Sub TimerRestart() _timer.Stop() _timer.Start() End Sub End Class
Los puntos a remarcar serian:
- Se define en esta clase un objeto timer que actuaria como controlador del tiempo transcurrido sin actividad.
- En el Load de formulario, el cual es tomado por la clase base al utilizar el OnLoad(), lo cual es posible ya que esta clase hereda de Form.
- En el Load se invoca un método de nombre HandlerActitivy(), cuya funcionalidad es tomar los controles definidos en el formulario y adjunta un evento estándar a cada control del formulario.
Este método si bien cubre el objetivo del ejemplo, puede que se necesite extender para controlar otros controles que pudieran usarse en el formulario.
Definición del formulario, usando la clase base
[C#]
public partial class Form1 : FormBase { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { } protected override void DisableControls() { txtNombre.Enabled = false; txtDireccion.Enabled = false; txtMail.Enabled = false; btnConfirmar.Enabled = false; confirmarToolStripMenuItem.Enabled = false; } protected override void EnableControls() { txtNombre.Enabled = true; txtDireccion.Enabled = true; txtMail.Enabled = true; btnConfirmar.Enabled = true; confirmarToolStripMenuItem.Enabled = true; } private void btnSalir_Click(object sender, EventArgs e) { this.Close(); } private void btnRestart_Click(object sender, EventArgs e) { base.Restart(); } private void restartToolStripMenuItem_Click(object sender, EventArgs e) { base.Restart(); } private void salirToolStripMenuItem_Click(object sender, EventArgs e) { this.Close(); } }
[VB.NET]
Public Partial Class Form1 Inherits FormBase Public Sub New() InitializeComponent() End Sub Private Sub Form1_Load(sender As Object, e As EventArgs) End Sub Protected Overloads Overrides Sub DisableControls() txtNombre.Enabled = False txtDireccion.Enabled = False txtMail.Enabled = False btnConfirmar.Enabled = False confirmarToolStripMenuItem.Enabled = False End Sub Protected Overloads Overrides Sub EnableControls() txtNombre.Enabled = True txtDireccion.Enabled = True txtMail.Enabled = True btnConfirmar.Enabled = True confirmarToolStripMenuItem.Enabled = True End Sub Private Sub btnSalir_Click(sender As Object, e As EventArgs) Me.Close() End Sub Private Sub btnRestart_Click(sender As Object, e As EventArgs) MyBase.Restart() End Sub Private Sub restartToolStripMenuItem_Click(sender As Object, e As EventArgs) MyBase.Restart() End Sub Private Sub salirToolStripMenuItem_Click(sender As Object, e As EventArgs) Me.Close() End Sub End Class
Los puntos a remarcar aquí podría ser
- En la definición del formulario no se hereda mas de Form, ahora se utiliza FormBase
- Se implementaron los método definidos como virtual en la clase base, DisableControls() y EnableControls(), estos métodos permites especificar concretamente que controles se deshabilitan cuando se vence el tiempo, y son invocados directamente desde FormBase.
Acerca del ejemplo
Cuando se abra por primera vez el código, si se realiza un doble clik en alguno de los formularios puede que el diseñador muestre un error, ya que requiere de la implementación de FormBase para poder resolver el diseño del formulario
Es por esto que lo primero que se debería hacer es compilar la solución, de esta formas e evita el problema que se comenta con el diseñador de los formularios
[C#] |
[VB.NET] |
Hola Leandro, como podría hacerse si el formulario principal ya esta heredando (Inherits) de otra clase y al mismo tiempo necesite implementar la técnica del control de tiempo por actividad?
ResponderEliminarhola bbionicss
ResponderEliminarPodrias hacer que el FormBase herede de la clase de actividad y luego tu form principal del formbase
o sea armarias una cascada de herencia:
public class FormControlActividad : Form
{
}
public class FormBase : FormControlActividad
{
}
public class FormPrincipal : FormBase
{
}
como veras es una cascada en dodne uno va heredando de otro, pero simpre el de mas abajo hereda de la clase Form
saludos
Una consulta amigo Leandro tu codigo es muy bueno pero el incoveniente es cuando la inactividad parece ser independiente por cada formulario en el caso de ser forms MDI quisiera que la inactividad se reinicie tanto del form padre como del form hijo cuando si hay actividad en uno de ellos no se si me explico graciassss de antemano
ResponderEliminarhola adruard
ResponderEliminarasi es la validacion de inactividad es por formulario, no es gobal a la aplicacion
el tema es que implementar algo como lo que planteras cambia completamente la situacion porque cada forma deberia informar de su inactividad y a la vez ser informado para reiniciar el conteo.
La verdad no se plantee algo asi, pero el problema lo veo en la comunicacion de los formularios, quizas se requiera alguna clase manejadora que interceda en el proceso.
saludos
Hola buenas tardes,
ResponderEliminarMe sirvió mucho el ejemplo y la explicación.
Saludos cordiales.
Hola Leandro,
ResponderEliminarSi tuviera codigo dentro de un evento de de mi FormBase y quiero agregarle más desde mi FormHeredado ??
EJ:
----Base---
protected virtual void Mensaje()
{
MessageBox.Show("Hola");
}
----Heredado---
protected override void Mensaje()
{
MessageBox.Show("Sergio");
}
=== Resultado ===
Hola
Sergio
hola
EliminarComo resultado solo verias el mensaje que dice "Sergio" ya que te esta faltanto la linea
base.Mensaje();
para invocar el metodo del form base
saludos
Muchas gracias Leandro, sos GRANDE...
EliminarFunciona bien, el problema es que quiero que si el usuario está inactivo durante x tiempo se le cierre la sesion o lo saque del aplicativo, si tengo mas de 2 formularios activos y estoy trabajando en uno solo, igual se me va a cerrar la sesion por que toma el tiempo para la otra ventana tambien... Hay alguna forma de controlar que no sea por formulario sino por proceso o por aplicativo?.
ResponderEliminarY otra cosa es que se me cierra el Visual Studio cuando heredo de la clase FormBase, solo me funciona la primera vez, es curioso.
saludos.