Creating a control to capture use defined key combinations - c#

I want to create a small control that allows the users of my application to define key combinations, and display them in a human readable format.
For example, I currently have a text box and if the user has focus and then presses a key, it will record and display the pressed key within the text box, my issues are when it comes to key combinations, or special keys (CTRL, ALT, BACKSPACE etc.)
Here is the simple code I have at the moment, which I was using just to experiment:
private void tboxKeyCombo_KeyPress(object sender, KeyPressEventArgs e)
{
if (tboxKeyCombo.Focused)
{
string sKeyboardCombo = String.Empty;
if (char.IsLetterOrDigit(e.KeyChar))
{
sKeyboardCombo += e.KeyChar.ToString();
}
else if (char.IsControl(e.KeyChar))
{
sKeyboardCombo += "CTRL";
}
tboxKeyCombo.Text += sKeyboardCombo + "+";
}
}
At the moment it behaves very weirdly, if I was to press "CTRL+O" it would display "CTRL+" in the text box. Even if I press BACKSPACE it just prints CTRL anyway.
I think I'm misunderstanding some of the parts of deciphering the keyboard input, so any help would be brilliant - thank you.

As an option, you can create a control based on TextBox and make it read-only, then override some key functions like ProcessCmdKey and convert pressed keys to string using KeysConverter class.
Example
using System.Windows.Forms;
public class MyTextBox : TextBox
{
public MyTextBox() { this.ReadOnly = true; }
public Keys ShortcutKey { get; set; }
public new bool ReadOnly
{
get { return true; }
set { base.ReadOnly = true; }
}
KeysConverter converter = new KeysConverter();
protected override bool ProcessCmdKey(ref Message m, Keys keyData)
{
ShortcutKey = keyData;
this.Text = converter.ConvertToString(keyData);
return false;
}
}

Related

Comparing Text entered into the textbox of a windows form to objects in order to validate user

I want to call a List from another class in order to compare text thats enter into a windowforms textbox. The list contains emails and passwords retrieved from a database using a select procedure already, I just want to compare the text for a text box to it in order to validate user login. I'm lost when it comes to doing this , please help. I searched the goggle and couldn't find anything.
Here's the creation of the list from the original class
List<UserModel> IDataConnection.CreateUserList()
{
List<UserModel> output;
using (IDbConnection connection = new System.Data.SqlClient.SqlConnection(GlobalConfig.CnnString("MasterChef")))
{
output = connection.Query<UserModel>("spPeople_GetLogin").ToList();
}
return output;
}
this is the other class and what I did so far. I called it and want to use it to validate login by seeing if the text entered into the text box match any of the elements
public partial class LoginForm : Form
{
List<UserModel> output = GlobalConfig.Connection.CreateUserList();
public LoginForm()
{
InitializeComponent();
}
private void logButton_Click(object sender, EventArgs e)
{
if (ValidateLogin())
{
}
}
private bool ValidateLogin()
{
bool valid = true;
if (loginEmailTextBox.Text.Length == 0)
{
valid = false;
}
if(loginPasswordTextBox.Text.Length == 0)
{
valid |= false;
}
return valid;
}
}
}
I searched all of google , watched youtube videos and everything.

How to pass textbox data to a datagridview in different forms

