How to keep text box's focus when a window pops up - c#

i am building a virtual keyboard to suit the needs of the touch screen machine i'm going to be deploying on. i am using a popup window for the keyboard and have been able to wire all number buttons as follow, here's my virtual keyboard class
public partial class NumKeypad : Window
{
withoutB withoutbvn;
enterBvn ebvnn;
public NumKeypad()
{
InitializeComponent();
}
public NumKeypad(withoutB wobvn)
{
InitializeComponent();
withoutbvn = wobvn;
}
private void one_Click(object sender, RoutedEventArgs e)
{
var focusedElt = FocusManager.GetFocusedElement(withoutbvn);
var tbox = focusedElt as TextBox;
try
{
withoutbvn.ph.Text += (((sender as Button).Content as Border).Child as TextBlock).Text;//this works, but this is assigning directly to only one control. i want to assign to whatever control that has focus
}
catch (Exception ex)
{
}
}
}
on the first line of the one_click function(which handles all input button click) i'm trying to get a reference to the element currently focused in the page whose instance is "withoutbvn".
on the second line, i am tryin to convert the element to a text box so i can write to its text property. but that keeps returning null. meaning when this pop up windows come up(the keyboard pop up window comes up when a textbox or any other input element receives focus), i cannot get a reference to the focused textbox so i cannot write to it. Please how do i ensure a focused textbox remains focused so that i can assign its text property from a pop up window? Or if there's a better way to do this, pls point me in the right direction. Thanks

I've used this keyboard for WPF :
keyboard control wpf
It is a popup control which can be customized as you wish. You have the entire code and it's free. In my case I had to adjust the popup (layout and to add the German letters) and was pretty straightforward.
I also had to show a numeric keyboard, and I've used the same keyboard but with a simpler layout. Behind the scenes, all it is very simple: you have to define a key in a grid, place it where you want and make sure you generate on click the corresponding virtual key code.

i used the popup control to create the keyboard, used buttons to create all keys and wired a single event handler to all input buttons, then different event handlers for the backspace and enter buttons. once any letter, number or symbol button is clicked, the following function gets called.
try
{
IInputElement focusedControl = Keyboard.FocusedElement;
var foc = focusedControl as TextBox;
foc.Text += (((sender as Button).Content as Border).Child as TextBlock).Text;
}
catch (Exception)
{
}
that inserts the button's text to the control in focus. This is pretty basic. i'll appreciate more suggestion on how i can expand on this. Thanks

Related

C# set active form based on event, flashes form and sends to background - whats wrong?

