How to find previous active control c# - c#

i am developing keyboard control, very simple embedded on a form. using sendkey class to perform char entry. to make this functional is required to know previous selected control.

Something like the following should do the trick:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace DragDropTest
{
public partial class LostFocusTestForm : Form
{
private Control _lastControl;
public LostFocusTestForm()
{
InitializeComponent();
TrapLostFocusOnChildControls(this.Controls);
}
private void finalTextBox_Enter(object sender, EventArgs e)
{
MessageBox.Show("From " + _lastControl.Name + " to " + this.ActiveControl.Name);
}
private void AllLostFocus(object sender, EventArgs e)
{
_lastControl = (Control)sender;
}
private void TrapLostFocusOnChildControls(Control.ControlCollection controls)
{
foreach (Control control in controls)
{
control.LostFocus += new EventHandler(AllLostFocus);
Control.ControlCollection childControls = control.Controls;
if (childControls != null)
TrapLostFocusOnChildControls(childControls);
}
}
}
}

Expanding on David's answer. This is how you can use the Enter event and a variable to store the last control:
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Control lastControlEntered = null;
public Form1()
{
InitializeComponent();
foreach (Control c in Controls)
if (!(c is Button)) c.Enter += new EventHandler(c_Enter);
}
void c_Enter(object sender, EventArgs e)
{
if (sender is Control)
lastControlEntered = (Control)sender;
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = lastControlEntered == null ? "No last control" : lastControlEntered.Name;
}
}
}
To run this code, add a few textboxes and other control to a Form in Visual Studio, and add a button and a label and attach the button's click handler to button1_Click. When you press the button, the last control you were in before pressing the button is displayed in the label. Edit this code to suit your needs.

You need to store it in a variable. For Control objects, there's "Enter" event

Another strategy is to use an Extension Method to extend Control.ControlCollection, and then using some indirection (a delegate) recursively parse the Controls collection of the Form adding a special "Enter" handler that updates a static variable. By keeping track of the previous Active Control and the current Active Control, you then have what you need ... if I understand your question fully. Here's an example that requires FrameWork 3.5 or 4.0.
// in a Public static class :
using System;
using System.Collections.Generic;
using System.Windows.Forms;
private static EventHandler _event;
// extension method on Control.ControlCollection
public static void SetEnterEvent(this Control.ControlCollection theCollection, EventHandler theEvent)
{
_event = theEvent;
recurseSetEnter(theCollection);
}
// recurse all the controls and add the Enter Event :
public static void recurseSetEnter(Control.ControlCollection aCollection)
{
foreach (Control theControl in aCollection)
{
// "weed out" things like internal controls of the NumericUpDown Control
// String.IsNullOrWhiteSpace is FrameWork 4.0
// use Trim() followed by String.IsNullOrEmpty for FrameWork 3.5
if (!String.IsNullOrWhiteSpace(theControl.Name))
{
Console.WriteLine("setting enter handler for : " + theControl.Name + " : " + theControl.GetType().ToString());
theControl.Enter += _event;
}
if (theControl.Controls.Count > 0) recurseSetEnter((Control.ControlCollection)theControl.Controls);
}
}
So how do we use this : in a Form :
First let's define an actual Event handler that is going to actually execute when the Enter event is encountered on any control :
We'll keep the current active control, and the previous active control, in public static variables :
public static Control theActiveControl = null;
public static Control thePreviousControl = null;
And here's the code that does the updating :
private void control_enter(object sender, EventArgs e)
{
thePreviousControl = theActiveControl;
theActiveControl = sender as Control;
Console.WriteLine("Active Control is now : " + theActiveControl.Name);
}
Now in the Form_Load event or elsewhere we just need to wire-up the events :
// in a Form**
// define a delegate for the enter Event
private event EventHandler enter = delegate { };
// in the form load even or somewhere : assign an actual event handler to the delegate
enter += new EventHandler(control_enter);
Finally we invoke the extension method on the Controls Collection of the Form :
this.Controls.SetEnterEvent(enter);
Discussion : a WinForm maintains an 'ActiveControl collection : this will contain a pointer to the most recently activated control no matter how deeply nested it is in one or more containers : ... some containers (like Panels) do not register as active controls in this collection even though they have Leave/Enter events ... controls are going to become the ActiveControl when they are used/selected/entered-into/focused-on, etc. Unfortunately there's no "ActiveControlChanged" event.
[edit] in practice I am developing this using"filters" so I can selectively skip over certain object types, or, for example, look for some "key" (in the control name or its tag) to determine whether or not to add the handler ... yes ... it's an experiment. [edit]
[edit] note that some controls like PictureBox expose no 'Enter event, but this code does not cause an error : my long-range goal is to find a way to test, without reflection, whether a particular control does expose a given 'event before I install one : since I consider it bad practice to just let things like PictureBox "wiggle through." So far I have not found the right "test" for "container-ness" ("is ControlContainer" turned out to be the wrong track). You may note also that Panels, for example, expose an 'Enter event, but it's only fired when some Control inside the Panel is activated. [edit]
Hope this is helpful. I am sure this could probably be written more elegantly using Lambdas, but as yet I am a "larva" feeding on the leaves of Skeet in that regard :)

