KeyDown and KeyUp Events inside "Custom Control" - c#

I have a custom control derived from control. The mouse events, such as OnMouseLeftButtonDown (MouseButtonEventArgs e), can be used without any problems. Now I would like a combination of e.g. left-ctrl and left mouse click. But I just can't manage to respond to keyboard events in my "custom control".
Can someone give me a hint how to implement this?
This overriden method works fine.
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
if (isKeyCtrlDown)
{
Debug.WriteLine("Test");
}
}
And this overriden methods will not fired.
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.LeftCtrl)
{
isKeyCtrlDown = true;
}
}
protected override void OnKeyUp(KeyEventArgs e)
{
base.OnKeyUp(e);
if (Keyboard.IsKeyUp(Key.LeftCtrl))
{
isKeyCtrlDown = false;
}
}
Thanks for any help.

Related

UserControl OnMouseWheel fires but other events do not

I have some basic override code in the same class to catch mouse events. I can get OnMouseWheel to fire, but other click events do to not fire with the same code.
protected override void OnMouseDown(System.Windows.Forms.MouseEventArgs e)
{
Debug.WriteLine("mouse down"); //does not work
}
protected override void OnMouseWheel(System.Windows.Forms.MouseEventArgs e)
{
Debug.WriteLine("mouse wheel"); //works
}
Does OnMouseWheel need focus to fire? That has been what I have been trying to troubleshoot so far.
protected override void OnMouseClick ( MouseEventArgs e )
{
Debug.WriteLine("Mouse click"); //works
}
private void panel1_MouseClick ( object sender, MouseEventArgs e )
{
OnMouseClick(e);
}
In your actual design window make sure you attached the event to the Control. If you need to do it programatically, then
this.panel1.MouseClick += new System.Windows.Forms.MouseEventHandler(this.panel1_MouseClick);
Note:
Yes I know the control names aren't the exact same and you aren't using MetroControls, but it's the same idea.
You need to call the base method implementation of OnMouse events so the base class can react to the events:
protected override void OnMouseDown(MouseEventArgs e)
{
Debug.WriteLine("OnMouseDown");
base.OnMouseDown(e);
}
protected override void OnMouseUp(MouseEventArgs e)
{
Debug.WriteLine("OnMouseUp");
base.OnMouseUp(e);
}
protected override void OnMouseWheel(MouseEventArgs e)
{
Debug.WriteLine("OnMouseWheel");
base.OnMouseWheel(e);
}

How to use the back function in UWP apps to change visibility of a grid?

I would like to use the back function in the UWP in the App.xaml.cs file to change the visibility property of a grid (grid1) on the MainPage.xaml file.
//Go Back
public void App_BackRequested(object sender, Windows.UI.Core.BackRequestedEventArgs e)
{
if(MainPage.MyGlobals.pageLocation == 0)
{
//Do Nothing
}
else if(MainPage.MyGlobals.pageLocation == 1)
{
MainPage.grid1.Visibility = Visibility.Collapsed;
MainPage.MyGlobals.pageLocation = 0;
}
}
I know it's not typical practice to change xaml elements' properties from a different page, but I would really like to change how the back feature works in this app. I believe I have to make the grid pubic, but even when I (thought I) found a way to do that I still couldn't change the properties of the grid with the way I have it written in my code.
As you've mentioned, changing XAML elements' properties from a different page is not a good practice. We can just use SystemNavigationManager.BackRequested event in MainPage like following to change the visibility of a grid.
protected override void OnNavigatedTo(NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().BackRequested += Page_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
SystemNavigationManager.GetForCurrentView().BackRequested -= Page_BackRequested;
}
private void Page_BackRequested(object sender, BackRequestedEventArgs e)
{
if (MyGrid.Visibility == Visibility.Visible)
{
MyGrid.Visibility = Visibility.Collapsed;
e.Handled = true;
}
else
{
if (this.Frame.CanGoBack)
{
this.Frame.GoBack();
e.Handled = true;
}
}
}
And if you want to take advantage of the back function in App.xaml.cs and use a different function in MainPage, you can add a event in App that wraps SystemNavigationManager.BackRequested to allow other pages to override the default behavior by subscribing to this event like following:
public event EventHandler<BackRequestedEventArgs> BackRequested;
private void App_BackRequested(object sender, BackRequestedEventArgs e)
{
BackRequested?.Invoke(sender, e);
Frame rootFrame = Window.Current.Content as Frame;
if (!e.Handled && rootFrame != null && rootFrame.CanGoBack)
{
rootFrame.GoBack();
e.Handled = true;
}
}
Then in MainPage, subscribe and unsubscribe this event like:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
(Application.Current as App).BackRequested += Page_BackRequested;
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
(Application.Current as App).BackRequested -= Page_BackRequested;
}
It doesn't work because you're trying to access the Grid as if it was a static property of the MainPage. You need a reference to the MainPage instance to manipulate the Grid, but all in all it is a really bad practice. You should have a look at the UWP/WP 8.1 navigation events.

wpf extending control with keyboard override

I'm extending the control canvas and adding my own custom overrides for MouseEvents. I was curious to know why this basic override which is when the user presses any key on the keyboard it doesn't emit a signal. How can I make this override work in wpf c#?
namespace CanvasGraphDemo
{
public class CanvasGraph : Canvas
{
public CanvasGraph()
{
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Enter)
{
Console.WriteLine("context menu open");
e.Handled = true;
}
}
}
}
This will work with your specific example. As others noted, you have to make the Canvas focusable and actually focus it, so it will receive keyboard events.
public class CanvasGraph : Canvas
{
public CanvasGraph()
{
Focusable = true;
Loaded += OnCanvasGraphLoaded;
}
private void OnCanvasGraphLoaded(object sender, RoutedEventArgs routedEventArgs)
{
Focus();
Loaded -= OnCanvasGraphLoaded;
}
protected override void OnKeyDown(KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.Key == Key.Enter)
{
Console.WriteLine("context menu open");
e.Handled = true;
}
}
}

