I have a WPF user control with multiple child controls and I am focusing DataGrid and TextBox programmatically with the following code:
searchTextBox.Focus();
and
productGrid.Focus();
productGrid.Focus(dataGrid); //tried this but it does not help
searchTextBox focuses normally but dataGrid does not (keyboard focus stays on some other control). Below I provided full source code that hides searchTextBox and moves focus to productGrid (searchPanel is a parent Grid of searchTextBox):
private void Execute_CancelCommand(object sender, ExecutedRoutedEventArgs e)
{
if (searchPanel.Visibility == Visibility.Visible)
{
searchPanel.Visibility = Visibility.Collapsed;
searchTextBox.Clear();
searchTextBox.Background = Brushes.White;
//the focus stays on the splitter for some reason
productGrid.Focus();
Keyboard.Focus(productGrid);
}
}
what can cause this situation?
Thnx.
It seems that productGrid.Focusable property is set to "false". You should just set it to "True" and your code should work correctly and there will be no need in calling Keyboard.Focus() method.
Related
I have a UserControl that contains several ComboBoxes and Buttons.
In the window that hosts the UserControl I need to update some properties when the UserControl gets the focus.
My problem is, that every time, when the focus inside the user control changes, that get a GotFocus event in the hosting windows.
Is there some kind of best practice to make sure, that I only get one GotFocused event in the hosting window? I mean, if I step through controls inside the UserControl the focus is always inside the UserControl, so I don't want a GotFocused event.
This is the solution I came up to:
First of all this post was the key for my solution: WPF UserControl detect LostFocus ignoring children .
And Refer to active Window in WPF? .
Using the functions in these posts I registered the LostFocus event in my UserControl.
private void UserControl_LostFocus(object sender, RoutedEventArgs e)
{
var focused_element = FocusManager.GetFocusedElement(Application.Current.Windows.OfType<Window>().FirstOrDefault(x => x.IsActive));
var parent = (focused_element as FrameworkElement).TryFindParent<KeywordSelector>();
if (parent != this) userControlHasFocus=false;
}
And then ...
private void UserControl_GotFocus(object sender, RoutedEventArgs e)
{
if (userControlHasFocus == true) e.Handled = true;
else userControlHasFocus = true;
}
This way I keep track of the focus. userControlHasFocus is false be default. When the GotFocus() happens for the first time it's false and the GotFocus event is not stopped form bubbling up. But userControlHasFocus gets set to true, because now the focus is inside the UserControl.
Whenever the focus moves to another control, LostFocus checks if the new controls parent is the UserControl. If not, it resets the userControlHasFocus to false.
I created a WPF UserControl, that handles all GotFocus/LostFocus events of its child controls. I call the OnGotFocus/OnLostFocus of the UserControl, but the IsFocused property of the UserControl will not set:
void MyUserControl_Initialized(object sender, EventArgs e)
{
foreach (UIElement control in (Content as Panel).Children)
{
control.LostFocus += control_LostFocus;
control.GotFocus += control_GotFocus;
}
}
void control_GotFocus(object sender, RoutedEventArgs e)
{
if (!IsFocused)
{
e.Handled = false;
OnGotFocus(e);
}
}
void control_LostFocus(object sender, RoutedEventArgs e)
{
bool hasAnythingTheFocus = false;
foreach (UIElement control in (Content as Panel).Children)
{
if (control.IsFocused)
{
hasAnythingTheFocus = true;
}
}
if (!hasAnythingTheFocus)
{
OnLostFocus(e);
}
}
How can I set it?
Instead of the IsFocused you can use IsKeyboardFocusWithin
use the event UIElement.IsKeyboardFocusWithinChanged and it should worked perfectly.
The GotFocus method will be called when the relevant control receives logical focus... from the UIElement.GotFocus Event page on MSDN:
Logical focus differs from keyboard focus if focus is deliberately forced by using a method call but the previous keyboard focus exists in a different scope. In this scenario, keyboard focus remains where it is and the element where a Focus method is called still gets logical focus.
A more precise interpretation of this event is that it is raised when the value of the IsFocused property of an element in the route is changed from false to true.
Because this event uses bubbling routing, the element that receives focus might be a child element instead of the element where the event handler is actually attached. Check the Source in the event data to determine the actual element that gained focus.
it will get focus when the user clicks on the relevant control in the UI and/or when you call control.Focus() in your code. The IsFocused is readonly and cannot be set.
I have an MVVM setup with a mainwindow that contains a ContentControl.
I set this to a particular viewmodel which then maps to a view.
A view is a usercontrol.
I want to be able to set the default keyboard focus to a default element in the usercontrol(View) when it loads so the application can eventually be driven just by using up, down, left, right and enter.
Some of my failed attempts are setting
FocusManager.FocusedElement="{Binding ElementName=DefaultElement}"
in my content control tag. This sets the logical focus but not the keyboard focus
I'd rather keep the solution in xaml if possable but have tried placing the following in code behind.
Keyboard.Focus(DefaultElement);
This does not work but if I popup a message box first it does. I'm a little confused as to why.
MessageBox.Show(Keyboard.FocusedElement.ToString());
Keyboard.Focus(DefaultElement);
EDIT::::
I just placed this in my onloaded event of my user control. It seems to work but can anyone see any issues that might arrise at this priority level. I.E a circumstance when the action will never run?
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
Keyboard.Focus(DefaultElement);
}));
It seems that this wpf the you have to implement a workaround on a case by case basis. The solution that seemed to work best, most of the time for me was to insert the focus code inside the dispatcher when OnVisible was changed. This sets the focus not only when the View/Usercontrol loads but also if you a changing Views by way of Visibility. If you Hide and then Show a ContentControl that is mapped to your ViewModels then the Loaded event won't fire and you'll be forced to Mouse input, or tabbing (Not so good if you want to navigate your app with a remote control).
VisibilityChanged will always fire however. This is what I ended up with for my listbox.
private void ItemsFlowListBox_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue == true)
{
Dispatcher.BeginInvoke(
DispatcherPriority.ContextIdle,
new Action(delegate()
{
ItemsFlowListBox.Focus();
ItemsFlowListBox.ScrollIntoView(ItemsFlowListBox.SelectedItem);
}));
}
}
I had the same symptom for a WPF UserControl hosted in a Winforms application. Just wanted to note I was about to try this solution when I found a normal TabIndex in the Winforms app fixed it
Per How to set which control gets the focus on application start
"The one with the minimum tab index automatically gets the focus
(assuming the TabStop property is set to true). Just set the tab
indices appropriately."
It's a tricky one with no easy answer. I'm currently doing this, although I'm not sure I like it:
public MyView()
{
InitializeComponent();
// When DataContext changes hook the txtName.TextChanged event so we can give it initial focus
DataContextChanged +=
(sender, args) =>
{
txtName.TextChanged += OnTxtNameOnTextChanged;
};
}
private void OnTxtNameOnTextChanged(object o, TextChangedEventArgs eventArgs)
{
// Setting focus will select all text in the TextBox due to the global class handler on TextBox
txtName.Focus();
// Now unhook the event handler, since it's no longer required
txtName.TextChanged -= OnTxtNameOnTextChanged;
}
And in case you're wondering what the global class handler does, it's this:
protected override void OnStartup(StartupEventArgs e)
{
...
// Register a global handler for this app-domain to select all text in a textBox when
// the textBox receives keyboard focus.
EventManager.RegisterClassHandler(
typeof (TextBox), UIElement.GotKeyboardFocusEvent,
new RoutedEventHandler((sender, args) => ((TextBox) sender).SelectAll()));
which auto selects TextBox text when receiving keyboard focus.
I have combobox in WPF application that when the user clicks on it, it selects all the text. How can I change the behavior of this to when the user clicks it just set the typing cursor like a normal textbox?
Try
<ComboBox IsEditable="True" />
According to Reflector, the ComboBox code contains this:
private static void OnGotFocus(object sender, RoutedEventArgs e)
{
ComboBox box = (ComboBox) sender;
if ((!e.Handled && box.IsEditable) && (box.EditableTextBoxSite != null))
{
if (e.OriginalSource == box)
{
box.EditableTextBoxSite.Focus();
e.Handled = true;
}
else if (e.OriginalSource == box.EditableTextBoxSite)
{
box.EditableTextBoxSite.SelectAll(); // <==
}
}
}
This method is registered for the GotFocus event in the static constructor using the EventManager:
EventManager.RegisterClassHandler(typeof(ComboBox), UIElement.GotFocusEvent, new RoutedEventHandler(ComboBox.OnGotFocus));
So, I think you can only change that behavior by deriving a custom control from ComboBox and override this event registration by your own method which replaces the call to SelectAll() with another method which sets the caret to the correct position. However, I do not know how to set the caret to the click position. You might have to use Reflector on the TextBox to find that...
Seems that I had to solve similar issue.
It's quite tricky, but the way I solved is to set IsEditable to false/true from code, at the same time I set the focus on TextBox.
Not the pretties way but does the job.
I have a usercontrol loaded inside a canvas; this usercontrol on default have visibility collapsed. When a specific textbox of my window is focused the usercontrol become visible.
When usercontrol become visible I want set focus to another textbox inside usercontrol.
I try to do that:
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
FocusManager.SetFocusedElement(this, TextBlockInput);
}
}
It seems work but there is a problem: the textbox seems focused but the cursor into textbox don't blink and I can't type chars for input.
I would that after focus the textbox is ready for input. How can I do?
Well, I solve in this way:
private void UserControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (this.Visibility == Visibility.Visible)
{
this.Dispatcher.BeginInvoke((Action)delegate
{
Keyboard.Focus(TextBlockInput);
}, DispatcherPriority.Render);
}
}
I think that the problem was tha focus call into IsVisibleChanged event "scope"...right?
try
Keyboard.Focus(TextBlockInput);
see here for more details
Another possible workaround is instead of Visibility property use Opacity. In this case calling Focus() actually sets focus.