You can do this by
string activeControl= this.ActiveControl.Name

You have to track this yourself. Write a trivial UIElement.LostFocus handler which puts the sender into a "last control with focus" variable, and you're done.
NOTE: WPF. Not sure if you're doing that or WinForms. I've been doing so much WPF lately I have it on the brain.

Related

button in c# not firing

I am writing a simple code it has 3 buttons 2 that will need to open up other forms and one to close the program. When i start the program the exit button will not work even though i have it coded the same as any other time i have wrote a program.
When i press any of the buttons nothing happens. Im not 100% sure how to use the buttons to open another form but i know the exit button should work as is.
Here is the code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace _3343_ParksJ_Lab02
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void workerButton_Click(object sender, EventArgs e)
{
WorkerForm workersForum = new WorkerForm();
}
private void suppervisorButton_Click(object sender, EventArgs e)
{
SupervisorForm workersForum = new SupervisorForm();
}
private void exitButton_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
You have to subscribe your buttons' click events to the event methods before they'll fire correctly.
You can check the Designer.cs file to see if this has already been done, though I'm guessing it hasn't. You'll be looking for something like this:
this.workerButton.Click += new System.EventHandler(this.workerButton_Click);
One way to do so is directly in the constructor:
public MainForm()
{
InitializeComponent();
workerButton.Click += workerButton_Click;
suppervisorButton.Click += suppervisorButton_Click;
exitButton.Click += exitButton_Click;
}
Normally, I'd do this through the designer. Select each Button in turn, then open the properties panel and double-click on the event you wish to subscribe to, which will create the corresponding event method in the code-behind for you.
Look at .Designer.cs file and make sure your button is adding the correct delegate method. In your case it should exitButton_Click.
Sometimes when you change names of a button VS designer does not make the name change correctly in the .Designer file. Very rare but it happens.

WPF Tab Control with Touch Not Working

