I have added a Windows Media control to my form and have been able to use it perfectly except when it is in the fullscreen state. It seems that I am unable to manipulate any aspects of the control through key events within my application. My current goal is to handle 'esc' key down to exit out of full screen. I can do more from there on.
If you have any idea please let me know!
Thanks, Kevin
I once found this code somewhere and worked pretty well, but don't remember where i got it from.
public partial class WMForm : Form,IMessageFilter
{
public WMForm()
{
InitializeComponent();
}
private void WMForm_Load(object sender, EventArgs e)
{
this.MyWindowsMediaPlayer.URL = #"YourFilePath/Url";
Application.AddMessageFilter(this);
}
private void WMForm_FormClosing(object sender, FormClosingEventArgs e)
{
Application.RemoveMessageFilter(this);
}
#region IMessageFilter
private const UInt32 WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_KEYDOWN)
{
Keys keyCode = (Keys)(int)m.WParam & Keys.KeyCode;
if (keyCode == Keys.Escape)
{
this.MyWindowsMediaPlayer.fullScreen = false;
}
return true;
}
return false;
}
#endregion
}
Related
So, apparently I had some problem when handling keys such as F10 or F11.
I want to move the focus from current textbox into another textbox, but not in one particular textbox. So, I wrote some code to handle key:
private void checkKeys(KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
buyerName.Focus();
}
else if (e.KeyCode == Keys.F11)
{
discount.Focus();
}
}
But, if I put this into individual textbox, which kinda hassle to me. Is there any method to listen key whether in global userControl or textbox?
Edit : here's my structure that I want to ask :
Form-
|-User Control
|-TextBox
Edit 2 : here's some image might help img
To use a global keyboard listener in Winforms, you just need to add a handler to KeyUp action for the main form itself:
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
textBox1.Focus();
e.Handled = true; //To use F10, you need to set the handled state to true
} else if (e.KeyCode == Keys.F11)
{
textBox2.Focus();
}
}
Then make sure that the KeyPreview property on the main form is set to True.
The issue with the application freezing when pressing F10 is because it is waiting for another consecutive action. To bypass this simply set the Handled property on the keyevent to TRUE. This releases the unresolved event.
This is my entire form class, refactored to use a helper method as you are refering to. This works fine. But you have to make sure that the KeyPreview property on your form is True, unless your keypresses will not be matched to your event handlers.
namespace KeyTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
CheckKeys(e);
}
private void CheckKeys(KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
textBox1.Focus();
e.Handled = true;
}
else if (e.KeyCode == Keys.F11)
{
textBox2.Focus();
e.Handled = true;
}
}
}
}
Now in your comment you are mentioning a UserControl, if you want that, then you need to create an instance method on your UserControl class, and pass the event to that from your global keyboard event handler on your main form.
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public void HandleKeys(KeyEventArgs e)
{
if (e.KeyCode == Keys.F10)
{
textBox1.Focus();
e.Handled = true;
}
else if (e.KeyCode == Keys.F11)
{
textBox2.Focus();
e.Handled = true;
}
}
}
Then on your main form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void Form1_KeyUp(object sender, KeyEventArgs e)
{
CheckKeys(e);
}
private void CheckKeys(KeyEventArgs e)
{
uc1.HandleKeys(e); //Instance method on your user control.
}
}
This then works as intended.
As pointed out in one of the comments, a better way would be to override the ProcessCmdKey method on the Form base class. This would be done like so:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
userControl11.HandleKeys(keyData); // method on the userControl to handle the key code.
base.ProcessCmdKey(ref msg, keyData);
return true;
}
}
The handler on the UserControl stays more or less the same:
public void HandleKeys(Keys keys)
{
if (keys == Keys.F10)
{
nameTB.Focus();
} else if (keys == Keys.F11)
{
emailTB.Focus();
}
}
Whether this is a more correct way of doing it, I am unsure of. They certainly both accomplish the same result. The documentation shows the first method in for handling keyboard events at the form level here:
How to handle keyboard input
But states here that the ProcessCmdKey method is to provide additional handling of shortcuts and MDI accellerators.
ProcessCmdKey
I will leave that up to you to decide what is the best for your scenario. But keep it in to show how you would use it should you choose to.
You can hook up to the KeyUp event of your form.
That way, any key pressed while your form is focused will be send to you (if the control didn't handle the key).
Thanks to #Espen and #reza-aghaei for handling keys into main form. Unfortunately, I still didn't managed find a way to focus to designated textbox inside a UserControl. However, I make some dirty method which kinda crappy and un-efficient by searching child control from it's parent
//MainForm.cs
if(yourUserControl.Name)//Do some check for targeted userControl, if null can cause NullReferenceException
{
if (e.KeyCode == Keys.F10)
{
this.Controls.Find("textboxName", true).First().Focus();
e.Handled = true;
}
}
Is there a way to distinguish whether the Enter event on a control was raised by keyboard (Tab, Shift+Tab) or by direct mouse click?
I need to perform an action only when the user is moving to the control using Tab, but not when the user directly clicks on the control. I have tried to intercept the mouse click directly, but it seems the Enter event is raised before Click.
Instead of tracking the Tab key, you can use the WM_MOUSEACTIVATE message to detect activation of the control with the mouse. You could either sub-class each control type you use and override the WndProc method or use a NativeWindow listener class like the one presented below. Depending on how many types of controls you use, it may be less work and clutter to just sub-class those controls to provide a property that indicates that the control was selected using the mouse. It is your decision to make, but the pattern will be the same.
This code is a slight modification of the example shown in the MS documentation.
public class MouseActivateListener : NativeWindow
{
private Control parent;
public MouseActivateListener(Control parent)
{
parent.HandleCreated += this.OnHandleCreated;
parent.HandleDestroyed += this.OnHandleDestroyed;
parent.Leave += Parent_Leave;
this.parent = parent;
if (parent.IsHandleCreated)
{
AssignHandle(parent.Handle);
}
}
private void Parent_Leave(object sender, EventArgs e)
{
MouseActivated = false;
}
private void OnHandleCreated(object sender, EventArgs e)
{
AssignHandle(((Form)sender).Handle);
}
private void OnHandleDestroyed(object sender, EventArgs e)
{
ReleaseHandle();
}
public bool MouseActivated { get; set; }
[System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
protected override void WndProc(ref Message m)
{
const Int32 WM_MouseActivate = 0x21;
base.WndProc(ref m);
if (m.Msg == WM_MouseActivate && m.Result.ToInt32() < 3)
{
MouseActivated = true;
}
}
}
Example Usage:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private MouseActivateListener textBox1Listener;
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
textBox1Listener = new MouseActivateListener(textBox1);
}
private void textBox1_Enter(object sender, EventArgs e)
{
if (textBox1Listener.MouseActivated)
{
MessageBox.Show("Mouse Enter");
}
else
{
MessageBox.Show("Tab Enter");
}
}
}
You can use the Form.KeyPreview event and store the last key press in a variable. Then in your control's Enter event, check the value of the key that was pressed last. If this is a tab, do whatever you need to:
private Keys lastKeyCode;
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
this.lastKeyCode = e.KeyCode;
}
Then in the Enter event, check it:
if (lastKeyCode == Keys.Tab)
{
// Whatever...
}
Intercepting WM_KEYUP and WM_KEYDOWN directly with a message filter to retrieve the state of the Tab key worked. This seems excessive for such a seemingly straightforward task, but apparently the Tab key is suppressed from most windows forms events.
Would be happy to take a cleaner answer, but for now, this is it:
class TabMessageFilter : IMessageFilter
{
public bool TabState { get; set; }
public bool PreFilterMessage(ref Message m)
{
const int WM_KEYUP = 0x101;
const int WM_KEYDOWN = 0x100;
switch (m.Msg)
{
case WM_KEYDOWN:
if ((Keys)m.WParam == Keys.Tab) TabState = true;
break;
case WM_KEYUP:
if ((Keys)m.WParam == Keys.Tab) TabState = false;
break;
}
return false;
}
}
class MainForm : Form
{
TabMessageFilter tabFilter;
public MainForm()
{
tabFilter = new TabMessageFilter();
Application.AddMessageFilter(tabFilter);
}
protected override void OnFormClosed(FormClosedEventArgs e)
{
Application.RemoveMessageFilter(tabFilter);
base.OnFormClosed(e);
}
void control_Enter(object sender, EventArgs e)
{
if (tabFilter.TabState) // do something
else // do domething else
}
}
I was looking for an answer and found an almost complete one by #LarsTech but without the exception :
https://stackoverflow.com/a/21314496/7026554
//You can still use MessageFilter and just filter for the ActiveForm:
private class MouseDownFilter : IMessageFilter {
public event EventHandler FormClicked;
private int WM_LBUTTONDOWN = 0x201;
private Form form = null;
[DllImport("user32.dll")]
public static extern bool IsChild(IntPtr hWndParent, IntPtr hWnd);
public MouseDownFilter(Form f) {
form = f;
}
public bool PreFilterMessage(ref Message m) {
if (m.Msg == WM_LBUTTONDOWN) {
if (Form.ActiveForm != null && Form.ActiveForm.Equals(form)) {
OnFormClicked();
}
}
return false;
}
protected void OnFormClicked() {
if (FormClicked != null) {
FormClicked(form, EventArgs.Empty);
}
}
}
//Then in your form, attach it:
public Form1() {
InitializeComponent();
MouseDownFilter mouseFilter = new MouseDownFilter(this);
mouseFilter.FormClicked += mouseFilter_FormClicked;
Application.AddMessageFilter(mouseFilter);
}
void mouseFilter_FormClicked(object sender, EventArgs e) {
// do something...
}
What I want is to hide the notifications panel but not when clicking on its content or the profile picture that shows it.
I have a procedure called NotificationVisible(bool IsVisible)
Any help is greatly appreciated.
So your mouseFilter_FormClicked fires whenever user clickes on form. Now the only thing you need to do is to detect the control that is placed behind the mouse cursor and with that you can deside whether you need to hide your panel or not.
You can do this with WindowFromPoint method. Check this thread.
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr WindowFromPoint(Point pnt);
void mouseFilter_FormClicked(object sender, EventArgs e) {
IntPtr hWnd = WindowFromPoint(Control.MousePosition);
if (hWnd != IntPtr.Zero) {
Control ctl = Control.FromHandle(hWnd);
if (ctl != YourPanelControl) {
HideThePanel();
}
}
}
Are there some ways to check charater in clipboard only digit before paste into textbox C# (Both Ctrl+V and right click -> Paste), which not using MarkedTextbox.
Add rule in textbox text change to accept number only like:
private string value;
private void textBox1_TextChanged(object sender, EventArgs e)
{
// at this moment value is still old
var oldValue = value;
if (System.Text.RegularExpressions.Regex.IsMatch(textBox1.Text, "[^0-9]"))
{
MessageBox.Show("Please enter numbers only.");
textBox1.Text = oldvalue;
}
else{
value = ((TextBox)sender).Text;
}
}
I ~think~ you want a TextBox that can only accept digits?
If yes, then set the ES_NUMBER style on the TextBox via SetWindowLong():
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += Form2_Load;
}
private void Form1_Load(object sender, EventArgs e)
{
SetNumbersOnlyTextBox(this.textBox1);
}
public const int GWL_STYLE = (-16);
public const int ES_NUMBER = 0x2000;
[System.Runtime.InteropServices.DllImport("user32.dll", SetLastError = true)]
static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
public void SetNumbersOnlyTextBox(TextBox TB)
{
SetWindowLong(TB.Handle, GWL_STYLE, GetWindowLong(TB.Handle, GWL_STYLE) | ES_NUMBER);
}
}
Alternatively, you can Inherit from TextBox and set ES_NUMBER in CreateParams():
public class IntegerTextBox : TextBox
{
private const int ES_NUMBER = 0x2000;
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style = cp.Style | ES_NUMBER;
return cp;
}
}
}
I doubt there are anyways to check before pasting to TextBox, I would suggest subscribing to KeyDown and MouseClick events, and writing your own logic.
protected override void OnKeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.V && e.Modifiers == Keys.Control)
{
// Your logic to read clipboard content and check length.;
}
}
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Right)
{
// You logic goes here.
}
}
You can get help from MSDN on how to read/write clipboard content.
If you literally want to only allow pastes that have digits only, then Inherit from TextBox and trap WM_PASTE, suppressing the message when desired:
public class DigitsOnlyOnPasteTextBox : TextBox
{
private const int WM_PASTE = 0x302;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_PASTE && Clipboard.ContainsText())
{
int i;
string txt = Clipboard.GetText();
foreach(char c in txt)
{
if (!char.IsNumber(c))
{
return;// suppress default behavior
}
}
}
base.WndProc(ref m); // allow normal processing of the message
}
}
I know that I can get the current state by WindowState, but I want to know if there's any event that will fire up when the user tries to minimize the form.
You can use the Resize event and check the Forms.WindowState Property in the event.
private void Form1_Resize ( object sender , EventArgs e )
{
if ( WindowState == FormWindowState.Minimized )
{
// Do some stuff
}
}
To get in before the form has been minimised you'll have to hook into the WndProc procedure:
private const int WM_SYSCOMMAND = 0x0112;
private const int SC_MINIMIZE = 0xF020;
[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
protected override void WndProc(ref Message m)
{
switch(m.Msg)
{
case WM_SYSCOMMAND:
int command = m.WParam.ToInt32() & 0xfff0;
if (command == SC_MINIMIZE)
{
// Do your action
}
// If you don't want to do the default action then break
break;
}
base.WndProc(ref m);
}
To react after the form has been minimised hook into the Resize event as the other answers point out (included here for completeness):
private void Form1_Resize (object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
// Do your action
}
}
I don't know of a specific event, but the Resize event fires when the form is minimized, you can check for FormWindowState.Minimized in that event
For people who search for WPF windows minimizing event :
It's a bit different. For the callback use WindowState :
private void Form1_Resize(object sender, EventArgs e)
{
if (WindowState == FormWindowState.Minimized)
{
// Do some stuff
}
}
The event to use is StateChanged (instead Resize):
public Main()
{
InitializeComponent();
this.StateChanged += Form1_Resize;
}