i am writing an windows form (C#.NET) project which will run on a thinkpad tablet. I already wrote a custom textbox which triggers the tabtip keyboard on the device to help with onscreen input, however this is annoying since the user has to switch constantly between the different modes (numbers, text) and some other problems which i hope to eliminate by providing a custom form (keyboard)
which simulates an onscreen keyboard.
My Vision:
On the Mainform the user selects a textbox by clicking into it, my keyboard form displays, is the active form and obtains the focus. The user can use the keyboard-form to send numbers/text into the previous selected textbox which is on the mainform. If he switches the focus back to the mainform it will bring it to the front and the keyboard (to the back).
How I solved it:
My Keyboard form is a Singleton which contains a method to register Textboxes which should trigger the previous mentioned behavior. The form contains a variable which will hold the current (or last) selected Textbox, to accomplish this I register the textbox's OnFocus event and set the variable as needed.
//part of the full solution
public TextBox CurrentControlInFocus
{
get { return _inFocusControl; }
set
{
if (_inFocusControl != null && _inFocusControl != value)
{
//a new control is being selected
//so we should reset the color on the previous one
//to indicate to the user
//that it is not more the active control
_inFocusControl.BackColor = DefaultColor;
}
// do nothing
if (value == _inFocusControl) return;
_inFocusControl = value;
if (_inFocusControl != null)
{
//highlight the control to indicate
//to the user that this is the current
//active control
_inFocusControl.BackColor = FocusColor;
// activate the keyboard form.
Application.OpenForms[Name].Activate();
}
}
}
My Issue:
The keyboard is already displayed and sits behind the main form and i expected that the line
Application.OpenForms[Name].Activate();
is going to bring it to the front and and make that the active form which is in focus, but what happens is that the form Flashes, comes to the front and then returns back into his previous z-order behind the mainform.
Current Undesired Workaround:
IF i change the TopMost property to yes on the keyboard form the code works as expected, however this doesnt meet my criteria that the keyboard should move back in the z-order if the mainform retrieves the focus again.
At the moment i am clueless what else i can try or what i am missing.
[OPTIONAL] since the textbox on the mainform is not in focus (since the keyboard form is) the caret does not display and animate, is there any easier solution than creating a custom textbox with overriden paint event and drawing the caret manually in that particular scenario?
Try using
Application.OpenForms[Name].BringToFront()
edit:
My guess is that you can't give another form focus inside of a controls OnFocus event. This would be a easy thing to test, I would have done it but I don't have a C# env right now.
edit2:
From MSDN
Do not attempt to set focus from within the Enter, GotFocus, Leave, LostFocus, Validating, or Validated event handlers.
You could try using a BeginInvoke to set the focus, I think it would look something like
BeginInvoke((MethodInvoker)new delegate()
{ Application.OpenForms[Name].Activate(); });
Based on the suggestion of #BoldAsLove
I found a solution which works for me.
As he mentioned the MSDN article I was trying to switch focus out of the GotFocus event in a Textbox and it didn't work as expected.
However with a .BeginIvoke I was able to accomplish the focus switch from FormA to FormB.
public TextBox CurrentControlInFocus
{
get { return _inFocusControl; }
set
{
if (_inFocusControl != null && _inFocusControl != value)
{
_inFocusControl.BackColor = DefaultColor;
}
if (value == _inFocusControl) return;
_inFocusControl = value;
if (_inFocusControl != null)
{
_inFocusControl.BackColor = FocusColor;
#region Important block
var f = Application.OpenForms[Name] ?? Singleton;
// just making sure both handles are created before using an invoke
if (Handle != IntPtr.Zero && _inFocusControl.Handle != IntPtr.Zero)
//call the invoke on the textbox control
_inFocusControl.BeginInvoke((MethodInvoker) (() => {
f.Show(); //show the form
// bring it to front
// it also should raise the event Activated
f.Activate();
}));
#endregion
}
}
}
This is a pretty ugly way. I am pretty sure that usually a Button would trigger a scenario like this and I came across an exception / edge case. I needed to change focus to another form on a GotFocus event.

Textbox issue in windows phone 7?

In my app,I just have a page with four text boxes, so when i click a text box soft keyboard appears, now when i want to move to next textbox then i have to tap outside the textbox to make the keyboard disappear and then click on another text box. I don't think it is user friendly, so i have two options,
1)To change the functionality of return button(to make it work as tab).
2)To reduce the frame size and so scrolling will be enabled.
How can I do the foretold two options in windows phone 7??
for the first option
Make return key of the input panel work like tab key.
make key down event of 1st textbox like this
private void txt1_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
{
if (e.Key == System.Windows.Input.Key.Enter)
{
txt2.Focus();
}
}
similarly make this event for txt2 and txt3 and give focus accordingly and on on txt4 keydown event focus the main grid.
and about the 2nd way. Its a big problem in wp according to my knowledge.
For moving to next textbox #Amu 's answer will work perfect, and to dismiss the keyboard,
if (e.Key == System.Windows.Input.Key.Enter)
{
this.Focus();
}
That will take the focus away from your text box and will bring it to your screen.
And So keyboard will disappear!

Is there any way to detect a mouseclick outside a user control?