I have a tab control that only responds to changing tabs with the mouse click.
Do I need to manually code in an event handler for tab control despite having the Surface SDK? Or is there a better control handler that I could use here?
I feel like this is entirely counter productive to the point of having the SDK. Especially because I plan on having a lot of different, unique tabs in my program and don't want to be handling each tab individually with nested ifs in a button_TouchDown function. I already have custom buttons that that have button_TouchDown setup and adding individual tab controls would be a headache and hell of a mess of code.
I tried searching but came up empty handed which makes me think that perhaps I am missing something and it should work. Is it because I have a predefined button_TouchDown function?
private void TabItem_TouchDown(object sender, TouchEventArgs e)
{
TabItem tab = sender as TabItem;
TabControl control = tab.Parent as TabControl;
control.SelectedItem = tab;
e.Handled = true;
}
XAML
<TabItem x:Name="hccontactTab" Header="Phone" TouchDown="TabItem_TouchDown">
Based on the above answer, but enhanced to account for scrolling per touch. Use a ClassHandler to handle this cleanly within your application (I use AutoFac's IStartable to auto-register it during building the container):
using System.Windows;
using System.Windows.Controls;
using Autofac;
namespace ...ClassHandlers
{
public class TabItemTouchClassHandler : IStartable
{
public void Start()
{
Register();
}
public void Register()
{
EventManager.RegisterClassHandler(typeof(TabItem), UIElement.TouchDownEvent, new RoutedEventHandler(OnTabItemTouchDown));
}
//must be static! otherwise memory leaks!
private static void OnTabItemTouchDown(object ender, routedEventArgs e)
{
var tab = sender as TabItem;
var control = tab?.Parent as TabControl;
if (control != null && !Equals(tab, control.SelectedItem))
{
control.SelectedItem = tab;
e.Handled = true;
}
}
}
}

c# main menu and mdi forms

So far in my life, as a .net developer, I have made heavy use of mdi forms to display particular "menu points" such as for instance "module 1" "module 2" and so on.
I have been doing this the following way:
create a parent form with "isMdiContainer" set to "true"
create a menu strip in in the mdi container
create a child form implementing singleton in order for the form to be shown only once
Add something like the following code to the mdi container:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Myapp
{
public partial class MdiContainer : Form
{
private module1 Module1Window;
private module2 Module2Window;
private module3 Module3Window;
public FormContainer()
{
InitializeComponent();
this.Module1Window = modul1.getInstance();
this.Module1Window.MdiParent = this;
this.Module2Window = modul2.getInstance();
this.Module2Window.MdiParent = this;
this.Module3Window = modul3.getInstance();
this.Module3Window.MdiParent = this;
this.Module1Window.Show();
}
private void module1ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Module3Window.Hide();
this.Module2Window.Hide();
this.Module1Window.Show();
}
private void module2ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Module1Window.Hide();
this.Module3Window.Hide();
this.Module2Window.Show();
}
private void module3ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.Module1Window.Hide();
this.Module2Window.Hide();
this.Module3Window.Show();
}
}
}
Now, this obviously works fine. But it is a a pain to maintain. Everytime I want to add another child form I have to:
implement Singleton
create the corresponding property in the mdi container
get the instance and set the mdi parent
Hide the new form when other buttons are clicked
Show the form and hide all other Forms when the corresponding button is clicked
Whats a more elegant or lets say efficient approach to archive this?
When do you create the menu items? Are these dynamically created along with the child forms?
If so what you can do is create the form and add it to a list and assign the menu item's Tag property to the form. Assign all the menu items click event to the same handler and within the handler do this...
private void menuStrip_Click(object sender, EventArgs e)
{
var menu = (ToolStripItem)sender;
var viewForm = (Form)sender.Tag;
foreach(Form childForm in _childForms)
childForm.Hide();
viewForm.Show();
}
This same handler can be used no matter how many forms you have.
Alternatively you can have a key as the Tag and have a Dictionary<string, Form> so you can more lazily create the forms, however the concept is the same.

Controls hide event's of form in C# Windows program

