J'ai un datagrid dans WPF avec un DataGridTextColum et un DataGridTemplateColum .
<DataGridTextColumn Width="4*" IsReadOnly="True" x:Name="dataGridColumnDescription"
Header="Description" Binding="{Binding Description}">
</DataGridTextColumn>
<DataGridTemplateColumn CellStyle="{StaticResource CellEditing}" IsReadOnly="False" Width="*" Header="Value"
CellEditingTemplateSelector="{StaticResource myCellEditingTemplateSelectorValue}"
CellTemplateSelector="{StaticResource myCellTemplateSelectorValue}">
</DataGridTemplateColumn>
CellTemplateSelectors renvoie un DataTemplate avec un TextBlock pour le resp. Celltemplate. une TextBox pour CellEditing!
<DataTemplate x:Key="dGridStringValueTemplate">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Path=Value}"/>
</DataTemplate>
<DataTemplate x:Key="dGridStringValueTemplateEditing">
<TextBox TextAlignment="Center" VerticalAlignment="Center" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" BorderThickness="1" Text="{Binding Path=Value, UpdateSourceTrigger=LostFocus}"/>
</DataTemplate>
Maintenant, je veux mettre au point automatiquement la zone de texte lorsque le DataGridCell obtient le focus. L'utilisateur doit pouvoir modifier le contenu de la zone de texte sans double-cliquer sur la cellule.
J'ai trouvé cet article:
Trucs et astuces dans DataGrid: Édition en un seul clic Où je peux obtenir le DataGridCell actuel, mais comment puis-je accéder au contenu pour donner à la zone de texte le focus pour l'éditer?
C'est mon style:
<Style x:Key="CellEditing" TargetType="{x:Type DataGridCell}">
<EventSetter Event="PreviewMouseLeftButtonDown" Handler="myDataGridMain_PreviewMouseLeftButtonDown"></EventSetter>
</Style>
Ceci est mon gestionnaire d'événement:
private void myDataGridMain_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DataGridCell cell = sender as DataGridCell; // cell ist not null
DataGridTemplateColumn col = cell.Column as DataGridTemplateColumn; //col is not null
DataTemplate template = col.CellTemplate; //this is null
}
Comment puis-je obtenir la zone de texte avec ce gestionnaire d'événements?
Je l’ai réussi, ce n’est pas la meilleure solution mais ça marche ... Quand Cell a le focus, je le mets en mode édition.
private void myDataGridMain_OnFocus(object sender, RoutedEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (cell != null)
cell.IsEditing = true;
//var test = FindVisualChild<TextBlock>(cell);
}
Sur Keydown, je recherche l'enfant visuel et lui donne le focus.
private void myDataGridMain_KeyDown(object sender, KeyEventArgs e)
{
DataGridCell cell = sender as DataGridCell;
if (e.Key == Key.Enter)
{ //give cell the focus
cell.Focus();
}
else
{
if ((cell != null))
{
TextBox textbox = FindVisualChild<TextBox>(cell);
if (textbox != null)
{ //TextBox has benn found
if ((textbox as TextBox).IsFocused == false)
{
(textbox as TextBox).SelectAll();
}
(textbox as TextBox).Focus();
}
CheckBox chkbox = FindVisualChild<CheckBox>(cell);
if (chkbox != null)
{ //Checkbox has been found
(chkbox as CheckBox).Focus();
}
ComboBox combbox = FindVisualChild<ComboBox>(cell);
if (combbox != null)
{ //ComboBox has been found
(combbox as ComboBox).Focus();
}
}
}
}
Trouver un enfant visuel!
public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
return (T)child;
else
{
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
Cela semble fonctionner:
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTemplateColumn>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Cette approche fonctionne pour moi. Il utilise le fait que la DataGrid
créera toujours une nouvelle instance du modèle lorsque la modification commencera:
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding MyProperty}"
Loaded="TextBox_Loaded"></TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
et dans le code derrière:
private void TextBox_Loaded(object sender, RoutedEventArgs e)
{
((TextBox)sender).Focus();
((TextBox)sender).SelectAll();
}
En prime, il sélectionne également tout le texte de la cellule. Cela devrait fonctionner quelle que soit la manière dont vous entrez en mode d'édition (double clic, clic simple, appui sur F2)
la réponse simple pour créer un nouveau contrôle dérivé du contrôle datagrid
using System.Windows.Controls;
public class CustomDataGrid : DataGrid
{
protected override void OnSelectedCellsChanged(SelectedCellsChangedEventArgs e)
{
//to make sure cell is selected
var cells = e.AddedCells.FirstOrDefault();
if (cells != null)
{
this.BeginEdit();
}
base.OnSelectedCellsChanged(e);
}
}