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();
Related
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);
I have written a custom OnScreen Keyboard as an UserControl to have a better control over what the user can type (Alphanumeric/Numpad/Navigation Keys - stuff like that) and to have a better control over the screen layout at design time.
The OSK works by manipulating the text- and selection-properties/functions of a textbox-control.
My main Problem is how to find the right TextBox to inject text into.
My first, naive approach was to register every TextBox I want to use with the OSK Control manually and use the GotFocus/LostFocus of those registered TextBoxes to determine the active control:
public void RegisterInput(TextBox text) {
if (!_listeners.ContainsKey(text)) {
_listeners.Add(text, modes);
text.GotFocus += Input_OnGotFocus;
text.LostFocus += Input_OnLostFocus;
}
}
private void Input_OnLostFocus(object sender, RoutedEventArgs routedEventArgs) {
if (_focused == sender) {
_focused = null;
IsEnabled = false;
UpdateKeyboardMode(); // << Updates Keyboard layout (Alphanumerical vs Numpad) based on focused control
}
}
private void Input_OnGotFocus(object sender, RoutedEventArgs routedEventArgs) {
_focused = (TextBox) sender;
IsEnabled = true;
UpdateKeyboardMode();
Bindings.Update();
}
I work with Focus here, because I need to determine which kind of keyboard (full-size alphanumerical vs. short numpad) to display for each TextBox. The _focused TextBox is then used to directly inject the pressed keys into it. In the constructor of my Page which also contains the OSK-control I would call RegisterInput() with a reference of each and every TextBox I defined on the page. This works just fine — if I have those references.
But now I am working with UserControls. That also removes the TextBoxes out of reach for direct referencing, but I could write some kind of VisualTree-Scan after InitializeComponent() to find all references and call RegisterInput() on each reference I found. If I only need to do this once, it isn't a problem (altough it is still ugly).
One step further - ListBoxes with dynamicly changing contents and DataTemplates. Now I'd need to rescan the whole VisualTree explicitly everytime something changes. But how to detect those changes?
The question is: Can I get an event as soon as $any element in my VisualTree gets/looses focus, without knowing all those elements beforehand (thus replacing RegisterInput() completely)? Or can I listen to changes to the VisualTree to rescan all controls and then call RegisterInput() manually for every TextBox I found?
The goal is to get a handler called everytime a GetFocus/LostFocus event on any TextBox/Control in the UI is raised so that I can update the keyboard to either display a full-sized alphanumerical keyboard (for default textboxes) or a shortened numpad (e.g. for textboxes bound to numerical backing fields).
Alternatively: Is there any other way to inject text and call UpdateKeyboardMode() to update the keyboard layout as soon as the selected textbox changes?
Other options I thought about include:
Build a custom control which derives from a TextBox and let it register itself to the OSK. I'll probably resort to this method, if I don't find any better way. But this will destroy support for 3rd party libraries in which my control is not present and thus does not use the "special magical textbox with osk support".
Don't use events at all. Get the currently focused TextBox with the FocusManager as soon as the user presses a key on my OSK and inject text into the focused instance. Problem with this approach is, that it completely destroys the capability to adapt the OSK to different input types (alphanumerical vs only Numpad), because I cannot determine the keyboard type I need before pressing a key.
Rescan the VisualTree with a timer. Won't do that, thats simply too much of a hack.
Use the OnScreen-Keyboard supplied by Win10 IoT. Two problems: It has no designtime support and is displayed above elements, even if the focused element is directly underneath the keyboard (acceptable if neccessary), but I don't know of a way to change the keyboard "layout" between a full-sized alphanumeric keyboard and a shortened Numpad which only contains numbers and some keys. Also it does not allow to use custom keys (e.g. arrow keys for navigation, custom return key handling).
After a discussion in the chat forum, the actual problem isn't to create a Custom OSK control and use that to interact with the TextBoxs but instead, it's "being bound to use custom control" wrapping a textbox everywhere a OSK needs to be shown.
The Solution would be to listen to the OS-OSK events and when they are triggered, pop up the Custom OSK this ways you won't have to wrap a Textbox in a user control and use that throughout your project.
Link to the Documentation: - respond to the presence of the touch keyboard
I have a C# winform which displays snapshots from a camera. The form has four PictureBox controls and When an image is taken it is placed into pictureBox1 and the previous images are bumped along to 2,3 and 4. Under each picture box is also a label which displays the time stamp and the order number (each image is given a number 1-4, that stays with it until it is bumped off in which the newest image takes that number). Currently I am doing it like below. However I feel this is very inefficient and will cause me problems later on if I decide to add key down events to change the backcolors of some of the labels (to indicate status).
Does anyone know of a better way to do this?
if (count > 4)
{
count = 0
}
count ++;
pictureBox4.image = pictureBox3.image;
pictureBox3.image = pictureBox2.image;
pictureBox2.image = pictureBox1.image;
pictureBox1.imagelocation = (#"http://192.168.X.X/image.cgi")
label4.Text =label3.text;
label3.text = label2.text;
label2.text = label1.text;
label1.text = count.ToString()+ " " + datetime.now();
I could create a new Control, most likely a Panel that contains all of these UI elements in it (PictureBox, Label, anything else). Have a constructor for your Control that takes a URL of the image. Load the image into your PictureBox, and set your label.
Have all of that logic encapsulated in your Control. So when a new one is added, you just create the new Control, and remove the last one in your row, and move the .Left properties of the 3 remaining to their new locations.
Don't forget to implement IDisposable, and Dispose of the Controls when they're removed to free up the resources of displaying the images.
EDIT
If it's not there already, you can provide references back to the top Control in each of your inner Controls (PictureBox and Label), and even to your main form in your top Control by passing this as a parameter in the constructor as well and setting a private member variable inside those controls. That way, when someone clicks on the PictureBox, you can go up the line to this.Parent and get your outer Control. You could even have that reference to your Main Form (hopefully a Panel in there that holds your 4 of these objects). That could be this.Parent.Parent to call a method on there. (I think there's already a public property of Parent on all Controls, so that's fine.)
A little bit of quick coding:
You have your main Form (mainForm). In there is a Panel (picturePanel). picturePanel holds your 4 new Panels, which we'll call customPanel. Each customPanel has a PictureBox (imageBox), and Label (fileNameLabel).
Your customPanel constructor would look like this:
public partial class CustomPanel : Panel {
private PictureBox _imageBox;
private Label _fileNameLabel;
public CustomPanel() {} // This is most likely tied into the code behind file. Sorry, It's been a while since I've done WinForms
public CustomPanel(string imageFileName, Panel parent) {
// Set the source for the PictureBox.
// Set the Text of the label.
_parent = parent;
}
}
Continue with this down the line through the PictureBox and Label. Then in your events, you have your PictureBox work up the chain. To find picturePanel. If you want to get really fancy, you could have that derive from Panel as well and just add a public property that handles all of the switching around of which customPanel sent the message.
So down in your PictureBox event, you could have a line of code like this:
if (this.Parent.Parent is PicturePanel) {
((PicturePanel)this.Parent.Parent).RemovePicture(this.Parent);
}
I have a published app in the windows phone marketplace, which I'm trying to port to Win 8. I'm using Windows 8 Release Preview and Visual Studio Express RC 2012 for Win 8 and the code is C#-XAML.
I have created a custom 6x7 calendar. The first 7 buttons are put into the first StackPanel , the next into another panel and so forth. So there are 6 StackPanels holding 42 buttons. All these StackPanels are put into a Grid for the easy positioning.
Every button has is associated with a Holding EventHandler named OnLongPress. So the problem I'm facing is that when a button is pressed, the OnLongPress function is being called twice. On debugging I found that first time, the Holding state is Started and the next time it is called, the Holding state id Completed. I cannot figure out why it is being called twice.
Is it because the event is bubbled up?? :(
private void OnLongPress(object sender, HoldingRoutedEventArgs e)
{
Button butClicked = (Button)sender;
int iNumClicked = Convert.ToInt32(butClicked.Content.ToString());
CycleManager pCycMan = CycleManager.Instance;
string iVal, jVal;
int iRow, jCol;
string butName = butClicked.Name;
iVal = butName.Substring(1, 1);
jVal = butName.Substring(2, 1);
iRow = Convert.ToInt32(iVal);
jCol = Convert.ToInt32(jVal);
DateTime dtSelDate = new DateTime(m_yearBuffer[iRow, jCol], m_monthBuffer[iRow, jCol], iNumClicked);
int trackingStatus = pCycMan.IsDateOkForHistory(dtSelDate);
// setting or resetting few colors based on few checks
}
It would be helpful if someone can shed some light since I'm new to Win 8 dev.
I have solved the issue holding event being called twice, once on handling state is started and once on completed by including the following check. I'm still not sure if it is the right method.
if (e.HoldingState == Windows.UI.Input.HoldingState.Started)
If you just want the event to fire only once when holding state is complete or cancel, try to use RightTapped.
Holding is intended for informational UI, but for interactions like displaying a context menu you should use RightTapped instead. You might handle Holding first to display a hint that a menu will appear, but to display the menu itself, use a RightTapped handler. See Touch interaction design or Guidelines for common user interactions for more info on how to use a Hold interaction in your app design.
http://msdn.microsoft.com/en-us/library/windows.ui.xaml.uielement.holding.aspx
RightTapped for a touch action results from processing an action that remains in one place for a certain amount of time. If it's a touch action, a Holding event from the same element always precedes this, but RightTapped won't fire until the touch point is released. If the time the pointer is pressed is too short and Tapped fires instead of Holding, or if the Hold action ends with HoldingState as Canceled, RightTapped won't fire.
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.