I had written an event handler for MouseMove for my form
but When I add a panel to form, this handler does NOT run while mouse moves on panel.
I added event handler to panel and this works but I had several panels on the form,
is there an easier solution?
Unfortunately, WinForms doesn't support event bubbling. But you can write some code to ease the task of hooking up events.
public void AssignMouseMoveEvent(Form form)
{
foreach(Control control in form.Controls)
{
if(! (control is Panel))
continue;
control.MouseMove += PanelMouseMove;
}
}
You should call the above code passing it your current form and it will assign PanelMouseMove as event handler for MouseMove event of all the panels.
I think you should be able to "propagate" the handlers, so you don't have to re-write the code in each one. Just remember that the MouseMove event has control-relative coordinates, so if you pass the event from your panel to your form, you'll have to translate the X & Y values in the event to the form coordinates (something like subtracting panel.location.X from event.X, etc).
This code worked for me (assumes you have a form with a panel and a label. The label is named "MouseCoords"
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void ShowCoords(int x, int y)
{
this.MouseCoords.Text = string.Format("({0}, {1})", x, y);
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
this.ShowCoords(e.X, e.Y);
}
protected override void OnControlAdded(ControlEventArgs e)
{
// hook the mouse move of any control that is added to the form
base.OnControlAdded(e);
e.Control.MouseMove += new MouseEventHandler(Control_MouseMove);
}
private void Control_MouseMove(object sender, MouseEventArgs e)
{
// convert the mouse coords from control codes to screen coords
// and then to form coords
System.Windows.Forms.Control ctrl = (System.Windows.Forms.Control)sender;
Point pt = this.PointToClient(ctrl.PointToScreen(e.Location));
this.ShowCoords(pt.X, pt.Y);
}
private void Form1_Load(object sender, EventArgs e)
{
this.MouseMove += this.Form1_MouseMove;
}
}
}
You could Implement IMessageFilter to pre-process messages that are going to your controls.
http://blogs.msdn.com/csharpfaq/archive/2004/10/20/245412.aspx
However, I don't think this is a very clean way to do things from a design perspective.
No there is no simpler way, and you should assign event handler for each control where you need to receive MouseMove events.
If you set the Capture property of the form to true, it will receive all mouse input, regardless of which control that is under the mouse. It will lose the mouse capture at certain operations (I am not sure exactly when, though). Also, according to the documentation for the property, shortcut keys should not work while the mouse is captured. So, depending on what you want to achieve, this might not be the preferred way to go.
Assuming that mouse starts moving over the form rather than over the panel - which is a big assumption - you'll get a MouseLeave event when it enters a sub control. You could check the cursor location and call the mouse move code if it's still within the bounds of the form.
This doesn't work if the mouse move event starts on a control.
I found another solution :) "Raise events in controls which hide events"
I catch the event in panel and rise the Mouse move event of the form by calling onMouseMove

Using a custom Button class instead of Forms.Button

I have create the class HoverButton which derives from Form.Button. Here I override the OnMouseEnter/OnMouseLeave events.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace DSLiteWizardLib
{
class HoverButton : Button
{
#region Constructor
public HoverButton()
{
InitializeComponent();
bMouseHover = false;
}
#endregion
#region Methods
private void OnMouseEnter(object sender, System.EventArgs e)
{
bMouseHover = true;
}
private void OnMouseLeave(object sender, System.EventArgs e)
{
bMouseHover = false;
}
private void InitializeComponent()
{
this.MouseEnter += new System.EventHandler(this.OnMouseEnter);
this.MouseLeave += new System.EventHandler(this.OnMouseLeave);
}
}
}
Eventually I want to pass an image for the hover state, pressed state, etc.
How can I get the button that is placed on my Form to use my HoverButton class instead of the standard Form.Button class?
If you're using a seperate assembly to store your control, you could right click the control toolbar and add an item for your assembly. You could then drag and drop your control just like any of the other builtin control.
If you're looking for something a little less elegant, you could go into the Designer.cs file and change the type of the button from Button to HoverButton there.
If you look in your toolbox in your Form Designer you should see the HoverButton that you created. (After a successful build of course.) You then drag it onto your form just like a regular button.
How to add and create a Usercontrol in Visual Studio 2008
NOTE: For the control to show in the toolbox automatically, make sure to set this option in VS:
Tools > Options > Windows Forms Designer > General : AutoToolboxPopulate

Categories