I have two forms:
The first form (XML Data Loader) contains a DataGridView with six columns (Name, Width, Height, Length, Dead Weight, Load Capacity)
XML Data Loader also has a button on it, which when pressed opens a new forms window (Add New Car).
Add New Car has six textboxes where train car data is input by a user.
The goal is for the user to be able to click the Save button on Add New Car and the data will be pushed into a new row in the DataGridView on XML Data Loader, but I am having an issue with actually finding a way to do this. Everything else I've found assumes that DataGridViews are being populated through a database, but mine is user-input populated.
public partial class XMLDataLoader : Form
{
public XMLDataLoader()
{
InitializeComponent();
}
private void buttonAddCar_Click(object sender, EventArgs e)
{
AddNewCar addNewCar = new AddNewCar();
addNewCar.Show();
}
}
public partial class AddNewCar : Form
{
public AddNewCar()
{
InitializeComponent();
}
private void buttonNewSave_Click(object sender, EventArgs e)
{
//Check that all textboxes have some kind of entry
//ToDo: check the type of data so that only numbers are entered into non-name categories
if(textBoxNewName.TextLength < 1)
{
MessageBox.Show("Please enter a train name!");
}
if (textBoxNewWidth.TextLength < 1)
{
MessageBox.Show("Please enter a train width!");
}
if (textBoxNewHeight.TextLength < 1)
{
MessageBox.Show("Please enter a train height!");
}
if (textBoxNewLength.TextLength < 1)
{
MessageBox.Show("Please enter a train length!");
}
if (textBoxNewDeadWeight.TextLength < 1)
{
MessageBox.Show("Please enter a train dead weight!");
}
if (textBoxNewLoadCapacity.TextLength < 1)
{
MessageBox.Show("Please enter a train load capacity!");
}
//Save all data input by user to create a new train momentarily
var newTrainName = textBoxNewName.Text;
var newTrainWidth = textBoxNewWidth.Text;
var newTrainHeight = textBoxNewHeight.Text;
var newTrainLength = textBoxNewLength.Text;
var newTrainDeadWeight = textBoxNewDeadWeight.Text;
var newTrainLoadCapacity = textBoxNewLoadCapacity.Text;
}
}
First, use ShowDialog() instead of Show(). That way, you will still be in buttonAddCar_Click when the AddNewCar dialog closes. The way your code is now, buttonAddCar_Click will exit while AddNewCar is still visible, and your main window will have lost all contact with the instance of AddNewCar that you created.
Secondly, you need to expose the text box values to the caller. So after the dialog closes, addNewCar.textBoxNewName.Text will contain the string the user typed into the New Name TextBox. But by default that's not public. So add a bunch of properties to expose the values:
public String NewName { get { return textBoxNewName.Text; } }
In buttonAddCar_Click after the call to ShowDialog(), you can do whatever you like with the exposed Text properties of all those TextBoxes.
I don't do winforms every day now, so it's possible that textBoxNewName.Text may throw an exception if you touch it after the form closes. Easy fix! Declare the public properties as regular properties instead of get-only accessors...
public String NewName { get; protected set; }
...and assign them their values in the OK click event when the user's input passes validation. Which is our next topic.
Lastly, making the user click on (potentially) six popups in succession is enough to make him commit suicide. Instead, I'd recommend declaring a string variable called message and concatenating:
string message = "";
if(textBoxNewName.TextLength < 1)
{
message += "Please enter a train name!\n"
}
if (textBoxNewWidth.TextLength < 1)
{
message += "Please enter a train width!\n";
}
// ...etc....
if (!String.IsNullOrWhiteSpace(message))
{
MessageBox.Show(message);
}
else
{
NewName = textBoxNewName.Text;
// ...and so on for the other five properties.
// This will close the form and cause ShowDialog() to
// return DialogResult.OK
DialogResult = DialogResult.OK;
}
Form.DialogResult is a useful adjunct to Form.ShowDialog().
If you have a Cancel button, it doesn't even need a Click method. Just set that Button's DialogResult property to DialogResult.Cancel in the form designer, and it'll assign that value to Form.DialogResult when the user clicks it, which will cause the window to close and ShowDialog to return DialogResult.Cancel.
Another way you could do this is declare a simple class which has all the car-creation data in it: NewName, Width, etc. Write an overload of ShowDialog() which returns that type, or which takes a reference to that type and returns bool (true for OK). If user cancels it returns null or false; if user clicks OK and passes validation, it returns an instance of that class, or in the reference version, populates the members of the reference that was passed in, and then returns true.
If you already have a class which represents a Car (from Entity Framework or whatever), you would just use that.
But the way I've described above is consistent with usage in built-in WinForms dialogs like FileOpen and so on. My touchstone when working in any environment like WinForms, MFC, WPF, etc. is What Would the Framework Do? That's almost invariably the right answer, because a) successful frameworks tend to be reasonably well designed (they are used successfully by people who can't access their internals or consult their implementors), and b) anybody who interacts your code will know exactly what to expect because he already knows the framework's way of doing things.
Every time I use third party code that thinks it's smarter than the framework, I can't help noticing how much dumber it is.
Hat tip to #Ed Plunkett for the help - it's working swimmingly now!!
public partial class XMLDataLoader : Form
{
public XMLDataLoader()
{
InitializeComponent();
}
//Function for the Add Car button to open the Add New Car window
private void buttonAddCar_Click(object sender, EventArgs e)
{
AddNewCar displayNewCarWindow = new AddNewCar();
displayNewCarWindow.ShowDialog();
dataGridViewMainCarDisplay.Rows.Add(displayNewCarWindow.NewTrainName
, displayNewCarWindow.NewTrainWidth
, displayNewCarWindow.NewTrainHeight
, displayNewCarWindow.NewTrainLength
, displayNewCarWindow.NewTrainDeadWeight
, displayNewCarWindow.NewTrainLoadCapacity);
}
//Function for the Remove Car button to delete the currently
//selected car from the datagridview
private void buttonRemoveCar_Click(object sender, EventArgs e)
{
}
}
}
public partial class AddNewCar : Form
{
public AddNewCar()
{
InitializeComponent();
}
//Get and Private Set methods to pass textbox data to XMLDataLoader form
public String NewTrainName { get; private set; }
public String NewTrainWidth { get; private set; }
public String NewTrainHeight { get; private set; }
public String NewTrainLength { get; private set; }
public String NewTrainDeadWeight { get; private set; }
public String NewTrainLoadCapacity { get; private set; }
private void buttonNewSave_Click(object sender, EventArgs e)
{
//Check that all textboxes have some kind of entry
//ToDo: check the type of data so that only numbers are entered into non-name categories
var message = String.Empty;
if(textBoxNewName.TextLength < 1)
{
message += "Please enter a train name!\n";
}
if (textBoxNewWidth.TextLength < 1)
{
message += "Please enter a train width!\n";
}
if (textBoxNewHeight.TextLength < 1)
{
message += "Please enter a train height!\n";
}
if (textBoxNewLoadCapacity.TextLength < 1)
{
message += "Please enter a train length!\n";
}
if (textBoxNewDeadWeight.TextLength < 1)
{
message += "Please enter a train dead weight!\n";
}
if (textBoxNewLength.TextLength < 1)
{
message += "Please enter a train load capacity!\n";
}
//Save all data input by user to create a new train
NewTrainName = textBoxNewName.Text;
NewTrainWidth = textBoxNewWidth.Text;
NewTrainHeight = textBoxNewHeight.Text;
NewTrainLength = textBoxNewLoadCapacity.Text;
NewTrainDeadWeight = textBoxNewDeadWeight.Text;
NewTrainLoadCapacity = textBoxNewLength.Text;
//Handle the form execution for whether or not a textbox is empty
if (message != String.Empty)
{
MessageBox.Show(message);
}
else
{
DialogResult = DialogResult.OK;
}
}
//Function for the Cancel button to close the Add New Car window
private void buttonNewCancel_Click(object sender, EventArgs e)
{
DialogResult = DialogResult.Cancel;
}
}

