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

Đó là ví dụ rõ ràng về cột Mẫu, phải không? Điều gì có thể sai với điều đó? Vì vậy, đây là điều - khi một người dùng điều hướng thông qua DataGrid với nhấn TAB-key, nó cần phải nhấn TAB hai lần (!) Để có thể chỉnh sửa văn bản trong TextBox. Làm thế nào tôi có thể làm cho nó có thể chỉnh sửa ngay sau khi người dùng nhận được tiêu điểm cột, tôi có nghĩa là ngay cả khi anh ta chỉ bắt đầu gõ?WPF DataGridTemplateColumn. Tui bỏ lỡ điều gì vậy?

Ok. Tôi tìm thấy một cách - thành Grid.KeyUp() tôi đặt vào mã bên dưới:

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

Trả lời

8

vấn đề của bạn bắt nguồn từ thực tế là mỗi tế bào đặt biên tập viên của nó trong một điều khiển nội dung mà đầu tiên nhận lấy nét, sau đó bạn phải tab một lần nữa để biên tập viên. Nếu bạn có một cái nhìn tại các mã cho DataGridTemplateColumn trong phương pháp GenerateEditingElement mà họ gọi là LoadTemplateContent phương pháp mà thực hiện điều này:.

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

xem làm thế nào nó tạo ra một người dẫn chương trình nội dung mới để đưa mẫu ở những người khác đã bị xử lý này vấn đề theo nhiều cách khác nhau, tôi lấy được loại cột của riêng mình để đối phó với công cụ này. (Vì vậy tôi không tạo ra một yếu tố thêm hoặc thiết lập người dẫn chương trình nội dung để không nhận được tập trung) Trong example này họ đang sử dụng quản lý tập trung để đối phó với vấn đề tương tự (i havent kiểm tra mã này)

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

Nếu bạn có một điều khiển người dùng làm trình chỉnh sửa của bạn, sau đó bạn có thể sử dụng mẫu với trình quản lý tập trung hoặc sử dụng trình xử lý sự kiện cho sự kiện được tải sẵn.

+0

một công trình xử, nhưng điều này thực sự là một hack xấu xí ... :(Tôi muốn MS sẽ tìm ra một cách tốt đẹp của cung cấp loại chức năng này – David

+0

Phương pháp FocusManager hoạt động tốt Để có được nội dung được chọn, bạn cũng có thể thêm phương thức lấy tiêu điểm: void riêng StrikeTextBox_GotFocus (đối tượng người gửi, RoutedEventArgs e) { var textBox = (TextBox) sender ; Dispatcher.BeginInvoke (Hành động mới (textBox.SelectAll)); } – Neil

0

Cách tiếp cận của tôi là sử dụng TriggerAction đặt tiêu điểm vào phần tử mẫu bạn muốn khi tải.

Trigger là rất đơn giản:

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

Các DataTemplate trông như thế này:

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

Bạn có thể viết trigger khác với nhiều loại nguyên tố khác.

+1

Tôi nghĩ rằng chức năng này yêu cầu một dll từ Expression Blend – Neil

7

Vấn đề mà bạn phải đối mặt là kiểm soát (ví dụ: Hộp văn bản) trong DataGridTemplateColumn được chứa trong một DataGridCell. Theo mặc định, DataGridCell có chức năng dừng tab. Vì vậy, lý do phải nhấn TAB hai lần để tập trung vào việc điều khiển TextBox của bạn. Giải pháp là tắt chức năng tab-stop cho DataGridCell. Điều này có thể được thực hiện thông qua một phong cách cho DataGridCell.

Dưới đây là giải pháp:

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

Đây là cách tiếp cận của tôi. Nó rất gần với câu trả lời của @Nalin Jayasuriya, nhưng tôi không muốn tạo ra một phong cách. Ngoài ra giải pháp này chọn văn bản trong TextBox. Dù sao - XAML cho lỗ DataGrid trông như thế này.

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

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

Đối với một biết thêm, có một cái nhìn tại blog của tôi: http://blog.baltz.dk/post/2014/11/28/WPF-DataGrid-set-focus-and-mark-text

Các vấn đề liên quan