Forward a KeyPress-event - c#

I have a TextBox and would like to forward a KeyPress-event from another Form.
So far I have my Form:
private readonly Action<KeyPressEventArgs> m_KeyPress;
public KeyboardForm( Action<KeyPressEventArgs> keyPress )
{
m_KeyPress = keyPress;
}
protected override void OnKeyPress( KeyPressEventArgs e )
{
m_KeyPress( e );
base.OnKeyPress( e );
}
And a derived TextBox, which initializes the Form:
var keyboardForm = new KeyboardForm( OnKeyPress );
keyboardForm.Show();
Now, the OnKeyPress-method gets called as expected (of the Form, then of the TextBox). But nevertheless nothing happens ... when I press 'a' I expected an 'a' to appear in my TextBox ...
Does anyone have an idea what's the problem here?
It is not working with KeyDown, too, and attaching to the regular exposed event KeyPress does not help me either. I think, that the problem is the explicit call of OnKeyPress. Is it allowed?

Form1:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
Form2 f = new Form2();
f.mEvent += new Form2.TestEvent(f_mEvent);
f.Show();
}
void f_mEvent(KeyPressEventArgs e)
{
textBox1.Text += e.KeyChar;
}
}
Form2:
public partial class Form2 : Form
{
public delegate void TestEvent(KeyPressEventArgs e);
public event TestEvent mEvent;
public Form2()
{
InitializeComponent();
}
protected override void OnKeyPress(KeyPressEventArgs e)
{
if (mEvent != null)
{
mEvent(e);
}
base.OnKeyPress(e);
}
}

This should do what you want. Make the text of the buttons on the Keyboard Form based on the SendKey characters. For example, if you want lower case a, just put "a" for the keyboard button text. If you want a backspace button, just put "backspace" as the text of the button. All the keyboard buttons Click events can register for the ButtonClick function
Keyboard Form:
public partial class KeyboardForm : Form
{
public delegate void ButtonPressed(string keyPressed);
public event ButtonPressed ButtonPressedEvent;
public KeyboardForm()
{
InitializeComponent();
}
private void ButtonClick(object sender, EventArgs e)
{
Button button = sender as Button;
if (button != null)
{
if ((ButtonPressedEvent != null))
{
ButtonPressedEvent("{"+button.Text+"}");
}
}
}
}
Form with textbox that the user types things into:
public partial class Form1 : Form
{
private KeyboardForm mKeyboardForm = new KeyboardForm();
private bool mIsKeyboardCode = false;
public Form1()
{
InitializeComponent();
mKeyboardForm.ButtonPressedEvent += new KeyboardForm.ButtonPressed(KeyboardFormButtonPressedEvent);
}
void KeyboardFormButtonPressedEvent(string keyPressed)
{
mIsKeyboardCode = true;
textBox1.Focus();
SendKeys.SendWait(keyPressed.ToString());
mKeyboardForm.Focus();
mIsKeyboardCode = false;
}
private void TextBoxKeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.ControlKey)
{
if (!mKeyboardForm.Visible)
{
mKeyboardForm.Show(this);
e.Handled = true;
}
}
else if (!mIsKeyboardCode)
{
mKeyboardForm.Hide();
}
}
}
Note: I did not use an extended textbox with a form inside of it. I dont think its a good design to have a form be shown/hidden from a custom textbox.

From this answer: https://social.msdn.microsoft.com/Forums/windows/en-US/92215fdf-8be0-4e3a-b796-dd7c0f131666/keypreview-true-how-do-you-then-detect-enterreturn?forum=winforms
If you have a button on your form that is catching the Enter key presses, you can allow the enter key to be handled as a normal KeyPreview key with the following code:
void button_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyData == Keys.Enter)
{
e.IsInputKey = true;
}
}

Related

Cannot implicitly convert type 'bool' to System.Windows.Forms.RadioButton

