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

Es un claro ejemplo de columna de plantilla, ¿verdad? Qué podría estar mal con eso? Así que, aquí está la cosa: cuando un usuario navega a través de DataGrid presionando la tecla TAB, necesita presionar la tecla TAB dos veces (!) Para poder editar texto en TextBox. ¿Cómo podría hacerlo editable tan pronto como el usuario obtenga el foco de la columna, es decir, incluso si acaba de comenzar a escribir?WPF DataGridTemplateColumn. ¿Me estoy perdiendo de algo?

Ok. He encontrado una manera - en Grid.KeyUp() pongo el código de abajo:

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

Respuesta

8

su problema se deriva del hecho de que cada célula pone su editor en un control de contenido que por primera vez recibe el foco, entonces usted tiene que pestaña una vez más al editor. Si usted tiene un vistazo al código de DataGridTemplateColumn en el método GenerateEditingElement que llama una LoadTemplateContent método que hace esto:.

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

ver cómo se crea un nuevo presentador de contenido para poner la plantilla en Otras personas han ocupado de este problema en una variedad de formas, obtengo mi propio tipo de columna para tratar con estas cosas. (Así que no crear un elemento extra o establecer el presentador de contenido a no recibir el foco) En este example que están utilizando gestor de selección para lidiar con el mismo problema (no he probado este código)

<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 usted tiene una control del usuario como su editor, entonces puede usar el patrón con el administrador de enfoque o usar un controlador de eventos para el evento OnLoaded.

+0

funciona un tratamiento, pero esto es realmente un truco feo ... :(Deseo MS sería encontrar una buena manera de proporcionar este tipo de funcionalidad – David

+0

El método FocusManager funciona bien el fin de obtener los contenidos seleccionados, también se puede añadir un método tiene el foco:. privada vacío StrikeTextBox_GotFocus (remitente del objeto, RoutedEventArgs e) { var textBox = (Cuadro de texto) emisor ; Dispatcher.BeginInvoke (new Action (textBox.SelectAll)); } – Neil

0

Mi enfoque es utilizar un TriggerAction que establece el foco en el elemento de la plantilla que desea cuando se carga.

El disparador es muy simple:

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

El DataTemplate se parece a esto:

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

Puede escribir otros factores desencadenantes de otros tipos de elementos.

+1

Creo que esta funcionalidad requiere una DLL de Expression Blend – Neil

7

El problema al que se enfrentó es que el control (por ejemplo, TextBox) dentro de DataGridTemplateColumn está dentro de un DataGridCell. Por defecto, DataGridCell tiene funcionalidad de tab-stop. Por lo tanto, la razón para tener que presionar TAB dos veces para enfocar tu control TextBox. La solución es desactivar la funcionalidad de tabulación para DataGridCell. Esto se puede hacer a través de un estilo para DataGridCell.

Aquí está la solución:

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

Aquí es mi enfoque. Está muy cerca de la respuesta de @Nalin Jayasuriya, pero no quería crear un estilo. También esta solución selecciona el texto en el TextBox. De todos modos, el XAML para el agujero DataGrid se ve así.

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

Y el código subyacente.

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

Para una mayor información, echar un vistazo a mi blog: http://blog.baltz.dk/post/2014/11/28/WPF-DataGrid-set-focus-and-mark-text

Cuestiones relacionadas