2009-07-09 3 views
6
 <data:DataGridTemplateColumn Header="Name"> 
     <data:DataGridTemplateColumn.CellTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding Name}"> 
      </DataTemplate> 
     </data:DataGridTemplateColumn.CellTemplate> 
     <data:DataGridTemplateColumn.CellEditingTemplate> 
      <DataTemplate> 
       <TextBox Text="{Binding Name}"> 
      </DataTemplate> 
     </data:DataGridTemplateColumn.CellEditingTemplate> 
    </data:DataGridTemplateColumn>    

C'est un exemple clair de colonne Modèle, non? Quest'ce qui pourrait ètre mauvais avec ça? Donc, voici la chose - quand un utilisateur navigue à travers DataGrid en appuyant sur la touche TAB, il doit frapper le TAB deux fois (!) Pour être en mesure de modifier le texte dans TextBox. Comment est-ce que je pourrais le rendre éditable dès que l'utilisateur obtient le focus de la colonne, je veux dire même s'il commence juste à taper?WPF DataGridTemplateColumn. Est-ce que je manque quelque chose?

Ok. J'ai trouvé un moyen - en Grid.KeyUp() Je mets le code ci-dessous:

if (Grid.CurrentColumn.Header.ToString() == "UserName") 
     { 
      if (e.Key != Key.Escape) 
      { 
       Grid.BeginEdit(); 

       // Simply send another TAB press 
       if (Keyboard.FocusedElement is Microsoft.Windows.Controls.DataGridCell) 
       { 
        var keyEvt = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Tab) { RoutedEvent = Keyboard.KeyDownEvent }; 
        InputManager.Current.ProcessInput(keyEvt); 
       } 
      } 
     } 

Répondre

8

votre problème provient du fait que chaque cellule met son éditeur dans un contrôle de contenu qui reçoit d'abord mise au point, alors vous devez onglet encore une fois à l'éditeur. Si vous regardez le code pour DataGridTemplateColumn dans la méthode GenerateEditingElement il appelle une LoadTemplateContent méthode qui fait cela.

private FrameworkElement LoadTemplateContent(bool isEditing, object dataItem, DataGridCell cell) 
{ 
    DataTemplate template = ChooseCellTemplate(isEditing); 
    DataTemplateSelector templateSelector = ChooseCellTemplateSelector(isEditing); 
    if (template != null || templateSelector != null) 
    { 
     ContentPresenter contentPresenter = new ContentPresenter(); 
     BindingOperations.SetBinding(contentPresenter, ContentPresenter.ContentProperty, new Binding()); 
     contentPresenter.ContentTemplate = template; 
     contentPresenter.ContentTemplateSelector = templateSelector; 
     return contentPresenter; 
    } 

    return null; 
} 

voir comment il crée un nouveau présentateur du contenu à mettre le modèle dans d'autres personnes ont traité ce problème de diverses façons, je dérive mon propre type de colonne pour faire face à ce genre de choses. (Donc je ne créer un élément supplémentaire ou définir le présentateur de contenu pour ne pas recevoir le focus) Dans ce example ils utilisent un gestionnaire de focus pour traiter la même question (i nai testé ce code)

<tk:DataGridTemplateColumn.CellEditingTemplate> 
    <DataTemplate> 
     <Grid FocusManager.FocusedElement="{Binding ElementName=txt1}"> 
     <TextBox Name="txt1" Text="{Binding [email protected]}" 
        BorderThickness="0" GotFocus="TextBox_GotFocus"/> 
     </Grid> 
    </DataTemplate> 
</tk:DataGridTemplateColumn.CellEditingTemplate> 

Si vous avez un contrôle de l'utilisateur en tant qu'éditeur, vous pouvez ensuite utiliser le modèle avec le gestionnaire de focus ou utiliser un gestionnaire d'événements pour l'événement OnLoaded.

+0

fonctionne un régal, mais ce qui est vraiment une bidouille horrible ... :(Je souhaite MS trouverait une belle façon de fournir ce type de fonctionnalité – David

+0

La méthode FocusManager fonctionne bien afin d'obtenir le contenu sélectionné, vous pouvez également ajouter une méthode de mise au point a obtenu:. private void StrikeTextBox_GotFocus (expéditeur d'objet, RoutedEventArgs e) { var textBox = (TextBox) expéditeur ; Dispatcher.BeginInvoke (nouvelle Action (textBox.SelectAll)); } – Neil

0

Mon approche consiste à utiliser une TriggerAction qui définit le focus sur l'élément de gabarit que vous voulez charger.

Le déclencheur est très simple:

public class TakeFocusAndSelectTextOnVisibleBehavior : TriggerAction<TextBox> 
{ 
    protected override void Invoke(object parameter) 
    { 
     Dispatcher.BeginInvoke(
      DispatcherPriority.Loaded, 
      new Action(() => 
      { 
       AssociatedObject.Focus(); 
       AssociatedObject.SelectAll(); 
      })); 
    } 
} 

Le DataTemplate ressemble à ceci:

<DataTemplate> 
    <TextBox Text="{Binding Path=Price, Mode=TwoWay}" 
       MinHeight="0" 
       Padding="1,0" 
       Height="20"> 
     <Interactivity:Interaction.Triggers> 
      <Interactivity:EventTrigger EventName="Loaded"> 
       <Behaviors:TakeFocusAndSelectTextOnVisibleBehavior /> 
      </Interactivity:EventTrigger> 
     </Interactivity:Interaction.Triggers> 
    </TextBox> 
</DataTemplate> 

Vous pouvez écrire d'autres déclencheurs pour d'autres types d'éléments.

+1

Je pense que cette fonctionnalité nécessite une DLL d'Expression Blend – Neil

7

Le problème que vous avez rencontré est que le contrôle (par exemple TextBox) dans le DataGridTemplateColumn est contenu dans un DataGridCell. Par défaut, DataGridCell possède une fonctionnalité de tabulation. Ainsi, la raison de devoir cliquer deux fois sur TAB pour obtenir le focus sur votre contrôle TextBox. La solution consiste à désactiver la fonctionnalité de tabulation-arrêt pour DataGridCell. Cela peut être fait via un style pour DataGridCell.

est ici la solution:

<Style TargetType="{x:Type DataGridCell}"> 
    <Setter Property="KeyboardNavigation.IsTabStop" Value="False" /> 
</Style> 
3

Voici mon approche. C'est très proche de @Nalin Jayasuriya réponse, mais je ne voulais pas créer un style. Aussi cette solution sélectionne le texte dans la TextBox. Quoi qu'il en soit - le XAML pour le trou DataGrid ressemble à ceci.

<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> 

Et le code-behind.

private void TextBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) 
{ 
    try 
    { 
     ((TextBox)sender).SelectAll(); 
    } 
    catch (Exception ex) { GlobalDebug.debugForm.WriteText(ex); } 
} 

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 (Exception ex) { GlobalDebug.debugForm.WriteText(ex); } 
} 

Pour plus d'informations, consultez mon blog: http://blog.baltz.dk/post/2014/11/28/WPF-DataGrid-set-focus-and-mark-text

Questions connexes