I have an application which asks the user a few simple questions. The user is supposed to input the answer by typing it into a TextBox. When I render the Windows Form though, the TextBox is greyed out, blends in with the background, and is uneditable.
Here's my code:
public string waitForText(Point Locution)
{
TextBox WriteAnswerHere = new TextBox();
WriteAnswerHere.Location = Locution;
WriteAnswerHere.ReadOnly = false;
WriteAnswerHere.Focus();
this.Controls.Add(WriteAnswerHere);
int waiting = 1;
while (waiting == 1)
{
if (Control.ModifierKeys == Keys.Enter)
{
waiting = 0;
}
}
string HowYouAre = WriteAnswerHere.Text;
this.Controls.Remove(WriteAnswerHere);
return HowYouAre;
}
The input is supposed to be given to the application when the Enter key is pressed, hence the (Control.ModifierKeys == Keys.Enter); Any suggestions on what I am doing wrong?
You shouldn't use a while loop to detect specific key events. Your while loop is holding up the form. I suggest you check out these articles on Events and Event handlers for Windows forms.
http://msdn.microsoft.com/en-us/library/dacysss4.aspx
Related
I have a problem using Sendkeys.Send in my C# application and I really cannot understand why. When using it then it does not send what I expect to the active application. I am using it together with the global hotkey manager, https://github.com/thomaslevesque/NHotkey
I have created this simple PoC that, for my part at least, will be able to reproduce my problem. Just launch Wordpad and press the hotkey, ALT + O:
using System.Windows.Forms;
using System.Diagnostics;
using NHotkey.WindowsForms;
namespace WindowsFormsApp5
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Convert string to keys
string hotkey = "Alt + O";
KeysConverter cvt;
Keys key;
cvt = new KeysConverter();
key = (Keys)cvt.ConvertFrom(hotkey);
// Setup the hotkey
HotkeyManager.Current.AddOrReplace("MyID", key, HotkeyAction);
// Copy some text to the clipboard that I want to paste to the active application
Clipboard.SetText("My String");
}
private void HotkeyAction(object sender, NHotkey.HotkeyEventArgs e)
{
Debug.WriteLine("Pressed the hotkey");
SendKeys.Send("^v");
// SendKeys.Send("Test string");
e.Handled = true;
}
}
}
When I do this in Wordpad, then instead of pasting the clipboard (^v equals CTRL + V) then it tries to "Paste Special":
Even if I do the most simple thing and then just put some text in SendKeys.Send, then it seems to be messing with the menus in Wordpad? SendKeys.SendWait is not any different.
I have been trying to figure this out for quite some time now but I simply do not understand why it does that. Basically, I need to paste the clipboard on a hotkey though it doesn't need to be with this exact method so if anyone knows another way of doing it then I would appreciate some hints.
MY IMPLEMENTED SOLUTION
Based on the accepted answer then I did change my implementation slightly as I could not get it working with just a timer. I may have missed something(?) but this is working.
In basic then I change focus to my application as soon as the hotkey is detected, to avoid conflict with modifier keys (ALT etc) in the active application. I then create an invisible form and when I detect a KeyUp event, then I check for modifier keys and if none is pressed down then I enable a timer and immediately switch focus back to the originating application. After 50ms the clipboard will be pasted to the active application.
Something like this:
// Somewhere else in code but nice to know
// IntPtr activeApp = GetForegroundWindow(); // get HWnd for active application
// SetForegroundWindow(this.Handle); // switch to my application
private System.Timers.Timer timerPasteOnHotkey = new System.Timers.Timer();
// Main
public PasteOnHotkey()
{
InitializeComponent();
// Define the timer
timerPasteOnHotkey.Elapsed += new ElapsedEventHandler(OnTimedEvent);
timerPasteOnHotkey.Interval = 50;
timerPasteOnHotkey.Enabled = false;
// Make the form invisble
this.Size = new System.Drawing.Size(0, 0);
this.Opacity = 0.0;
}
private void PasteOnHotkey_KeyUp(object sender, KeyEventArgs e)
{
// Check if modifier keys are pressed
bool isShift = e.Shift;
bool isAlt = e.Alt;
bool isControl = e.Control;
// Proceed if no modifier keys are pressed down
if (!isShift && !isAlt && !isControl)
{
Hide();
// Start the timer and change focus to the active application
timerPasteOnHotkey.Enabled = true;
SetForegroundWindow(activeApp);
}
}
private void OnTimedEvent(object source, ElapsedEventArgs e)
{
timerPasteOnHotkey.Enabled = false;
SendKeys.SendWait("^v"); // send "CTRL + v" (paste from clipboard)
}
When you use SendKeys.Send in a response to a key press then the keys you send may be combined with the physical keys you’re holding at that moment. In this case you’re holding Alt, so Wordpad assumes you pressed Alt-Ctrl-V instead of just Ctrl-V. Also Alt opens menu, so sending other keys may relate to hotkeys there.
Adding a delay will remove this issue, and usually when sending key presses it would be done as not relating to other key presses so it won’t be a problem.
I am working on a barcode reader project in Visual Studio using C#. I have created a WinForm Application and have added a RichTextBox to it. I want the user to be able to start scanning when they open the program without having to click on the textbox.
Thanks in advance!
(I'm assuming you have an application with a multitude of stuff in it. However there is one field that needs to be filled in with a scanned barcode.)
I faced a simular issue a while ago. I needed to capture a barcode in WPF. Setting the focus property in load seemed a good idea but because there were a multitude of other controls on the page that the user could click etc. focus jumped from one control to the other, making the barcode go in the wrong fields or vanish in a grid that has focus for example.
We were not able to use any other way of reading the barcode from the scanner because it was used for other applications too. It had to be configured as input.
We came up with a solution of capturing the keypresses instead.
By using the keydown events we could track the scanner input and stated that if more than 5 keys came in within a limited time + with our prefix and suffix it had to be a barcode.
EDIT: here is a simplified version of the class.
public delegate void BarcodeRead(string barcode);
public class ManualReader
{
private string barcode = "no barcode detected";
private string possible = "";
private DateTime timestarted = DateTime.MinValue;
private Timer InputTimeout;
public BarcodeRead OnBarcodeRead;
public void OnKeyDown(object sender, KeyEventArgs.KeyEventArgs e)
{
//create timer if it does not exist
if (InputTimeout == null)
{
InputTimeout = new Timer(100);
InputTimeout.Enabled = true;
InputTimeout.Elapsed += new ElapsedEventHandler(OnTimedEvent);
}
//reset timer
InputTimeout.Stop();
InputTimeout.Start();
//possible barcode
possible += CharToKey.GetCharFromKey(e);
if (timestarted == DateTime.MinValue)
{
timestarted = DateTime.Now;
}
}
//Timer elapses
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
//Is it a barcode?
if ((timestarted.AddMilliseconds(600) > DateTime.Now) && (possible.Length > 5)
&& (timestarted != DateTime.MinValue) && possible.Contains("\r"))
{
barcode = possible;
barcode = barcode.Remove(0, 1);
barcode = barcode.Replace("\r", "");
//launch delegate
if (OnBarcodeRead != null)
{
OnBarcodeRead.Invoke(barcode);
}
}
//delete timers
timestarted = DateTime.MinValue;
InputTimeout.Dispose();
InputTimeout = null;
possible = null;
}
}
}
I'm aware that for really short timeouts datetime functions aren't precise but still this little 'hack' worked perfectly for our application.
You can add directly in the element. This works for textbox but not sure with RichTexBox
FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"
I have a modeless UI that adds a userID to a list that allows or removes access to parts of a program. When I click the modify button everything works as it should. Suppose I close the dialog and realize "Wait, forgot to do X". When I reopen the dialog box, perform my work and click Modify, the value for adding the userID is still available to the program even though the textbox is blank.
It's happening somewhere in the following code.
public static void checkSame()
{
int count = 0;
bool test = false;
while (linesPerm.Length >= count && tbPermValue != "")
{
if (linesPerm.Length >= count)
{
test = linesPerm.Contains(tbPermValue);
count += (linesPerm.Length + 1);
if (test == true)
{
DialogResult dr = MessageBox.Show("The UserID " + tbPermValue +
" already exists in the Permissions column. "
+ Environment.NewLine + "Would you like to add the UserID" +
tbPermValue + " to the Permissions column anyway?",
"User Already Exists", MessageBoxButtons.YesNo,
MessageBoxIcon.Question);
switch (dr)
{
case DialogResult.Yes:
break;
case DialogResult.No:
tbPermValue = "";
break;
}
}
}
else
{
MessageBox.Show("Do Nothing");
}
}
}
If the user selects No on the dialog box, the value of tbPermValue is not available to the program. If the user selects Yes then the value of tbPermValue persists even if the dialog box is closed and reopened. I have tried to clear the textbox value like so.
tbUserName.Text = "";
tbUserName.Clear();
and several other ways. tbUserName value is being cleared from the textbox, but not from the code above. I get the value of tbPermValue like this.
public static void addPerm(System.Windows.Forms.Form targetForm)
{
foreach (Control C in targetForm.Controls)
{
if (C.GetType() == typeof(TextBox))
{
if (C.Text != "")
{
tbPermValue = C.Text;
}
}
}
}
This is a modeless dialog box owned by it's parent.
Can anyone point me in a direction that would remove access to tbPermValue to the DialogResult portion of the first code box after the button is clicked. I can't lose it completely because tbPermValue is used in other code down the line.
EDIT: Ok. I just tested this and the value is being held in memory. I have a dialog Form1 that has a button that opens dialog StartHere. On StartHere there is a button that opens Permissions. StartHere owns Permissions so that when I close StartHere, Permissions and all other child forms of StartHere will close. These are all modeless dialogs. My variable tbPermValue is being held in memory way back to Form1. The value is not being disposed when I close the dialog StartHere. I'm going to go back and research Garbage Collection at the advice of Eric below. Thank you Eric. I'll delete the question or at least post a new better question once I find out the rules for this process. Thank You.
Edit 2: Here is the code you asked for γηράσκωδ'αείπολλάδιδασκόμε
private void bModify_Click(object sender, EventArgs e)
{
WidgetLogic.addPerm(this);
WidgetLogic.checkSame();
WidgetLogic.writePerm(this);
WidgetLogic.writeAdmin(this);
WidgetLogic.writeDetailer(this);
tbUserName.Clear();
}
As noted above I have tried numerous ways to clear tbUserName to no avail.
Don't use tbPermValue but instead use the textbox directly:
while (linesPerm.Length >= count && tbUserName.Text != "")
EDIT
Change the code in addPerm to this, and you are done :):
public static void addPerm(System.Windows.Forms.Form targetForm)
{
foreach (Control C in targetForm.Controls)
{
if (C.GetType() == typeof(TextBox))
{
tbPermValue = C.Text;
}
}
}
You don't need the switch (dr) in checkSame()
I see that you say you have tried setting the following in the "yes" part of your switch statement:
tbUserName.Text = "";
tbUserName.Clear();
But in your "no" part, you don't set tbUserName, but instead you set the variable tbPermValue. From what I can tell, you should also be setting
tbPermValue = "";
in your "yes" part as well to clear that variable, or even just move it out of the switch and have it do that before the dialog closes since you would be setting it in all of the possible switch cases anyways.
I have a application that reads data from health cards and parse them for basic info like D.O.B., Health Card #, and names. Right now, I have a textbox that takes input from the card swiper and it works great, but I feel there could be a better approach for this.
I want to have a keyboard listener in the background of the application that captures input from the card swiper and parse the data without the need of a textbox. I figure I'll need a loop function in the Form1_Load that actively listens for keyboard inputs, prepare a buffer for the input, and then when a carriage return is detected, go ahead and parse the buffered data. When the parsing is done, clear the buffer.
My problem is I'm relatively new to C# and I don't know what I should use for listening to keyboard inputs without a textbox. Could someone point me in the right direction?
Here's my code in case if anyone's interested: http://pastebin.com/q6AkghvN
Just a note, I followed the credit card swipe guide from
http://www.markhagan.me/Samples/CreditCardSwipeMagneticStripProcessing and modified it slightly for my usecase.
--- EDITED ---
Thanks Paul and everyone else for their help!
Here is my solution if anyone is interested:
private void frmMain_KeyPress(object sender, KeyPressEventArgs e)
{
lblStatus.Text = "Reading Card...";
lblStatus.ForeColor = Color.Blue;
if (e.KeyChar != (char)Keys.Enter)
{
buffer += e.KeyChar;
}
else
{
lblStatus.Text = "Parsing Card...";
if (buffer.Contains('^') && buffer.Contains(';') && buffer.Contains('='))
{
try
{
string[] cardData = buffer.Split(';');
string[] caretData = cardData[0].Split('^');
string[] nameData = caretData[1].Split('/');
string[] equalData = cardData[1].Split('=');
tBoxHealthCardNumber.Text = equalData[0];
tBoxDateOfBirth.Text = FormatBirthday(equalData[1]);
tBoxFirstName.Text = TrimName(nameData[1]);
tBoxLastName.Text = TrimName(nameData[0]);
tBoxDateTimeScanned.Text = DateTime.UtcNow.ToString("yyyy/MM/dd HH:mm");
e.Handled = true;
}
catch (Exception)
{
throw;
}
}
else
{
lblStatus.Text = "Error Reading Card";
}
buffer = "";
lblStatus.Text = "Ready";
lblStatus.ForeColor = Color.Green;
}
}
If you add a key handler to the form you will not see the key presses when focus is on a control, e.g. a textbox. For the form to see the key presses even when there is a focused control, you must also enable the KeyPreview property.
You can then add a handler for KeyDown, KeyPress and/or KeyUp on the form as you desire to receive these events.
As you can read in the documentation to KeyPreview, if you set the Handled property to true, you can prevent the event from being subsequently sent to the focused control, i.e. you can hide certain key events from being seen by the focused control.
I am working on a wpf .My requirement is to change selection of tab according to user confirmation it means every time when user changes tab a message box opens and confirm with user whether he wants to change the tab or not.
But problem with me is when I press no first time it works fine .but after that on second time it asks two times for user confirmation
can anyone help me to solve this ?
private void tabcontrol_SelectionChanged(object sender,SelectionChangedEventArgs e)
{
try
{
if (handleSelection && e.OriginalSource == tbUserProfileMainControl)
{
//Ask user for change
if (isUserAllowedToChanged)
{
int currentIndex = (tabcontrol.SelectedIndex);
GeneralDeclaration.currentSelectedTabIndex = currentIndex;
LoadUserControl(GeneralDeclaration.currentSelectedTabIndex);
}
else
{
//e.Handled = true;
handleSelection = false;
tbUserProfileMainControl.SelectedIndex = Math.Abs(tbUserProfileMainControl.SelectedIndex - 1);
}
}
handleSelection = true;
}
catch (Exception ex)
{
//
}
}
It sounds like you're adding handlers during the click event itself. This causes your subsequent click to perform the action one more time (3rd click 3 times, 4th click 4 times, etc).
Check how you bind the event to the handler and check where you are defining the handler itself. You're doing something twice that should only be done once.
This is my estimation based on your findings, without code, I'm just taking a wild stab in the dark.