NumberPicker does not work with keyboard input value in Xamarin Android

I have a numberpicker control in android activity. It works good when clicking those "+" and "-" buttons. But when I enter a number from keyboard it and try to get the current entered value in program, it does not give value which was entered by keyboard. I am working with C# Xamarin android.
is there any key press event or something which can help?
You could create set a Custom OnEditorActionListener on the EditText of the NumberPicker:
NumberPicker picker;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.test);
picker = FindViewById<NumberPicker>(Resource.Id.numberPicker);
picker.MaxValue = 40;
picker.MinValue = 1;
EditText editText= (EditText)picker.GetChildAt(1);
editText.SetOnEditorActionListener(new CustomActionListener());
}
public class CustomActionListener : Java.Lang.Object,EditText.IOnEditorActionListener
{
public bool OnEditorAction(TextView v, Android.Views.InputMethods.ImeAction actionId, KeyEvent e)
{
if(actionId == Android.Views.InputMethods.ImeAction.Done)
{
// Here is you number
string countNumber = v.Text;
}
return true;
}
public IntPtr Handle
{
get { return base.Handle; }
}
public void Dispose()
{
base.Dispose();
}
}

C# validating data in multiple text boxes?

I have a C# form with multiple text boxes. Before proceeding I need to validate the inputs in the each text box. If my validation rule for each text box is same, Do I have any way to apply the same rule for all the fields at once. And my desired output is same. (I want to change the backcolour of the relevant textbox into pink) I mean I don't want to use anything like
validate_txtName();
validate_txtAddress();
validate_txtCity();
There should be some standard and easy way to do this.. I am seeking of that way ;)
First, put all the textboxes in a list. Then apply the ForEach function on the list, passing as argument the lambda expression that represents you're validation rule.
Edit:
I've found this example in my own code:
Core.Model.Settings.Labels.ToList()
.ForEach(x => schedulerStorage1.Appointments.Labels.Add(Color.FromArgb(x.ARGB), x.LabelName));
maybe foreach loop? :)
Write you own control which accepts a regular expression string for validation check during design time. At execution time handle the Validating event with one common handler. Following code does this. You can remove the errorprovider and just use the backcolor logic.
public class ValidatedTextBox : TextBox
{
private IContainer components;
private Color m_OldBackColor;
[Description("Color to be set when validation fails.")]
public Color BackColorOnFailedValidation
{
get
{
return m_BackColorOnFailedValidation;
}
set
{
m_BackColorOnFailedValidation = value;
}
}
private Color m_BackColorOnFailedValidation = Color.Yellow;
[Description("Message displayed by the error provider.")]
public string ErrorMessage
{
get
{
return m_ErrorMessage;
}
set
{
m_ErrorMessage = value;
}
}
private string m_ErrorMessage = "";
[Description("Regular expression string to validate the text.")]
public string RegularExpressionString
{
get
{
return m_RegularExpressionString;
}
set
{
m_RegularExpressionString = value;
}
}
private string m_RegularExpressionString = "";
private ErrorProvider errorProvider1;
[Browsable(false)]
public bool Valid
{
get
{
return m_Valid;
}
}
private bool m_Valid = true;
public ValidatedTextBox()
: base()
{
InitializeComponent();
m_OldBackColor = this.BackColor;
this.Validating += new System.ComponentModel.CancelEventHandler(ValidatedTextBox_Validating);
errorProvider1.Clear();
}
void ValidatedTextBox_Validating(object sender, System.ComponentModel.CancelEventArgs e)
{
if (RegularExpressionString != string.Empty)
{
Regex regex = new Regex(RegularExpressionString);
m_Valid = regex.IsMatch(Text);
SetBackColor();
if (!Valid)
{
errorProvider1.SetError(this, this.ErrorMessage);
this.Focus();
}
else
{
errorProvider1.Clear();
}
}
}
private void SetBackColor()
{
if (!Valid)
BackColor = BackColorOnFailedValidation;
else
BackColor = m_OldBackColor;
}
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.errorProvider1 = new System.Windows.Forms.ErrorProvider(this.components);
((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).BeginInit();
this.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.errorProvider1)).EndInit();
this.ResumeLayout(false);
}
}
you can try this i suppose.. Put all the controls you want to validate in a grouper control and call validate on all the controls inside the grouper using a foreach loop

