Is it possible to know who got the focus in a lost focus event?
Compact Framework does not have an ActiveControl, so I don't know how to tell who got the focus.
This is the solution that ended up working:
public System.Windows.Forms.Control FindFocusedControl()
{
return FindFocusedControl(this);
}
public static System.Windows.Forms.Control FindFocusedControl(System.Windows.Forms.Control container)
{
foreach (System.Windows.Forms.Control childControl in container.Controls)
{
if (childControl.Focused)
{
return childControl;
}
}
foreach (System.Windows.Forms.Control childControl in container.Controls)
{
System.Windows.Forms.Control maybeFocusedControl = FindFocusedControl(childControl);
if (maybeFocusedControl != null)
{
return maybeFocusedControl;
}
}
return null; // Couldn't find any, darn!
}
One option would be to interop the GetFocus API
[DllImport("coredll.dll, EntryPoint="GetFocus")]
public extern static IntPtr GetFocus();
This will give you the handle to the window that currently has input focus, you can then recursively iterate the control tree to find the control with that handle.
Using the corell.dll looks like a good idea.
Another possible way is to create GotFocus event handlers for all the controls on your form Then create a class level variable that updates with the name of the control that has the current focus.
No. first comes the LostFocus-event of one control then comes the GotFocus-event of the next control. as long as you can not figure out which control the user uses in the next moment, it is not possible.
whereas if the compact framework control does have a TabIndex-property it could be predicted only if the user uses the tab-key.
Edit:
OK You posted the solution and it works fine I must admit: the simple "No" is wrong
+1
This is a shorter code for the Vaccano's answer, using Linq
private static Control FindFocusedControl(Control container)
{
foreach (Control childControl in container.Controls.Cast<Control>().Where(childControl => childControl.Focused)) return childControl;
return (from Control childControl in container.Controls select FindFocusedControl(childControl)).FirstOrDefault(maybeFocusedControl => maybeFocusedControl != null);
}
Exactly the same (in high-level, abstraction).
Related
I have a user control that is dynamically loaded in the the page load:
protected void Page_Load(object sender, EventArgs e)
{
MyControl ctl = (MyControl)LoadControl(controlPath);
ctl.ID = "mycontrol";
this.MyControlPlaceHolder.Controls.Add(ctl);
}
Front End of the Page:
<asp:PlaceHolder runat="server" ID="MyControlPlaceHolder"></asp:PlaceHolder>
I have an click event on the page that initiates and postback and calls a method where I'm trying to find the control and set some properties:
MyControl ctl = (MyControl)FindControl("mycontrol");
if (ctl != null){
ctl.MyProperty = true;
Response.Write("success");
}
else
Response.Write("fail");
This is writing fail after the postback, so it seems like I'm doing something incorrectly in finding the control. What is the best way to do this?
EDIT:
I switched it to MyControl ctl = (MyControl)this.MyControlPlaceHolder.FindControl("mycontrol");
This made it so it was finding the control, however, when the control loads after the postback, it appears as though the property is not set.
You have to use a recursive FindControl implementation because FindControl will only find direct childs. Your control is inserted in a naming container at a lower level. A generic FindControlRecurisve from MSDN:
private Control FindControlRecursive(Control rootControl, string controlID)
{
if (rootControl.ID == controlID) return rootControl;
foreach (Control controlToSearch in rootControl.Controls)
{
Control controlToReturn =
FindControlRecursive(controlToSearch, controlID);
if (controlToReturn != null) return controlToReturn;
}
return null;
}
from MSDN
Or, if you only have one specific conatiner like in your sample:
MyControl ctl = this.MyControlPlaceHolder.FindControl("mycontrol");
if (ctl != null){
ctl.MyProperty = true;
Response.Write("success");
}
else
Response.Write("fail");
ViewState enable your control
public class MyControl:Control
{
public bool MyProperty
{
get
{
return ViewState["my"] != null? (bool) ViewState["my"]: false;
}
set
{
ViewState["my"] = value;
}
}
}
Try moving the code to dynamically add the control into Init instead of load. I can't be sure but there are a lot of things that happen between Init and Load and if your control is not present and accounted for it may cause issues like this.
You added the Control in the controls collection of a placeholder.
Apart of what control is your dynamically created control, if you want to looking for your dynamically added control in that way you have to do a recursive search starting from the root (maybe the page), so, if you surf over the net, you could find good solutions for that.
Personally I prefer solutions with: generics support and expressed as extension methods, so you could use the solution everywhere. These are some usefull links
Recursive Find Control with generics
Recursive Find Control with generics by extension method
Recursive Find Control with generics by extension method and linq support/example
hope this helps
I have a TabControl that contains several tabs. Each tab has one UserControl on it. I would like to check the visibility of a control x on UserControl A from UserControl B. I figured that doing x.Visible from UserControl B would be good enough. As it turns out, it was displaying false in the debugger even though I set it explicitly to true and it was never changed. Then I read on MSDN for Control.Visible that:
Even if Visible is set to true, the control might not be visible to the user if it is obscured behind other controls.
So much to my surprise, that will not work. Now I'm wondering how I can tell if the control x is visible from a different UserControl. I would like to avoid using a boolean if possible. Has anyone run into this and found a solution?
Note: It also appears that Control.IsAccessible is false in this situation.
Unfortunately the control doesn't provide anything public that will allow you to check this.
One possibility would be to set something in the controls 'Tag' property. The tag’s purpose is to associate user data with the control. So it can be anything not just a boolean.
Here is the Tag property doc
If you really want the brute force way, you can use Reflection, basically calling GetState(2):
public static bool WouldBeVisible(Control ctl)
{
// Returns true if the control would be visible if container is visible
MethodInfo mi = ctl.GetType().GetMethod("GetState", BindingFlags.Instance | BindingFlags.NonPublic);
if (mi == null) return ctl.Visible;
return (bool)(mi.Invoke(ctl, new object[] { 2 }));
}
Please try this:
bool ControlIsReallyVisible(Control C)
{
if (C.Parent == null) return C.Visible;
else return (C.Visible && ControlIsReallyVisible(C.Parent));
}
I'm using this code not only checking all the ancestors visible and also who is the root control. Checking a root is needed when the control is not added on the Mainform.
public static class StratoControlExtension
{
public static bool TruelyVisible(this Control control, Control expected_root)
{
if (control.Parent == null) { return control == expected_root && control.Visible; }
return control.Parent.TruelyVisible(expected_root) && control.Visible;
}
}
I have a form MainForm which is a Windows Forms form that contains many child controls. I want to call one function on MainForm that notifies all of its children. Does the Windows Forms form provide a means to do this? I played with update, refresh and invalidate with no success.
foreach (Control ctrl in this.Controls)
{
// call whatever you want on ctrl
}
If you want access to all controls on the form, and also all the controls on each control on the form (and so on, recursively), use a function like this:
public void DoSomething(Control.ControlCollection controls)
{
foreach (Control ctrl in controls)
{
// do something to ctrl
MessageBox.Show(ctrl.Name);
// recurse through all child controls
DoSomething(ctrl.Controls);
}
}
... which you call by initially passing in the form's Controls collection, like this:
DoSomething(this.Controls);
The answer from MusiGenesis is elegant, (typical in a good way), nice and clean.
But just to offer an alternative using lambda expressions and an 'Action' for a different type of recursion:
Action<Control> traverse = null;
//in a function:
traverse = (ctrl) =>
{
ctrl.Enabled = false; //or whatever action you're performing
traverse = (ctrl2) => ctrl.Controls.GetEnumerator();
};
//kick off the recursion:
traverse(rootControl);
No, there isn't. You must roll out your own.
On a side note - WPF has "routed events" which is exactly this and more.
You are going to need a recursive method to do this (as below), because controls can have children.
void NotifyChildren( control parent )
{
if ( parent == null ) return;
parent.notify();
foreach( control child in parent.children )
{
NotifyChildren( child );
}
}
I have a dynamically created (runtime creation) textbox whose name is available as a string.What i want to do is access this textbox like we do as normal textboxes .Can any one tell me how to cast it as textbox or any other solution
If you know the name of the textbox and its parent controls, you can do like this:
TextBox tb = (TextBox )parent.Controls["name"];
In addition to Iordan's answer, if you don't know exactly where on your form the textbox is, then this extension method should help alot. Note, Form's inherit from Control somewhere down the track too, so you can call it from that, or any control on your form.
public static class ExtensionMethods
{
public static Control FindControl(this Control root, string name)
{
foreach (Control c in root.Controls)
{
// Check this control
if (c.Name == name) return c;
// Check this controls subcontrols
Control tmp = c.FindControl(name);
if (tmp != null) return tmp;
}
return null;
}
}
If this still isn't flexible enough for you, then you can iterate over System.Windows.Forms.Application.OpenForms
Since you seem to have control over the creation process, put a reference to it in a dictionary.
TextBox txt = DynamicCreate(name);
map[name] = txt;
this.Controls.Add(txt);
All you have to do is look it up in your dictionary, instead of loop through all the controls on the form.
TextBox txt = map["name"];
HEllo, I need to dynamically activate fields in a page according to the service that is going to be executed...
Let me explain:
There's a page with all the possible fields and a ListBox with all the selected services to be executed, then when the user selects which service to execute (change a car plate, for example), then I need to activate only the field(s) that the service require... (The realationship between Services and Fields are stored in a database).
public void CheckAll(int pService_Id, Control pPage)
{
foreach (Control control in pPage.Controls)
{
busExecutaServico vExecuta = new busExecutaServico();
if (vExecuta.EnableField(control.ID.ToString(), Convert.ToInt32(listBoxServices.SelectedValue)))
{
switch (control.GetType().ToString())
{
case "TextBox":
TextBox controleText = (TextBox)Page.FindControl(control.ID.ToString());
controleText.Enabled = true;
break;
Note that busExecutaServico is the class which contains the method (EnableField) for checking if the selected item matches any field on the database..
I can't seem to get the control.ID.ToString() to work properly (the ID always comes as NULL)
If anyone can help me solve this, or if there's another way (even if it's completely different from what i'm trying), it would be of great help. thanks
I like to use a recursive function for locating controls by either type or ID.
public Control FindControlRecursive(Control rootControl, string controlId)
{
if (rootControl.ID == controlId)
return rootControl;
foreach (Control control in rootControl.Controls)
{
Control foundControl = FindControlRecursive(control, controlId);
if (foundControl != null)
{
return foundControl;
}
}
return null;
}
public Control FindControlRecursive(Control rootControl, Type type)
{
if (rootControl.GetType().Equals(type))
return rootControl;
foreach (Control control in rootControl.Controls)
{
Control foundControl = FindControlRecursive(control, type);
if (foundControl != null)
{
return foundControl;
}
}
return null;
}
You can adapt these to first return a collection of controls, then process them later. Might be easier to keep track of what's happening.
I learned this technique here: http://www.west-wind.com/Weblog/posts/5127.aspx
Be aware that FindControl only searches the current naming container so Page.FindControl will only find controls that are added directly to Page. For example, if you had a repeater control that had the controls you were looking for and it was added to Page, you could find your repeater control via Page.FindControl but it wouldn't find child controls within your repeater, you'd have to recursively perform the FindControl on all container controls in the page.
This might seem a bit strange but it allows you to have controls with the same ID existing on the same page. For example, if you had 10 instances of a user control with textboxes within them called "MyName", you'd really want them to not being over-writing each other's 'MyName' fields!
Your code will come across a null for an ID unless every control has been given an ID.
Also why use:-
TextBox controleText = (TextBox)Page.FindControl(control.ID.ToString());
at all instead of:-
TextBox controleText = (TextBox)control;
and indeed since you only want to change the Enabled property consider:-
((WebControl)control).Enabled = False;
That I suspect will eliminate many case statements.
In your code you don't need to search any control - you already have it in 'control' variable. You even don't need to cast it to TextBox, just to a WebControl, just do this:
...
if (vExecuta.EnableField(control.ID.ToString(), Convert.ToInt32(listBoxServices.SelectedValue)))
((WebControl)control).Enabled = true;
P.S. control.ID is already string, so you should remove any ID.ToString() also.