I'm creating a custom dropdown box, and I want to register when the mouse is clicked outside the dropdown box, in order to hide it. Is it possible to detect a click outside a control? or should I make some mechanism on the containing form and check for mouseclick when any dropdownbox is open?
So I finally understand that you only want it to close when the user clicks outside of it. In that case, the Leave event should work just fine... For some reason, I got the impression you wanted it to close whenever they moved the mouse outside of your custom dropdown. The Leave event is raised whenever your control loses the focus, and if the user clicks on something else, it will certainly lose focus as the thing they clicked on gains the focus.
The documentation also says that this event cascades up and down the control chain as necessary:
The Enter and Leave events are hierarchical and will cascade up and down the parent chain until the appropriate control is reached. For example, assume you have a Form with two GroupBox controls, and each GroupBox control has one TextBox control. When the caret is moved from one TextBox to the other, the Leave event is raised for the TextBox and GroupBox, and the Enter event is raised for the other GroupBox and TextBox.
Overriding your UserControl's OnLeave method is the best way to handle this:
protected override void OnLeave(EventArgs e)
{
// Call the base class
base.OnLeave(e);
// When this control loses the focus, close it
this.Hide();
}
And then for testing purposes, I created a form that shows the drop-down UserControl on command:
public partial class Form1 : Form
{
private UserControl1 customDropDown;
public Form1()
{
InitializeComponent();
// Create the user control
customDropDown = new UserControl1();
// Add it to the form's Controls collection
Controls.Add(customDropDown);
customDropDown.Hide();
}
private void button1_Click(object sender, EventArgs e)
{
// Display the user control
customDropDown.Show();
customDropDown.BringToFront(); // display in front of other controls
customDropDown.Select(); // make sure it gets the focus
}
}
Everything works perfectly with the above code, except for one thing: if the user clicks on a blank area of the form, the UserControl doesn't close. Hmm, why not? Well, because the form itself doesn't want the focus. Only controls can get the focus, and we didn't click on a control. And because nothing else stole the focus, the Leave event never got raised, meaning that the UserControl didn't know it was supposed to close itself.
If you need the UserControl to close itself when the user clicks on a blank area in the form, you need some special case handling for that. Since you say that you're only concerned about clicks, you can just handle the Click event for the form, and set the focus to a different control:
protected override void OnClick(EventArgs e)
{
// Call the base class
base.OnClick(e);
// See if our custom drop-down is visible
if (customDropDown.Visible)
{
// Set the focus to a different control on the form,
// which will force the drop-down to close
this.SelectNextControl(customDropDown, true, true, true, true);
}
}
Yes, this last part feels like a hack. The better solution, as others have mentioned, is to use the SetCapture function to instruct Windows to capture the mouse over your UserControl's window. The control's Capture property provides an even simpler way to do the same thing.
Technically, you'll need to p/invoke SetCapture() in order to receive click events that happen outside of your control.
But in your case, handling the Leave event, as #Martin suggests, should be sufficient.
EDIT: While looking for an usage example for SetCapture(), I came across the Control.Capture property, of which I was not aware. Using that property means you won't have to p/invoke anything, which is always a good thing in my book.
So, you'll have to set Capture to true when showing the dropdown, then determine if the mouse pointer lies inside the control in your click event handler and, if it doesn't, set Capture to false and close the dropdown.
UPDATE:
You can also use the Control.Focused property to determine if the control has got or lost focus when using a keyboard or mouse instead of using the Capture with the same example provided in the MSDN Capture page.
Handle the Form's MouseDown event, or override the Form's OnMouseDown
method:
enter code here
And then:
protected override void OnMouseDown(MouseEventArgs e)
{
if (!theListBox.Bounds.Contains(e.Location))
{
theListBox.Visible = false;
}
}
The Contains method old System.Drawing.Rectangle can be used to indicate if
a point is contained inside a rectangle. The Bounds property of a Control is
the outer Rectangle defined by the edges of the Control. The Location
property of the MouseEventArgs is the Point relative to the Control which
received the MouseDown event. The Bounds property of a Control in a Form is
relative to the Form.
You are probably looking for the leave event:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.leave.aspx
Leave occurs when the input focus leaves the control.
I just wanted to share this. It is probably not a good way of doing it that way, but looks like it works for drop down panel that closes on fake "MouseLeave", I tried to hide it on Panel MouseLeave but it does not work because moving from panel to button leaves the panel because the button is not the panel itself. Probably there is better way of doing this but I am sharing this because I used about 7 hours figuring out how to get it to work. Thanks to #FTheGodfather
But it works only if the mouse moves on the form. If there is a panel this will not work.
private void click_to_show_Panel_button_MouseDown(object sender, MouseEventArgs e)
{
item_panel1.Visible = true; //Menu Panel
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
if (!item_panel1.Bounds.Contains(e.Location))
{
item_panel1.Visible = false; // Menu panel
}
}
I've done this myself, and this is how I did it.
When the drop down is opened, register a click event on the control's parent form:
this.Form.Click += new EventHandler(CloseDropDown);
But this only takes you half the way. You probably want your drop down to close also when the current window gets deactivated. The most reliable way of detecting this has for me been through a timer that checks which window is currently active:
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
and
var timer = new Timer();
timer.Interval = 100;
timer.Tick += (sender, args) =>
{
IntPtr f = GetForegroundWindow();
if (this.Form == null || f != this.Form.Handle)
{
CloseDropDown();
}
};
You should of course only let the timer run when the drop down is visible. Also, there's probably a few other events on the parent form you'd want to register when the drop down is opened:
this.Form.LocationChanged += new EventHandler(CloseDropDown);
this.Form.SizeChanged += new EventHandler(CloseDropDown);
Just don't forget to unregister all these events in the CloseDropDown method :)
EDIT:
I forgot, you should also register the Leave event on you control to see if another control gets activated/clicked:
this.Leave += new EventHandler(CloseDropDown);
I think I've got it now, this should cover all bases. Let me know if I'm missing something.
If you have Form, you can simply use Deactivate event just like this :
protected override void OnDeactivate(EventArgs e)
{
this.Dispose();
}

