I'm trying to put together a small application in WPF (a media player) using Visual Studio 2012 Express for Desktop, and want to use the space bar to pause. Unfortunately, the space bar, as well as the enter key, seem to have a default behavior in which (just before they execute any commands I have programmed for them) they re-execute or re-raise the most recent event in the window (button clicks, keypresses, etc.).
I have tried overriding OnKeydown, OnKeyUp, OnPreviewKeyDown, and OnPreviewKeyUp in every combination, but no amount of overriding eliminates this behavior. I have also found that this is true in other WPF applications I wrote, and even in a Windows Forms application I put together a few months ago. Is this some default aspect of all applications built by Visual Studio? And more importantly, is there a way to get rid of it?
If you override OnPreviewKeyDown you can add the logic you want, then set e.Handled to true and this will prevent the event from bubbling up and causing the behavior you are seeing.
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter || e.Key == Key.Space)
{
//Your Logic
e.Handled = true;
}
}
Related
I have a datagrid in a Silverlight application. Clicking on the first row, and then pressing the Enter key causes the selection to move to the next row. I do not want this behavior - the Enter key is used for totally different purposes on this screen.
I realize that this is part of the editing framework, but I need a way to turn it off. I tried setting IsReadOnly to True (even though the control isn't technically read-only) and that didn't have any effect.
I attached to the datagrid KeyDown event but it's not called when the Enter key is pressed. It works fine for other keys.
I'm stumped. Thanks for your help.
Yeah, that's annoying.
As far as I know, the only option is to create your own control that inherits from DataGrid, and do what is needed before passing the event on to the base.
public class NewDataGrid : DataGrid
{
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
//do what is needed here
e.Handled = true;
}
base.OnKeyDown(e);
}
}
I have some RoutedCommands for commands like control-A, copy paste and they all work fine.
Then I added 4 more routedcommands to move object up down left and right in the canvas using arrowkeys, they sometimes works and sometime doesn't. At first I thought it was a Focus issue on the Canvas but I just found out that at the same time, all the other routedcommands like control-A works but arrowkeys doesn't.
I really have no idea what's going on here, they are identical routedcommands with different variable names, how come one works 100% of time and one only work 50% of time?
Working RoutedCommand:
_bindings.Add(new CommandBinding(DesignerCanvas.SelectAll, SelectAll_Executed));
SelectAll.InputGestures.Add(new KeyGesture(Key.A, ModifierKeys.Control));
private void SelectAll_Executed(object sender, ExecutedRoutedEventArgs e)
{
SelectionService.SelectAll();
}
Malfunctioning RoutedCommand:
_bindings.Add(new CommandBinding(DesignerCanvas.MoveDown, MoveDown_Executed));
MoveDown.InputGestures.Add(new KeyGesture(Key.Down));
private void MoveDown_Executed(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
var selectedItems = from item in SelectionService.CurrentSelection.OfType<DesignerItem>()
select item;
if (selectedItems.Count() > 0)
{
for (int i = 0; i < selectedItems.Count(); i++)
selectedItems.ElementAt(i).Top += Option.OptionSingleton.Sensitivity;
}
}
The malfunctioning RoutedCommand is just not firing sometimes, especially after I open some other window and come back to the canvas, then it will stop firing while other routedcommands are unaffected. Any ideas what's causing this weird behavior?
You can sometiems use very inclusive class event handlers to trace the route of an event:
EventManager.RegisterClassHandler(typeof(FrameworkElement), CommandManager.CanExecuteEvent,
new CanExecuteRoutedEventHandler((s, e) => Debug.WriteLine("CanExecute: " + s)), true);
EventManager.RegisterClassHandler(typeof(FrameworkElement), CommandManager.ExecutedEvent,
new CanExecuteRoutedEventHandler((s, e) => Debug.WriteLine("Executed:" + s)), true);
EventManager.RegisterClassHandler(typeof(FrameworkElement), CommandManager.ExecutedEvent,
new CanExecuteRoutedEventHandler((s, e) => Debug.WriteLine("KeyDown:" + s)), true);
In your case the KeyDown may be handled before it reaches the command binding or the CanExecute event may not reach it for some other reason.
Hopefully this will help you debug the problem
This may be due to the fact that the key you are using is the "Down" key. I suspect that if you used a different key, it would work.
Some controls consume the arrow keys and pageup/pagedown keys. For example, TextBox does this. If your Canvas is in a scrollviewer, the scrollviewer might be eating it.
There are two workarounds for this:
Add a binding to the control that is eating the key gesture.
Handle KeyPreview for the Canvas (or any parent of the control that is eating the keystroke) and execute the command from there.
The answer to this question shows how you can do #2 without writing specific code in the KeyPreview handler for each command.
It turns out that it was a focus issue, I just set the focus to the canvas whenever mouse enters, now it's sort of fixed. Thanks everybody for answering.
I see some QnAs in our SO discussing about how to detect a drag-n-drop event but sometimes, for some reason such as application A run with admin right whist application B did not, the drag-n-drop is NOT allowed by Windows OS.
My question is: How can we detect a NOT-possible drag-n-drop happens in our code?
Edit
This question is about drag-n-dropping between two applications, one is privileged (run as admin) and other is NOT. Dragging between them is not allowed by Windows OS. I want to detect that situation and pop up a message in my application to let the users know why dragging then is not possible.
I guess you can do this using the DragOver event
private void UserControl_DragOver(object sender, DragEventArgs e)
{
//Verify that this is a valid drop
if (!Validate())
{
e.Effects = DragDropEffects.None;
e.Handled = true;
}
}
You might not know this, but pressing the F4 key on a ComboBox makes it's drop-down item list appear. I believe this is the default behavior on Windows.
Does anyone know how to override this behavior in WPF (C#)?
I know that overriding default behavior is generally seen as bad practice, however in this case I have a rugged-device that runs XP Embedded. It has a handful of prominent Function keys (F1 - F6) that need to trigger different events. This works fine, however when focused over a ComboBox the events aren't triggered as the ComboBox drops down.
I have tried catching the KeyDown event both on the form and on the ComboBox and listening for the F4 key, however it doesn't get this far as the key press must be handled at a lower level.
Any ideas?
I'm not positive about XP Embedded, but on regular ol' XP, this works. Use PreviewKeyDown, and set e.Handled to true:
public MyWindowOrControl()
{
InitializeComponent();
cboTest.PreviewKeyDown += new KeyEventHandler(cboTest_PreviewKeyDown);
}
void cboTest_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F4)
e.Handled = true;
}
You could make your own ComboBox class and just inherit from the old one.. you should hopefully be able to override the keydown/up methods.
I put several ComboBoxes on a XAML window. When I expand any of them, the DropDown part appears on the upper left corner of the screen.
I use Visual Studio 2008 C# Express. I don't remember this phenomenon when I used Visual Studio 2008 (Trial Version), though I use the same FrameWork (3.5).
It seems to be a bug.
Workaround:
Use Window.Show() instead with a custom logic to simulate the ShowDialog() behavior.
This appears to be a bug in WPF. In my case, I was trying to open a window in the Loaded event of another window. To get around this, I set a timer up to fire, then used a delegate to open the window (cannot open the window in a timer event because the calling thread that opens a window must be STA).
Edit - timer isn't necessary - didn't see the answer above just queue it on the dispatcher...
private delegate void DelegateOpenWindow();
private DelegateOpenWindow m_DelegateOpenWindow;
private Timer loginTimer = new Timer(200);
private void MainWindow1_Loaded(object sender, RoutedEventArgs e)
{
// create delegate used for asynchronous call
m_DelegateOpenWindow= new DelegateOpenWindow(this.OpenWindow);
// start a timer to fire off the open window.
loginTimer.Elapsed += loginTimer_Elapsed;
loginTimer.Enabled = true;
}
void loginTimer_Elapsed(object sender, ElapsedEventArgs e)
{
loginTimer.Enabled = false;
this.Dispatcher.BeginInvoke(m_DelegateOpenWindow);
}
void OpenWindow()
{
MyWindow w = new MyWindow();
w.Owner = this;
w.ShowDialog();
}
I started observing this (and other strange behavioral quirks) yesterday when I tried to "tweak" window sizes, shapes, colors, and invoke a log-on dialog from the Window.Loaded event handler. I had been doing this just fine in each of a dozen+ individual "MVVM" pattern apps. Yesterday, I decided to move this from each app's code behind into a consolidated code-behind base class, since the pre-processing had become common in all those apps. When I did, the drop-downs in two ComboBoxes in the log-in dialog suddenly appeared in the upper left corner of my screen. I seem to have "solved" it by using the following technique (your mileage may vary):
protected void WindowBaseLoadedHandler(object sender, RoutedEventArgs e)
{
...non-essential lines of code removed...
if (DataContext != null)
{
Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
{
/*----------------------------------------------------------------------
* Do we have a View Model? If so, perform standard VM Initialization...
*---------------------------------------------------------------------*/
this.IsEnabled = false;
LoginDlg loginDlg = new LoginDlg();
loginDlg.ShowDialog();
if (!loginDlg.Success)
{
/*-----------------------------------
* Log on failed -- terminate app...
*----------------------------------*/
...termination logic removed...
}
this.IsEnabled = true;
}));
}
WindowBaseLoadedHandler is the Loaded event handler. LoginDlg is a WPF app with a dialog containing two ComboBoxes.
Recap: After I consolidated the code into the Loaded event handler of the base class the ComboBox's drop down lists appeared in the upper left corner of my screen. Once I wrapped the logic into the Dispatcher.BeginInvoke call, the appropriate ComboBox behavior returned with lists below the current item.
I suspect WPF needs the application to return from the Loaded event to complete the layout system's initialization. That doesn't fully explain why it worked before, but I'll have to queue up my desire to hunt that "why" down for some rainy day in the future and celebrate overcoming the latest obstacle for today.
In any event, I hope someone finds this of use.
I'm using the latest .Net 4.5 and WPF framework and I still have this problem. One thing I noticed is that it only happen when there's an attached debugger. When the debugger is not attached, everything works fine.
I had the same problem on Visual Studio 2019.
Using window.Show() can help but it can ruin your design.
The solution is to open the window asynchronously.
var yourDialog= new YourDialog();
yourDialog.Owner = this;
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
this.Dispatcher.BeginInvoke(new Action(() =>
completion.SetResult(yourDialog.ShowDialog())));
bool? result = await completion.Task;
You can also create a more elegant solution by making the extension method:
public static class AsyncWindowExtension
{
public static Task<bool?> ShowDialogAsync(this Window self)
{
if (self == null) throw new ArgumentNullException("self");
TaskCompletionSource<bool?> completion = new TaskCompletionSource<bool?>();
self.Dispatcher.BeginInvoke(new Action(() => completion.SetResult(self.ShowDialog())));
return completion.Task;
}
}
And you can use it like this:
await dlgReview.ShowDialogAsync();
It’s a bug in WPF (not the only one, I'm afraid). It happened when I opened another window in the Loaded Event, something like:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Window selectionWindow = new SelectionWindow();
bool? result = selectionWindow.ShowDialog();
if (result == true)
RecordChanged();
}
I already found a workabout.