WPF TextBox - don't hide the selection - wpf

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.

Related

WPF popup listbox use keyboard for navigation

Can anyone suggest the solution how can I make navigation using down and up keys in listbox which come on popup.
Solutions like set selected items on keyup and keydown event are not working for me.
Should I make something more special then just set selected item in this case?
ListBox already implements selection navigation using keyboard when it is focused.
All you have to do is give it focus when you want, for example in the window that contains it:
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Down)
{
listbox.SelectedIndex = 0;
listbox.Focus();
}
}
Because listbox.Focus(); will only give it focus but won't yet change the selection item (which will make the user hit's the "Down" button twice in order to do so) set the ListBox's SelectedIndex first.
Hope this helps

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.

Setting Default Keyboard Focus On Loading A UserControl

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.

WPF Default Button command not triggering binding in textbox

I have a search screen with some textboxes and a Search button as the default. If I type in a textbox and I CLICK the button, everything's great. But if I press enter within a text box, the button command fires but the binding on whatever text box I was in does NOT fire and so my criteria doesn't make it to the view model to get filtered on.
I know one fix is to set the bindings on the text boxes to PropertyChanged, but this seems like way overkill. I might have logic in the viewmodel doing stuff and I don't want that to trigger on every single keystroke.
What I really want is a way for the button itself to either trigger a focus change or somehow trigger binding. Or to have the textbox trigger binding if focus is lost OR I press enter OR a command is executed from anywhere
One way to do this is with a BindingGroup.
http://msdn.microsoft.com/en-us/library/system.windows.frameworkelement.bindinggroup.aspx
If your TextBox(es) and Button are both contained within a Grid (for example), you would add a BindingGroup like this:
<Grid>
<Grid.BindingGroup>
<BindingGroup Name="bindingGroup1"/>
</Grid.BindingGroup>
Then you could add a Click event handler to your button and call CommitEdit() on the BindingGroup (which the Button and TextBox inherit from the Grid):
private void button1_Click(object sender, RoutedEventArgs e)
{
(sender as FrameworkElement).BindingGroup.CommitEdit();
}
The Button.Click event fires before the CommandBinding, so any databound TextBox or any other databound controls within that BindingGroup should be updated before your view model command gets executed.
I've had the exact scenario you just mentioned. The trick I use is an attached behavior that sits on a control and listens for the PreviewKeyDown event. It checks if enter is being pressed. If so it forces the control to lose focus, thus causing the binding to fire before the command executes.
A simpler approach (rather than using a binding group) is to use the default button's click event to set the focus to itself. As this happens before the command is executed it means the ViewModel is updated in time.
private void button1_Click(object sender, RoutedEventArgs e)
{
(sender as Button).Focus()
}
And if you really hate code behind, you could always write an attached property...

Is it possible to avoid Focus on SplitContainer?

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.

Resources