How to detect the currently pressed key?

In Windows Forms, you can know, at any time, the current position of the cursor thanks to the Cursors class.
The same thing doesn't seem to be available for the keyboard. Is it possible to know if, for example, the Shift key is pressed?
Is it absolutely necessary to track down every keyboard notification (KeyDown and KeyUp events)?
if ((Control.ModifierKeys & Keys.Shift) != 0)
This will also be true if Ctrl+Shift is down. If you want to check whether Shift alone is pressed,
if (Control.ModifierKeys == Keys.Shift)
If you're in a class that inherits Control (such as a form), you can remove the Control.
The code below is how to detect almost all currently pressed keys, not just the Shift key.
private KeyMessageFilter m_filter = new KeyMessageFilter();
private void Form1_Load(object sender, EventArgs e)
{
Application.AddMessageFilter(m_filter);
}
public class KeyMessageFilter : IMessageFilter
{
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private bool m_keyPressed = false;
private Dictionary<Keys, bool> m_keyTable = new Dictionary<Keys, bool>();
public Dictionary<Keys, bool> KeyTable
{
get { return m_keyTable; }
private set { m_keyTable = value; }
}
public bool IsKeyPressed()
{
return m_keyPressed;
}
public bool IsKeyPressed(Keys k)
{
bool pressed = false;
if (KeyTable.TryGetValue(k, out pressed))
{
return pressed;
}
return false;
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
KeyTable[(Keys)m.WParam] = true;
m_keyPressed = true;
}
if (m.Msg == WM_KEYUP)
{
KeyTable[(Keys)m.WParam] = false;
m_keyPressed = false;
}
return false;
}
}
You can also look at the following if you use WPF or reference System.Windows.Input
if (Keyboard.Modifiers == ModifierKeys.Shift)
The Keyboard namespace can also be used to check the pressed state of other keys with Keyboard.IsKeyDown(Key), or if you are subscribing to a KeyDownEvent or similar event, the event arguments carry a list of currently pressed keys.
Most of these answers are either far too complicated or don't seem to work for me (e.g. System.Windows.Input doesn't seem to exist). Then I found some sample code which works fine:
http://www.switchonthecode.com/tutorials/winforms-accessing-mouse-and-keyboard-state
In case the page disappears in the future I am posting the relevant source code below:
using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace MouseKeyboardStateTest
{
public abstract class Keyboard
{
[Flags]
private enum KeyStates
{
None = 0,
Down = 1,
Toggled = 2
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern short GetKeyState(int keyCode);
private static KeyStates GetKeyState(Keys key)
{
KeyStates state = KeyStates.None;
short retVal = GetKeyState((int)key);
//If the high-order bit is 1, the key is down
//otherwise, it is up.
if ((retVal & 0x8000) == 0x8000)
state |= KeyStates.Down;
//If the low-order bit is 1, the key is toggled.
if ((retVal & 1) == 1)
state |= KeyStates.Toggled;
return state;
}
public static bool IsKeyDown(Keys key)
{
return KeyStates.Down == (GetKeyState(key) & KeyStates.Down);
}
public static bool IsKeyToggled(Keys key)
{
return KeyStates.Toggled == (GetKeyState(key) & KeyStates.Toggled);
}
}
}
Since .NET Framework version 3.0, it is possible to use the Keyboard.IsKeyDown method from the new System.Windows.Input namespace. For instance:
if (((Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)) && Keyboard.IsKeyDown(Key.F))
{
// CTRL + F is currently pressed
}
Even though it's part of WPF, that method works fine for WinForm applications (provided that you add references to PresentationCore.dll and WindowsBase.dll). Unfortunately, however, the 3.0 and 3.5 versions of the Keyboard.IsKeyDown method did not work for WinForm applications. Therefore, if you do want to use it in a WinForm application, you'll need to be targeting .NET Framework 4.0 or later in order for it to work.
You can P/Invoke down to the Win32 GetAsyncKeyState to test any key on the keyboard.
You can pass in values from the Keys enum (e.g. Keys.Shift) to this function, so it only requires a couple of lines of code to add it.
if ((ModifierKeys == Keys.Control) && ((e.KeyChar & (char)Keys.F) != 0))
{
// CTRL+F pressed !
}
if (Control.ModifierKeys == Keys.Shift)
//Shift is pressed
The cursor x/y position is a property, and a keypress (like a mouse click/mousemove) is an event. Best practice is usually to let the interface be event driven. About the only time you would need the above is if you're trying to do a shift + mouseclick thing.
The best way I have found to manage keyboard input on a Windows Forms form is to process it after the keystroke and before the focused control receives the event. Microsoft maintains a built-in Form-level property named .KeyPreview to facilitate this precise thing:
public frmForm()
{
// ...
frmForm.KeyPreview = true;
// ...
}
Then the form's _KeyDown, _KeyPress, and / or _KeyUp events can be marshaled to access input events before the focused form control ever sees them, and you can apply handler logic to capture the event there or allow it to pass through to the focused form control.
Although not as structurally graceful as XAML's event-routing architecture, it makes management of form-level functions in Winforms far simpler. See the MSDN notes on KeyPreview for caveats.
if (Form.ModifierKeys == Keys.Shift)
does work for a text box if the above code is in the form's keydown event and no other control captures the keydown event for the key down.
Also one may wish stop further key processing with:
e.Handled = true;
In WinForms:
if( Form.ModifierKeys == Keys.Shift )
It sounds like a duplicate of Stack Overflow question Detect Shift key is pressed without using events in Windows Forms?.
If you need to listen to keys in any generic class what are pressed when a 'Form' Window, this is your code. It doesnt listen to global windows key events, so it cannot be used to see keys when the window is not active.
Form.cs
public partial class Form1 : Form
{
public Form1()
{
// Some other Code
// Register all Keys pressed
this.KeyPreview = true;
KeyHandler.Instance.Init();
this.KeyDown += Form1_KeyDown;
this.KeyUp += Form1_KeyUp;
// Some other Code in the constructor
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
// Fire event when a key is released
KeyHandler.Instance.FireKeyUp(sender, e);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
// Fire event when a key is pressed
KeyHandler.Instance.FireKeyDown(sender, e);
}
}
KeyHandler.cs
KeyHandler is a Singleton Class and can be accessed in any other Object through Handler.Instance... Easy right.
public class KeyHandler
{
#region Singleton
private static KeyHandler instance;
private KeyHandler()
{
currentlyPressedKeys = new List<Keys>();
}
public static KeyHandler Instance
{
get
{
if (instance is null)
{
instance = new KeyHandler();
}
return instance;
}
}
#endregion Singleton
private List<Keys> currentlyPressedKeys;
public List<Keys> GetCurrentlyPressedKeys { get { return currentlyPressedKeys; } }
public void FireKeyDown(object sender, KeyEventArgs e)
{
if (!currentlyPressedKeys.Contains(e.KeyCode))
{
currentlyPressedKeys.Add(e.KeyCode);
KeyEventKeyPressed(sender, e);
}
}
public void FireKeyUp(object sender, KeyEventArgs e)
{
currentlyPressedKeys.Remove(e.KeyCode);
KeyEventKeyReleased(sender, e);
}
public event EventHandler<KeyEventArgs> KeyPressed;
protected virtual void KeyEventKeyPressed(object sender, KeyEventArgs e)
{
EventHandler<KeyEventArgs> handler = KeyPressed;
handler?.Invoke(sender, e);
}
public event EventHandler<KeyEventArgs> KeyReleased;
protected virtual void KeyEventKeyReleased(object sender, KeyEventArgs e)
{
EventHandler<KeyEventArgs> handler = KeyReleased;
handler?.Invoke(sender, e);
}
public void Init()
{
// Nothing to initialize yet
}
}
// In any other Class/Object its now possible to receive KeyEvents that are fired when the 'Form' is active. So its possible to listen to key events in any Control object or anything else. Its possible to see if e.g. multiple keys are pressed like Shift+Ctrl+Q or something like that.
public class SomeClass
{
public SomeClass()
{
KeyHandler.instance.KeyPressed += Instance_KeyPressed
KeyHandler.Instance.KeyReleased += Instance_KeyReleased;
}
public void SomeMethod()
{
if (KeyHandler.Instance.GetCurrentlyPressedKeys.Contains(Keys.ShiftKey))
{
// Do Stuff when the method has a key (e.g. Shift/Control...) pressed
}
}
private void Instance_KeyPressed(object sender, KeyEventArgs e)
{
// Any Key was pressed, do Stuff then
}
private void Instance_KeyReleased(object sender, KeyEventArgs e)
{
// Do Stuff when a Key was Released
}
}

Categories

Resources