UserControl Keyboard Focus

I got a form with a number of buttons on it (assume 20). In the middle, I got a User Control which is completely empty. The question is: how can I make it so that when the User Control is clicked, it will get keyboard focus?
Reason: I paint shapes in that User Control, with my mouse. The shapes are actually other User Controls. What I want to do is be able to use the keyboard to move those shapes. But I cannot seem to correctly be able to grab the Keyboard focus. The Key_Down events just don't reach my main (drawing into) User Control.
So, in other words, how can we have keyboard focus in a control has no focusable items on it? How can one make an keyboard-unfocusable control, catch those events? Any way of grabbing these events window-wide, other than going raw-WIN32 API hardcore?
A UserControl was very much designed to be a container control for other controls. It abhors getting the focus and tries to pass it off first chance it gets. You should not be using a UserControl here, given that you don't put any controls inside of it. A Panel control will suffice. Which has the exact same problem, it doesn't want to get focus either.
Surgery is required to override its behavior. Everything you need is in this answer.
Add this to your user control code to capture keyboard input:
/// <summary>Keys which can generate OnKeyDown event.</summary>
private static readonly Keys[] InputKeys = new []
{ Keys.Left, Keys.Up, Keys.Right, Keys.Down, };
protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
{
if(Array.IndexOf<Keys>(InputKeys, e.KeyCode) != -1)
{
e.IsInputKey = true;
}
base.OnPreviewKeyDown(e);
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
// just to illustrate this works
MessageBox.Show("KeyDown: " + e.KeyCode);
}
See http://msdn.microsoft.com/en-us/library/aa969768.aspx. You can assign keyboard focus by
1. Set the usercontrol.Focusable=true;
2. Use Keyboard.Focus(usercontrol).
You need to set the CommandRouting flag on your control to true.
The command routing dependency property is defined in a public API (MS.VS.Editor.dll) and your adornment will want to use that API to indicate that it is handling its commands instead of allowing the containing text view handle them. You can do this with from your control’s initialization.
Microsoft.VisualStudio.Editor.CommandRouting.SetInterceptsCommandRouting(this, true);

