OK - So I’ve got a WPF DataGrid, with a DataGridTemplateColumn. The DataTemplate is a plane TextBox. When I tab through the cells, I want to select the text in the TextBox. And when I click the text in the TextBox, I also want to select it. That proved more difficult than I expected.
But hacking and slashing from this blog
http://andora.us/blog/2011/06/09/wpf-textbox-select-all-on-focus/
and this answer
http://stackoverflow.com/questions/1104164/wpf-datagridtemplatecolumn-am-i-missing-something
I came up with a solution. Although not strictly MVVM, I still think it falls under that design pattern. All View related stuff is still handled in the View.
Anyway - First of all. when you tab through the cells the first tab stop is the border of the cell, and the second is the actual TextBox.
Secondly, In WPF, the default behavior of the TextBox on focus is to put the cursor where it was the last time the TextBox had lost focus or if it hasn’t had focus yet, at the beginning.
The first problem I solved by by using the answer from stackoverflow:
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridTemplateColumn.CellStyle>
The second by following Andora block. So the hole XAML DataGrid looks like this:
<DataGrid Name="TextBlockDataGrid" ItemsSource="{Binding Path=Rows}" Style="{StaticResource DefaultSettingsDataGrid}">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Text}" IsReadOnly="True"/>
<DataGridTemplateColumn Width="*">
<DataGridTemplateColumn.CellStyle>
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="KeyboardNavigation.IsTabStop" Value="False"/>
</Style>
</DataGridTemplateColumn.CellStyle>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Border BorderThickness="{Binding ErrorBorderThickness}" BorderBrush="{Binding ErrorBorderBrush}">
<TextBox Text="{Binding UserText, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"
HorizontalAlignment="Right"
GotKeyboardFocus="TextBox_GotKeyboardFocus"
PreviewMouseDown="TextBox_PreviewMouseDown"
Style="{StaticResource DefaultTextBox}"/>
</Border>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
And the code-behind like this:
private void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
try
{
((TextBox)sender).SelectAll();
}
catch { }
}
private void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
try
{
// If its a triple click, select all text for the user.
if (e.ClickCount == 3)
{
((TextBox)sender).SelectAll();
return;
}
// Find the TextBox
DependencyObject parent = e.OriginalSource as UIElement;
while (parent != null && !(parent is TextBox))
{
parent = System.Windows.Media.VisualTreeHelper.GetParent(parent);
}
if (parent != null)
{
if (parent is TextBox)
{
var textBox = (TextBox)parent;
if (!textBox.IsKeyboardFocusWithin)
{
// If the text box is not yet focussed, give it the focus and
// stop further processing of this click event.
textBox.Focus();
e.Handled = true;
}
}
}
}
catch { }
}
As always, feel free to comment, or ask.