Is it possible to avoid Focus on SplitContainer? - winforms

The WinForm SplitContainer gets the focus when it's dragged or clicked, while the Splitter does not.
The side-effect of this, is that dragging a SplitContainer bar fires Leave/Validate on other controls, and I need to avoid this.
I already tried setting TabStop and CausesValidation to False, but with no success.
Is there a way to stop the SplitContainer from getting focused? (not a big deal, I can still use the old Splitter, but I lose some nice VS properties...)

Remove the SplitContainer control and replace it manually with Panel and Splitter controls. A little more effort, but a much cleaner outcome.

Try with this code:
//This code will move the focus from the splitContainer to TreeView shortly after moved.
private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) {
if(this.splitContainer1.CanFocus) {
this.splitContainer1.ActiveControl = this.treeView1;
}
}

Filini,
The only time that the splitcontainer would have focus is when you are actually moving the splitter. So I would so something like this in your validating and leave events.
private void Button_Leave(object sender, EventArgs e)
{
if(SplitContainer.ContainsFocus)
return;
}
I reproduced your issue and when I added the above it still calls the event of course, but the code execution doesn't occur because the SplitContainer has focus while you are moving the splitter.
Hope that helps.

Related

WPF DataGrid loses focus after row delete / cut

I have a DataGrid implemented in an MVVM/Prism application. The DataGrid supports Cut/Copy/Paste/Delete through a context menu and keyboard gestures.
I find that when a row is deleted/cut the entire DataGrid loses focus and keyboard focus moves to the last focused control.
Is there anyway to prevent this?
After removing a row I may want to re-paste into the DataGrid. Furthermore if the grid is empty there is no way at all for it to get keyboard focus. Clicking an empty grid does not give it focus.
Here is a similar question, but it doesn't solve the issue for me:
DataGrid Looses Focus When Delete Key is Pressed
You could set the DataGrids Focus in the PreviewKeyDown-Event
private void TheDataGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Delete)
{
var grid = (DataGrid)sender;
FocusManager.SetFocusedElement(Window.GetWindow(grid), grid); //not tested
}
}
If you dont want to put code in code-behind use AttachedProperties in combination with the DependencyPropertyChanged-Event.
How to set set focus.
A dirty solution might be to handle the LostFocus event exposed by DataGrid and set focus on the control.
It arguably marginally infringes on the MVVM pattern i.e keeping the view dumb as hell, but it's still view code.

DataGrid + ContextMenu: How to get the row under the right click

In Silverlight 5, I have a DataGrid with a ContextMenuService.ContextMenu. If you click a row to select, then right click, you just check the grid.selecteditem for context. However, if you right click a row without selecting it, you don't have that row's context when the menu opens. How do you get the DataContext row of the grid that was right clicked on when the context menu opens? The right click on the grid seems to be an option, but it is intercepted for the contextmenu and does not fire unless a contextmenu is already open/in focus.
I have found tons of examples of getting around the original issue with Silverlight 4 and detecting the rown on right click. However, the contextmenu now intercepts the rigth click of the grid, so those no logner work. I also found posts on 'bugs' with the initial relase of the ContextMenu. All these posts/blogs are making it hard to find a current answer or solution.
yeah it seems like Silverlight 5 has changed something that breaks the old tricks.
We've been doing this: add row enters on row load handler. EG:
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.MouseEnter += new MouseEventHandler(Row_MouseEnter);
e.Row.MouseLeave += new MouseEventHandler(Row_MouseLeave);
}
void Row_MouseEnter(object sender, MouseEventArgs e)
{
DataGridRow dgr = sender as DataGridRow;
IncidentGrid.SelectedItem = dgr.DataContext;
}
pretty ugly i know, but it's working.
Besides Roger's concerns of accuracy, I didn't want to wire up those events on every row because my grid is quite large, and I have to keep it lean.
I found a solution here...
https://mutelight.org/silverlight-datagrid-make-right-click-select-a-row
Apply just one event handler to the grid's MouseRightButtonDown event. The event args has the mouse position and you can use VisualTreeHelper to find which DataGridRow the mouse is over. Then that row's DataContext will have your SelectedItem.

WPF Routed Command only fires sometimes

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.

WPF TextBox - don't hide the selection