.NET UserControl accept button best practice?

I have a windows forms app where I have split different functionality into several user controls. I want each of these user controls to have an accept button.
Any best practices here?
My idèa is to detect which user control that has focus, and than set it in the parent Form.
Any other idèas?
The best practice is usually to only have one accept button for your form so that its behavior is consistent. It generally would be confusing for users if hitting return caused different actions depending on which section of the form had focus. However, if you have a specialized application or users have requested this feature then I think the solution you propose would work.
Jan Miksovsky has an excellent blog on UI design, and wrote an article about this very thing.
Most UI platforms allow a designer to
indicate which button in a dialog
should be the default button: the
button that will be pressed if the
user types the Enter key. The default
button is generally the button the
user is most likely to press next,
often a button like OK that closes the
dialog. In very high-traffic dialogs,
you may want to consider dynamically
changing the default button to save
keystrokes and help speed the user's
task.
The example he uses is the "Select Names" dialog in Microsoft Outlook, which changes the default button depending on what you are doing.
I assume each user button is its own instance on the individual user controls?
If so then you can trap the button events on the Parent form. If you expose the individual buttons through a property you can tie into their Click events. Like all controls they have a name property so you can have one method that is called on all button click events.
Below I have a partial sample code. I have two user controls that have one button each. The button on UC1 is named "btn1" and "btn2" for UC2. I call the exposed property "ButtonOK"
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public Button ButtonOK
{
get { return btn1; }
}
}
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
public Button ButtonOK
{
get { return btn2; }
}
}
Now on the parent ("Form1") when it loads have a mthod that ties into the Click events of each button but it calls the same method. Inside the method I test for the "Name" property.
public Form1()
{
InitializeComponent();
}
void Form1_Load(object sender, EventArgs e)
{
RegisterButtonEvents();
}
void RegisterButtonEvents()
{
userControl11.ButtonOK.Click += new EventHandler(ButtonOK_Click);
userControl21.ButtonOK.Click += new EventHandler(ButtonOK_Click);
}
void ButtonOK_Click(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn != null)
{
if (btn.Name == "btn1")
{
Console.WriteLine(" ButtonOK from UserControl1 was pushed. The tag is " + btn.Tag.ToString());
}
else if (btn.Name == "btn2")
{
Console.WriteLine(" ButtonOK from UserControl2 was pushed. The tag is " + btn.Tag.ToString());
}
}
}
You can also user the "Tag" property of a control. This property can be very useful as it can reference objects.
You don't need to do exactly as shown but you can use any "Parent" form to get a reference to the UserControls, have them expose their Buttons, then you can do anything you want with properties and events from those Buttons (or any control for that matter).
Keep in mind that if you are tying into the click event on the user control also (in addition to the parent form), you will have to be mindful of the order in which it will enumerate through it list of delegates and execute code after the event is intiated.
Hope that helps.
I know this is an old post, but I think I figured it out.
Use the "Enter" event on each user control from the main form, such that when the user "enters" (focuses on) the user control, this.AcceptButton = myUserControlButton. You can also use the "Leave" event on each user control to set the accept button back to the default, if you have one.
I'm not sure if I understood your question correctly.
If you want to assign one event to several buttons:
For this you could for instance:
- Get the button name on the Button_Click event.
- Enumerate between names
- Iterate over the controls.
Example bellow:
"How to get the button name from the Button_Click event".
// First; dont forget to assign the "Button_Click" event to your Button(s).
private void Button_Click(object sender, EventArgs e)
{
// The line bellow assigns to "btn" variable the currently clicked button.
Button btn = (Button)sender;
// Then using a switch block; you can compare the button name and
// perform the action desired for the clicked button.
switch(btn.Name)
{
case "buttonName1": /* Do Something Here */ break;
case "buttonName2": /* Do Something Here */ break;
// etc
}
}
Additionally; if you require; there's always the way to retrieve the Button outside the form class by exposing them.

Categories

Resources