public partial class Form2 : Form
{
public bool male {get; set;}
{
InitializeComponent();
}
private void Form2_Load(object sender, EventArgs e)
{
maleGender_rb1 = male;
}
}
I want to display the radio buttton result from form1 to form2 using also radio buttons
The best solution is to setup an event in the child form and for the RadioButton controls subscribe to CheckedChanged. The CheckedChange event determines which RadioButton was checked and sends notification to any listeners.
Child form:
namespace PassStringFromChildToParentForm
{
public partial class ChildForm : Form
{
public delegate void OnPassData(bool isMale);
public event OnPassData PassData;
public ChildForm()
{
InitializeComponent();
MaleRadioButton.Checked = true;
MaleRadioButton.CheckedChanged += RadioButton_CheckedChanged;
FemaleRadioButton.CheckedChanged += RadioButton_CheckedChanged;
}
private void RadioButton_CheckedChanged(object sender, EventArgs e)
{
var radioButton = (RadioButton)sender;
if (radioButton.Checked)
{
PassData?.Invoke(radioButton == MaleRadioButton);
}
}
public void UpdateRadioButton(bool isMale)
{
if (isMale)
{
MaleRadioButton.Checked = true;
}
else
{
FemaleRadioButton.Checked = true;
}
}
}
}
Main Form:
Here we subscribe to the child form event and determine which RadioButton to check based on the bool value passed.
namespace PassStringFromChildToParentForm
{
public partial class MainForm : Form
{
private ChildForm _childForm;
public MainForm()
{
InitializeComponent();
MaleRadioButton.CheckedChanged += RadioButton_CheckedChanged;
FemaleRadioButton.CheckedChanged += RadioButton_CheckedChanged;
}
private void RadioButton_CheckedChanged(object sender, EventArgs e)
{
if (Application.OpenForms.OfType<ChildForm>().Count() != 1) return;
var radioButton = (RadioButton)sender;
if (!radioButton.Checked) return;
if (!radioButton.Checked) return;
_childForm.UpdateRadioButton(MaleRadioButton.Checked);
}
private void ShowChildForm_Click(object sender, EventArgs e)
{
_childForm = new ChildForm();
_childForm.PassData += ChildForm_PassData; ;
_childForm.Show(this);
}
private void ChildForm_PassData(bool isMale)
{
if (isMale)
{
MaleRadioButton.Checked = true;
}
else
{
FemaleRadioButton.Checked = true;
}
}
}
}
You can't convert bool to RadioButton. I think you need to use Checked property of radio button to pass boolean value to it.
For example:
maleGender_rb1.Checked = true;// or false

C# WinForms. Enable control from another class

In my program, I have two forms: public partial class Form1 : Form,
and a log-in form: public partial class Login : Form. Both within the same namespace
Login window is opened when a Log-in button is clicked on the main window:
public partial class Form1 : Form
{
private void LoginToolStripMenuItem_Click(object sender, EventArgs e) //Login button event
{
LoginWindow = new Login();
LoginWindow.ShowDialog();
LogOutToolStripMenuItem.Enabled = true;
}
}
When the password is entered, I want to enable additional controls for the user, on the main screen.
groupBox2 is invisible by default, now I would like to make it visible:
public partial class Login : Form
{
public Login()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e) //Confirm click event
{
if (textBox1.Text == Form1.password) //Here, no trouble accessing a string from the main screen
{
Form1.groupBox2.Visible = true; //********** Here is my problem **********
Form1.LoginWindow.Close();
}
else
{
textBox1.Text = "Incorrect password";
textBox1.SelectAll();
}
}
}
How do I overcome "An object reference is required for the non-static field, method or property 'Form1.groupBox2' problem?
All my controls are already set to public.
I'm reading and reading and can't figure it out, it's driving me mad now.
I'm not expecting a ready solution, just a good explanation.
You can just raise a event on your login form like this:
public partial class Login : Form
{
public EventHandler OnPasswordDone; // declare a event handler
public Login()
{
InitializeComponent();
}
public void button1_Click(object sender, EventArgs e)
{
if (textBox1.Text == Form1.password)
{
// raise the event to notify main form
OnPasswordDone(this, new EventArgs());
}
else
{
textBox1.Text = "Incorrect password";
textBox1.SelectAll();
}
}
}
And in your main form:
public partial class Form1 : Form
{
private void LoginToolStripMenuItem_Click(object sender, EventArgs e) //Login button event
{
LoginWindow = new Login();
LoginWindow.OnPasswordDone += Login_PasswordDone; // regist your event here
LoginWindow.ShowDialog();
LogOutToolStripMenuItem.Enabled = true;
}
private void Login_PasswordDone(object sender, EventArgs e)
{
//Do what you need to do here like:
groupBox2.Visible = true;
}
}
Since Form1 is not static class , so you should create object of this class then set visible to true like as
Form1 formobj=new Form1();
formobj.groupBox2.Visible = true;

How to have Main form's menu process events on OwnedForms?

