How to prevent text box from gaining focus unless clicked? - c#

I have a WinForms application that has a TextBox control (search box) at the top of it. This TextBox is constantly receiving focus during normal application use, and it is very distracting.
I would like the TextBox to only receive the focus if the user explicitly clicks on it.
I can think of a couple rather complicated ways to accomplish this:
Change an image of a text box into a text box when clicked
Keep track of mouse clicks and shift the focus away based on mouse state
Is there something simpler that I can do to accomplish this?
Edit to add better description of problem based on new understanding
Based on the answers that I have received, I now have a bit of a better understanding of what was causing this problem. As the user interacted with my application, various actions would cause controls to either be disabled or to completely disappear. If one of these controls happened to have the focus at the time, then the next control in the tab order would receive the focus.
I don't know what was the "next control" before I added the text box in question. The application has hundreds of controls on screen at any given time, and I'm pretty sure that tab order was never intentionally defined. Whatever it was before, it was innocuous. After adding the search text box, it seemed like that control would always end up with the focus.
Here is a very simple example that demonstrates what was happening:
public class Form1 : Form
{
public Form1()
{
var button = new Button
{
Location = new System.Drawing.Point(159, 67),
Size = new System.Drawing.Size(75, 23),
TabIndex = 0,
Text = #"Click me"
};
button.Click += (sender, args) => button.Enabled = false;
var textBox = new TextBox
{
Location = new System.Drawing.Point(159, 142),
Name = "textBox1",
Size = new System.Drawing.Size(174, 20),
TabIndex = 1
};
SuspendLayout();
ClientSize = new System.Drawing.Size(486, 392);
Controls.Add(textBox);
Controls.Add(_button);
ResumeLayout(false);
PerformLayout();
}
}
After starting the application, clicking on the button will force the text box to get the focus, since it is the next in the tab order. As mentioned by Handbag Crab in the accepted answer, this behavior can be avoided by setting TabStop = false on the text box.

textBox1.TabStop = false;
The above should stop it receiving focus from tabbing.

Subclass the TextBox and over WndProc function to capture the focus message and handle it. Maybe something like this:
if (m.Msg == WM_MOUSEACTIVATE) {
m.Result = (IntPtr)MA_NOACTIVATEANDEAT;
return;
}
base.WndProc(ref m);

Related

DevExpress textbox validation not working as desired

I have a text box which has the following requirements:
Can be Empty
If not empty must be exactly 9 numbers
I would like it so as soon as you type a character into the textbox a message appears saying this is invalid and that message will remain visible without disappearing as long as the validation doesn't pass even while the user is typing into the box. For Example I type 1 into the box and immediately the error appears, then while I type 2345678 the message stays visible even when losing focus on the editor. Then as soon as I add 9 the message disappears. I already have working logic for the validation I just can't seem to get the events to fire how I want. For example if I start typing into the field the error disappears until it loses focus and then it reappears. How to I make it stay even while typing?
Html.DevExpress().TextBox(tb =>
{
tb.Name = "tbAddressChangeDUNS";
tb.Width = Unit.Percentage(100);
tb.Properties.ClientSideEvents.KeyUp = "function(s, e) {s.Validate();}";
tb.Properties.ClientSideEvents.LostFocus = "function(s, e) {s.Validate();}";
tb.Properties.ClientSideEvents.Validation = #"function(s, e) {
var duns = e.value;
if(!duns)
return;
if(!IsValidDunsNumber(duns)) {
e.isValid = false;
e.errorText = 'Must be exactly 9 digits';
}
}";
}).Render();
According to my comments, there is a big hint below that should solve your problem :
You can manually trigger validation at any moment via the ASPxClientEdit.Validate Method. Handle the [ASPxClientTextEdit.TextChanged][1] Event of the text box editor to execute custom logic (e.g., trigger validation) when its text is changed. I hope this information will help you.
source : https://www.devexpress.com/Support/Center/Question/Details/Q572171/how-to-implement-custom-validation-on-text-boxes

