2009-07-09 13 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>    

È un chiaro esempio di colonna Modello, giusto? Cosa potrebbe esserci di sbagliato in questo? Quindi, ecco la cosa: quando un utente naviga attraverso DataGrid premendo TAB-key, deve premere due volte il TAB (!) Per poter modificare il testo in TextBox. Come posso renderlo modificabile non appena l'utente ottiene il focus della colonna, voglio dire anche se inizia a digitare?WPF DataGridTemplateColumn. Mi sto perdendo qualcosa?

Ok. Ho trovato un modo - in Grid.KeyUp() Ho messo il codice qui sotto:

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); 
       } 
      } 
     } 

risposta

8

il problema deriva dal fatto che ogni cella mette il suo editore in un controllo dei contenuti che riceve primo fuoco, poi si deve scheda ancora una volta all'editore. Se si dispone di uno sguardo al codice per DataGridTemplateColumn nel metodo GenerateEditingElement si chiama un metodo LoadTemplateContent che fa questo:.

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

vedere come si crea un nuovo presentatore contenuti di mettere il modello in Altre persone hanno affrontato questo problema in una varietà di modi, io tratto il mio tipo di colonna per affrontare questa roba. (Così io non creare un elemento in più o impostare il presentatore contenuti di non ricevere l'attivazione) In questo example stanno usando gestore di attivazione a che fare con lo stesso problema (i havent provato questo codice)

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

Se si dispone di un controllo utente come editor, quindi è possibile utilizzare il pattern con il gestore di focus o utilizzare un gestore di eventi per l'evento OnLoaded.

+0

funziona a meraviglia, ma questo è davvero un brutto mod ... :(Vorrei che MS avrebbe trovato un bel modo di fornire questo tipo di funzionalità – David

+0

Il metodo FocusManager funziona bene al fine di ottenere il contenuto selezionato, è possibile anche aggiungere un metodo preso fuoco:. private void StrikeTextBox_GotFocus (object sender, RoutedEventArgs e) { var textBox = (TextBox) mittente ; Dispatcher.BeginInvoke (new Action (textBox.SelectAll)); } – Neil

0

Il mio approccio consiste nell'utilizzare un'azione Trigger che imposta lo stato attivo sull'elemento modello che si desidera quando viene caricato.

Il grilletto è molto semplice:

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

DataTemplate assomiglia a questo:

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

È possibile scrivere altri trigger per gli altri tipi di elementi.

+1

Penso che questa funzionalità richiede una dll di Expression Blend – Neil

7

Il problema che si è verificato è che il controllo (ad esempio TextBox) all'interno di DataGridTemplateColumn è contenuto in un DataGridCell. Per impostazione predefinita, DataGridCell ha funzionalità di tabulazione. Quindi, la ragione per cui si deve premere TAB due volte per focalizzarsi sul controllo TextBox. La soluzione è disabilitare la funzionalità tab-stop per DataGridCell. Questo può essere fatto tramite uno stile per DataGridCell.

ecco la soluzione:

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

Ecco il mio approccio. È molto vicino alla risposta di @Nalin Jayasuriya, ma non volevo creare uno stile. Anche questa soluzione seleziona il testo nel TextBox. Ad ogni modo, lo XAML per il buco DataGrid è simile a questo.

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

E il 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); } 
} 

Per una più informazioni, date un'occhiata al mio blog: http://blog.baltz.dk/post/2014/11/28/WPF-DataGrid-set-focus-and-mark-text

Problemi correlati