Text Box User Control in C# Windows Application?

In my User Control I have a Text Box which does the validation to take only digits. I place this user control on my form but the Keypress event is not Firing in form.Following is the code in my user control
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (this.KeyPress != null)
this.KeyPress(this, e);
}
private void txtLocl_KeyPress(object sender, KeyPressEventArgs e)
{
if (e.KeyChar!=(char)Keys.Back)
{
if (!char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
}
but in Form also i want keypress event to fire but it is not firing
public Form1()
{
InitializeComponent();
txtNum.KeyPress += new KeyPressEventHandler(txtPrprCase1_KeyPress);
}
void txtPrprCase1_KeyPress(object sender, KeyPressEventArgs e)
{
MessageBox.Show("KeyPress is fired");
}
but it is not firing. I don't understand what i want to do? It is Urgent for me.
This following override is not needed:
protected override void OnKeyPress(KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (this.KeyPress != null)
this.KeyPress(this, e);
}
Because base.OnKeyPress(e); will fire the attached event. You don't need to do it manually.
Instead call OnKeyPress of user control in the text-box's event handler:
private void txtLocl_KeyPress(object sender, KeyPressEventArgs e)
{
base.OnKeyPress(e);
if (e.KeyChar!=(char)Keys.Back)
{
if (!char.IsDigit(e.KeyChar))
{
e.Handled = true;
}
}
}
Try putting the event handler code in your Form_Load event, or using the Form Designer to create the event handler (it's in the lightning icon on the properties page).

Is there a way to catch when ContainsFocus changes?

I need to be able to determine when ContainsFocus changes on a Control (specifically a windows form). Overriding OnGotFocus is not the answer. When I bring the form to the foreground, ContainsFocus is true and Focused is false. So is there an OnGotFocus equivalent for ContainsFocus? Or any other way?
Note: GotFocus events of the child controls are fired if you have a child control. Otherwise OnGotFocus of the form is called.
If I understood the question correctly, then this should work:
bool lastNotificationWasGotFocus = false;
protected override void OnControlAdded(ControlEventArgs e)
{
SubscribeEvents(e.Control);
base.OnControlAdded(e);
}
protected override void OnControlRemoved(ControlEventArgs e)
{
UnsubscribeEvents(e.Control);
base.OnControlRemoved(e);
}
private void SubscribeEvents(Control control)
{
control.GotFocus += new EventHandler(control_GotFocus);
control.LostFocus += new EventHandler(control_LostFocus);
control.ControlAdded += new ControlEventHandler(control_ControlAdded);
control.ControlRemoved += new ControlEventHandler(control_ControlRemoved);
foreach (Control innerControl in control.Controls)
{
SubscribeEvents(innerControl);
}
}
private void UnsubscribeEvents(Control control)
{
control.GotFocus -= new EventHandler(control_GotFocus);
control.LostFocus -= new EventHandler(control_LostFocus);
control.ControlAdded -= new ControlEventHandler(control_ControlAdded);
control.ControlRemoved -= new ControlEventHandler(control_ControlRemoved);
foreach (Control innerControl in control.Controls)
{
UnsubscribeEvents(innerControl);
}
}
private void control_ControlAdded(object sender, ControlEventArgs e)
{
SubscribeEvents(e.Control);
}
private void control_ControlRemoved(object sender, ControlEventArgs e)
{
UnsubscribeEvents(e.Control);
}
protected override void OnGotFocus(EventArgs e)
{
CheckContainsFocus();
base.OnGotFocus(e);
}
protected override void OnLostFocus(EventArgs e)
{
CheckLostFocus();
base.OnLostFocus(e);
}
private void control_GotFocus(object sender, EventArgs e)
{
CheckContainsFocus();
}
private void control_LostFocus(object sender, EventArgs e)
{
CheckLostFocus();
}
private void CheckContainsFocus()
{
if (lastNotificationWasGotFocus == false)
{
lastNotificationWasGotFocus = true;
OnContainsFocus();
}
}
private void CheckLostFocus()
{
if (ContainsFocus == false)
{
lastNotificationWasGotFocus = false;
OnLostFocus();
}
}
private void OnContainsFocus()
{
Console.WriteLine("I have the power of focus!");
}
private void OnLostFocus()
{
Console.WriteLine("I lost my power...");
}
One way to solve this is to use a Timer. It's definitely brute force, but it gets the job done:
private Timer m_checkContainsFocusTimer = new Timer();
private bool m_containsFocus = true;
m_checkContainsFocusTimer.Interval = 1000; // every second is good enough
m_checkContainsFocusTimer.Tick += new EventHandler(CheckContainsFocusTimer_Tick);
m_checkContainsFocusTimer.Start();
private void CheckContainsFocusTimer_Tick(object sender, EventArgs e)
{
if (!m_containsFocus && ContainsFocus)
OnAppGotFocus();
m_containsFocus = ContainsFocus;
}
But is there an easier way?
Handling the GotFocus and LostFocus events should do it.
Another thing to note... the SDK says this about the ContainsFocus property:
You can use this property to determine
whether a control or any of the
controls contained within it has the
input focus. To determine whether the
control has focus, regardless of
whether any of its child controls have
focus, use the Focused property.
EDIT:
When handling the GotFocus event, you may still have to check the Focused/ContainsFocus property depending on how the hierarchy of your controls is set up.
ContainsFocus will be true if the control or any of its children have focus.
Focus will only be true if the specific control itself has focus, regardless of its children.

Categories

Resources