Closing a form that was opened by ShowDialog()

I have a winform application where I've written my own little color picker that will only display system colours. It's basically a TableLayoutPanel with a bunch of smaller panels added to it, to which I just set the background color.
Pretty simple:
Now I'm opening this form for with:
using (frmColourWindow colourPicker = new frmColourWindow (Cursor.Position.X, Cursor.Position.Y, findingPriority))
{
colourPicker.ShowDialog();
if (!colourPicker.SelectedColor.IsEmpty)
{
pnlColor.BackColor = colourPicker._SelectedColor;
}
}
and closing it with by setting the DialogResult when the user has clicked on one of the color panels.
This all works pretty good, the only thing I can not manage to get right is by closing the form when it loses focus (E.g. when the user clicks somewhere else or starts typing). I've had a look at the Deactivate, LostFocus, and Leave events. Just can't seem to get those events to fire when I want them to. Maybe I'm missing something obvious?
As I mentioned in the comments, when using the ShowDialog() you can only use the Dialog you have opened and thus it never looses focus, so event like Deactivate, LostFocus and Leave won't work.
You need to use the Show() command to use those event to close the opened Form.
As to addressing the issue you pointed out in the comments about assigning the color to the object. you can do the following:
Declare a public Property
Color SelectedColor {get; private set; }
In your color picker and change your using statement to this:
var colourPicker = new frmColourWindow (Cursor.Position.X, Cursor.Position.Y, findingPriority);
colourPicker.Closed += (o, args) => { pnlColor.BackColor = colourPicker.SelectedColor };
colourPicker.Show();
This is of course just one of many possible solutions for that.
You can achieve this by displaying the form with the Show() method and then using the Form.Deactivate event.

Suspend updates to control Text property

I am implementing a QWERTY-style keyboard on a cheap touchscreen PC running (similar to a bank ATM). The Panel container has several dozen buttons and when the user presses "Shift", I swap all the text on the buttons. For example, btnPos12.Text = (m_bShiftOn) ? "Q" : "q"; in a big loop for all buttons on the Panel.
This works fine, but because the processor is not very powerful, there is significant flicker as all the button text changes. I'd like to suspend all text updates till they've all been done and then...bang!...change them all (aka double-buffering). I tried using this thread:
How do I suspend painting for a control and its children?
This works very well for single controls, such as a multi-line TextBox, but does not prevent each button's text from updating.
I then tried changing the text on a single button. First I suspended drawing on that button, and then changed the text in a big loop...but again the text changes each time btnPosXX.Text = ... is called. Is there any way to prevent changes to the "Text" property of a control?
int nShiftIndex = (m_bShiftOn) ? UPPER : LOWER;
for (int nButton = 0; nButton < pnlButtons.Controls.Count; nButton++)
{
pnlButtons.Controls[nButton].Text = m_aszKeys[nShiftIndex];
}
this.SuspendLayout();
...
this.ResumeLayout();

Control input via button