I have a Main Form with a MenuStrip on it, and I use that MenuStrip to open new owned Forms like so:
var target = new Target();
target.Owner = this;
target.Show();
This works exactly how I want it to: the Forms are always shown in front of the Main Form.
The issue that I run into is that, when one of these owned Forms has the focus, I can't access the MenuStrip via keyboard. I'd like CTRL+S to trigger the Save functionality, the same as it does when the Main Form has the focus.
Is this possible? Is there a better way to approach this?
Sorry for the delay, but if you're still having issues or looking for a different method, see below.
In your MainForm:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
ChildForm child = new ChildForm();
// KeyPreview can be set in the properties of the child form instead
child.KeyPreview = true;
child.KeyPressed += Child_KeyPressed;
child.ShowDialog();
}
private void Child_KeyPressed(object sender, KeyEventArgs e)
{
if (e.Control && e.KeyCode == Keys.S)
{
// Save Pressed
}
}
}
and then in your Child Form:
public partial class ChildForm : Form
{
public event EventHandler<KeyEventArgs> KeyPressed;
public ChildForm()
{
InitializeComponent();
}
private void Child1_KeyUp(object sender, KeyEventArgs e)
{
KeyPressed?.Invoke(sender, e);
}
}
Thanks to Troy Mac1ure for the direction. Here's the solution that lets me use the ShortCutKeys from the main menu.
ownedForm.KeyPreview = true;
ownedForm.KeyDown += OwnedForm_KeyDown;
private void OwnedForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.Control)
{
foreach (ToolStripMenuItem menuItem in menu.Items)
{
foreach (ToolStripMenuItem item in menuItem.DropDownItems.OfType<ToolStripMenuItem>())
{
if (item.ShortcutKeys == e.KeyData)
{
item.PerformClick();
return;
}
}
}
}
}
This doesn't handle Alt menu activation, but Paint.NET doesn't handle that either, so I view that as a nice-to-have.

Why does MessageBox be run several times in this code?

I'm a newbie in programming and writing codes.
I have a very simple form with 6 buttons.
When I click on every button only the sender's text got Magenta.
But Button3 do a further work and that's opening a "Hello" messageBox.
The problem is when I click on Button3, it shows "hello" string 4 times. Why?
I think and expect it show it just once no more.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Typhok(object sender, EventArgs e)
{
foreach (Control x in this.Controls)
{
if (x.Equals(sender))
x.ForeColor = Color.Magenta;
else
x.ForeColor = Color.Black;
}
b3.Click += new EventHandler(Popup);
}
private void Popup(object sender, EventArgs e)
{
MessageBox.Show("hello!");
}
}
UPDATE: Can anyone explain to me why that original code had that problem?
Register event handler in constructor, not in Typhok method. The final code should look like:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
b3.Click += new EventHandler(Popup);
}
private void Typhok(object sender, EventArgs e)
{
foreach (Control x in this.Controls)
{
if (x.Equals(sender))
x.ForeColor = Color.Magenta;
else
x.ForeColor = Color.Black;
}
}
private void Popup(object sender, EventArgs e)
{
MessageBox.Show("hello!");
}
}

Counting every mouseclick on a form and its elements

I want to count all the mouseclicks that are made in a window. I want the counter to increase on every single object i click on, even if its a button, the form it self or a textbox etc. etc.
I have this so far but I cant seem to get it to work:
int mouseCounter = 0;
private void Form1_Load(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
c.Click += ClickCounter;
}
}
void ClickCounter(object sender, EventArgs e)
{
mouseCounter++;
label8.Text = mouseCounter.ToString();
}
The counter only respond to click on the controls for now and not the form it self. How can I simply fix that?
You may use a message filter, to filter out mouse clicks on your (main)form.
You basically get the message before it is dispatched to the control and may do whatever you want (in your case: increase a counter).
The return value of PreFilterMessage(ref Message m) determines wether the message will be dispatched to the control: false means you didn't filter the message and it will be dispatched.
See the documentation for details.
public partial class Form1 : Form, IMessageFilter
{
public Form1()
{
InitializeComponent();
label1.Text = "0";
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == 0x201) //wm_lbuttondown
{
label1.Text = "" + (Int32.Parse(label1.Text) + 1);
}
return false;
}
}
Tested with .NET4.0 and a form full of various controls.
You have to use some Application-Wide Click message with an IMessageFilter like this:
public partial class Form1 : Form, IMessageFilter
{
int mouseCounter;
public Form1()
{
InitializeComponent();
Application.AddMessageFilter(this);
}
public bool PreFilterMessage(ref Message msg)
{
if(msg.Msg == 0x202) //WM_LBUTTONUP
{
mouseCounter++;
label8.Text = mouseCounter.ToString();
}
return false;
}
}
Use this:
namespace TicTacToe
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
button1.Visible = false;
}
}
}

Categories