WPF's TextBox (System.Windows.Controls.TextBox) appears to highlight selected text only when it has the focus. I need to make a TextBox continue to show the selection when focus is lost.
In a standard Win32 EDIT control I could achieve this with ES_NOHIDESEL. How can I get the equivalent in WPF?
You can handle the LostFocus event and set the event arg to e.Handled = true. In this way the TextBox will not know that it lost focus and will keep your selection.
private void myTextCtrl_LostFocus(object sender, RoutedEventArgs e)
{
e.Handled = true;
}
This will give you a similar thing to what you are looking for, but unlike the Win32 way, it will still show your selection in the highlighted color instead of dark gray.
If you really want to go through the effort you could also write XAML for <TextBox.SelectionBrush>.
Another way is to use FocusManager, you can read about this method here.

Can't set focus to a child of UserControl

I have a UserControl which contains a TextBox. When my main window loads I want to set the focus to this textbox so I added Focusable="True" GotFocus="UC_GotFocus" to the UserControls definition and FocusManager.FocusedElement="{Binding ElementName=login}" to my main windows definition. In the UC_GotFocus method i simply call .Focus() on the control i want to focus on but this doesn't work.
All i need to do is have a TextBox in a UserControl receive focus when the application starts.
Any help would be appreciated, thanks.
I recently fixed this problem for a login splash screen that is being displayed via a storyboard when the main window is first loaded.
I believe there were two keys to the fix. One was to make the containing element a focus scope. The other was to handle the Storyboard Completed event for the storyboard that was triggered by the window being loaded.
This storyboard makes the username and password canvas visible and then fades into being 100% opaque. The key is that the username control was not visible until the storyboard ran and therefore that control could not get keyboard focus until it was visible. What threw me off for awhile was that it had "focus" (i.e. focus was true, but as it turns out this was only logical focus) and I did not know that WPF had the concept of both logical and keyboard focus until reading Kent Boogaart's answer and looking at Microsoft's WPF link text
Once I did that the solution for my particular problem was straightforward:
1) Make the containing element a focus scope
<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
<TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
</TextBox>
</Canvas>
2) Attach a Completed Event Handler to the Storyboard
<Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>
and
3) Set my username TextBox to have the keyboard focus in the storyboard completed event handler.
void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
m_uxUsername.Focus();
}
Note that calling item.Focus() results in the call Keyboard.Focus(this), so you don't need to call this explicitly. See this question about the difference between Keyboard.Focus(item) and item.Focus.
Its stupid but it works:
Pop a thread that waits a while then comes back and sets the focus you want. It even works within the context of an element host.
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
System.Threading.ThreadPool.QueueUserWorkItem(
(a) =>
{
System.Threading.Thread.Sleep(100);
someUiElementThatWantsFocus.Dispatcher.Invoke(
new Action(() =>
{
someUiElementThatWantsFocus.Focus();
}));
}
);
}
Just recently I had a list-box that housed some TextBlocks. I wanted to be able to double click on the text block and have it turn into a TextBox, then focus on it and select all the text so the user could just start typing the new name (Akin to Adobe Layers)
Anyway, I was doing this with an event and it just wasn't working. The magic bullet for me here was making sure that I set the event to handled. I figure it was setting focus, but as soon as the event went down the path it was switching the logical focus.
The moral of the story is, make sure you're marking the event as handled, that might be your issue.
“When setting initial focus at application startup, the element to
receive focus must be connected to a PresentationSource and the
element must have Focusable and IsVisible set to true. The recommended
place to set initial focus is in the Loaded event handler"
(MSDN)
Simply add a "Loaded" event handler in the constructor of your Window (or Control), and in that event handler call the Focus() method on the target control.
public MyWindow() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
}
void MyWindow_Loaded(object sender, RoutedEventArgs e) {
textBox.Focus();
}
since i tried a fuzquat's solution and found it the most generic one, i thought i'd share a different version, since some complained about it looking messy. so here it is:
casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
{
x.Focus();
}), DispatcherPriority.ApplicationIdle, casted);
no Thread.Sleep, no ThreadPool. Clean enough i hope.
UPDATE:
Since people seem to like pretty code:
public static class WpfExtensions
{
public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
{
element.Dispatcher.BeginInvoke(priority, action);
}
}
now you can call it like this:
child.BeginInvoke(d => d.Focus());
WPF supports two different flavors of focus:
Keyboard focus
Logical focus
The FocusedElement property gets or sets logical focus within a focus scope. I suspect your TextBox does have logical focus, but its containing focus scope is not the active focus scope. Ergo, it does not have keyboard focus.
So the question is, do you have multiple focus scopes in your visual tree?
I found a good series of blog posts on WPF focus.
Part 1: It’s Basically Focus
Part 2: Changing WPF focus in code
Part 3: Shifting focus to the first available element in WPF
They are all good to read, but the 3rd part specifically deals with setting focus to a UI element in a UserControl.
Set your user control to Focusable="True" (XAML)
Handle the GotFocus event on your control and call yourTextBox.Focus()
Handle the Loaded event on your window and call yourControl.Focus()
I have a sample app running with this solution as I type. If this does not work for you, there must be something specific to your app or environment that causes the problem. In your original question, I think the binding is causing the problem.
I hope this helps.
After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.
First, add your App.xaml OnStartup() the followings:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
Then add the 'WindowLoaded' event also in App.xaml :
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.
I found the following solution best as it is used globally for the whole app.
Hope it helps...
Oran
I converted fuzquat's answer to an extension method. I'm using this instead of Focus() where Focus() did not work.
using System;
using System.Threading;
using System.Windows;
namespace YourProject.Extensions
{
public static class UIElementExtension
{
public static void WaitAndFocus(this UIElement element, int ms = 100)
{
ThreadPool.QueueUserWorkItem(f =>
{
Thread.Sleep(ms);
element.Dispatcher.Invoke(new Action(() =>
{
element.Focus();
}));
});
}
}
}
I've noticed a focus issue specifically related to hosting WPF UserControls within ElementHosts which are contained within a Form that is set as an MDI child via the MdiParent property.
I'm not sure if this is the same issue others are experiencing but you dig into the details by following the link below.
Issue with setting focus within a WPF UserControl hosted within an ElementHost in a WindowsForms child MDI form
I don't like solutions with setting another tab scope for UserControl. In that case, you will have two different carets when navigating by keyboard: on the window and the another - inside user control. My solution is simply to redirect focus from user control to inner child control. Set user control focusable (because by default its false):
<UserControl ..... Focusable="True">
and override focus events handlers in code-behind:
protected override void OnGotFocus(RoutedEventArgs e)
{
base.OnGotFocus(e);
MyTextBox.Focus();
}
protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
base.OnGotKeyboardFocus(e);
Keyboard.Focus(MyTextBox);
}
What did the trick for me was the FocusManager.FocusedElement attribute. I first tried to set it on the UserControl, but it didn't work.
So I tried putting it on the UserControl's first child instead:
<UserControl x:Class="WpfApplication3.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
<TextBox x:Name="MyTextBox"/>
</Grid>
... and it worked! :)
I have user control - stack panel with two text boxes.The text boxes were added in contructor, not in the xaml. When i try to focus first text box, nothing happend.
The siggestion with Loaded event fix my problem. Just called control.Focus() in Loaded event and everthing.
Assuming you want to set focus for Username textbox, thus user can type in directly every time it shows up.
In Constructor of your control:
this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
After trying combinations of the suggestions above, I was able to reliably assign focus to a desired text box on a child UserControl with the following. Basically, give focus to the child control and have the child UserControl give focus to its TextBox. The TextBox's focus statement returned true by itself, however did not yield the desired result until the UserControl was given focus as well. I should also note that the UserControl was unable to request focus for itself and had to be given by the Window.
For brevity I left out registering the Loaded events on the Window and UserControl.
Window
private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
ControlXYZ.Focus();
}
UserControl
private void OnControlLoaded(object sender, RoutedEventArgs e)
{
TextBoxXYZ.Focus();
}
I set it in the PageLoaded() or control loaded, but then I'm calling WCF async service and doing stuff that seems to lose the focus. I have to to set it at the end of all the stuff I do. That's fine and all, but sometimes I make changes to the code and then I forget that I'm also setting the cursor.
I had same problem with setting keyboard focus to canvas in WPF user control.
My solution
In XAML set element to Focusable="True"
In element_mousemove event create simple check:
if(!element.IsKeyBoardFocused)
element.Focus();
In my case it works fine.

Resources