I made a Tic Tac Toe game and I'm trying to add a few features.
I was used to handle the taken buttons with
button.enabled=false;
The problems is that the text on the buttons turns grey.
So I made a button click for each button:
A1_Click, A2_Click, and so on
This is my code into A1_click, and it's the same for the other buttons, the only thing that changes is "A1", "A2", and so on
Button b = (Button)sender;
if (!A1.Text.Equals(""))
{
MessageBox.Show("Not A Valid Input");
}
I get "not a valid input" when I click a button I've already clicked before, I'd just like to be able to click an another button.
I don't want to lose my turn if I click on an already taken button
Based on what I have read I think I know what you are looking for. You are looking for a way to force the user to lose a turn when they click a button that has already been taken, and you do not want to set the enabled property to false. If that is what you want, then I might have some code that could help. First if you are assigning the same click event to multiple buttons with different functions you should try something like this:
for (int i = 1; i < 10; i++)
{
string currentButtonName = "A" + i;
Control currentButton = this.Controls.Find(currentButtonName, true).FirstOrDefault();
currentButton.Click += OnGameButton_Click;
}
What this is doing is searching your form for a control that has a specified name, and since your buttons have a similar name we can easily search for them. Then we can bind a specific function to all of them so that instead of 9 functions to modify you only have 1, and you can validate that they all work the same. Here is the OnGameButton_Click() event code:
private void OnGameButton_Click(object sender, EventArgs e)
{
if (!hasGameStarted || shouldLoseTurn)
return;
// This is the current button user pressed
Button b = (sender as Button);
if (b.Name.Contains('A') && b.Enabled)
{
if (!b.Text.Equals(""))
{
MessageBox.Show("Not A Valid Input! You have lost your turn.");
shouldLoseTurn = true;
}
else
{
b.Text = currentPlayersLetter;
shouldLoseTurn = false;
}
}
}
As you can see with some flags we can monitor the game, and force the buttons to react accordingly take a look at the beginning of the function. We have to validate that the game is engaged, and that the current user has not lost their turn due to pressing the same button. From there we just need modify what you had so that if they do press the same button twice then we modify the shouldLoseTurn flag as needed.
The other approach is to just simply use the Button.Enabled property to disable the button from use. I know you do not what the button to be grayed out, but if you create your own style guide for the button you could make it how you want. This can be challenging though because you will have to modify the default style template for the button to achieve this. Here is another question that discusses just that here

Suppress WaitCursor for WinForms WebBrowser control

Consider the following simple WinForms form with a textbox and a webbrowser control. Whenever the textbox content changes, the text is pushed to the browser:
public class MainForm : Form
{
public MainForm()
{
var browser = new WebBrowser() { Dock = DockStyle.Fill };
var textbox = new TextBox() { Dock = DockStyle.Fill, Multiline = true };
var splitter = new SplitContainer() { Dock = DockStyle.Fill };
splitter.Panel1.Controls.Add(textbox);
splitter.Panel2.Controls.Add(browser);
this.Controls.Add(splitter);
textbox.TextChanged += delegate { browser.DocumentText = textbox.Text; };
textbox.Text = "<b>hello world</b>";
}
}
(I am doing something like this in my DownMarker code to build a Markdown editor with Stackoverflow's MarkdownSharp library.)
This works fine, except that the WebBrowser control insists on showing the wait cursor whenever DocumentText is set - even if updating the browser content takes only a few milliseconds. This results in mouse cursor flicker when typing in the textbox.
Is there any way to supress these mouse cursor changes? I already considered rate-limiting the DocumentText updates, but I find that the occasional flicker during an update is still annoying and I would prefer instant updates.
edit: Hans' answer pointed me in the right direction. Changing the TextChanged event handler to this seems to work without cursor flicker:
textbox.TextChanged +=
delegate
{
if (browser.Document == null)
{
browser.DocumentText = "<html><body></body></html>";
}
while ((browser.Document == null)
|| (browser.Document.Body == null))
{
Application.DoEvents();
}
browser.Document.Body.InnerHtml = textbox.Text;
};
edit2: the above still shows the wait cursor when the page is made heavier, e.g. by adding images. This might be fixable be doing more fine grained updates of just the html elements that change, but that is obviously much more complex.
Assigning the DocumentText property is a Big Deal, WebBrowser treats it like a navigation command. It can't tell the difference. Which normally takes time, hundreds of milliseconds, enough for it to justify displaying the wait cursor.
A very different approach would be to load a dummy document and alter the DOM through the Document property. That's pretty common in web pages, Ajax and javascript and what-not. No wait cursor for those. Not so sure if that will still fit your editing model, I'd guess at you wanting to load a dummy HTML document with a empty <body> and change the body content.
Should work. Back-up plan is an Update! button. Which would also avoid trying to render half-finished and thus broken HTML.

Categories