WPF DataGridTemplateColumn. Я что-то пропустил? - PullRequest
6 голосов
/ 09 июля 2009
     <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>              

Это понятный пример столбца Шаблон, верно? Что может быть не так с этим? Итак, вот в чем дело - когда пользователь перемещается по DataGrid, нажимая клавишу TAB, ему нужно дважды (!) Нажать TAB, чтобы иметь возможность редактировать текст в TextBox. Как я могу сделать его редактируемым, как только пользователь получит фокус на колонке, я имею в виду, даже если он только начинает печатать?

Ok. Я нашел способ - в Grid.KeyUp () я поместил код ниже:

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

Ответы [ 4 ]

8 голосов
/ 05 августа 2012

Проблема, с которой вы столкнулись, заключается в том, что элемент управления (например, TextBox) в DataGridTemplateColumn содержится в DataGridCell. По умолчанию DataGridCell имеет функцию табуляции. Таким образом, причина для того, чтобы дважды нажать TAB, чтобы получить фокус на вашем элементе управления TextBox. Решение состоит в том, чтобы отключить функцию табуляции для DataGridCell. Это можно сделать с помощью стиля для DataGridCell.

Вот решение:

<Style TargetType="{x:Type DataGridCell}">
     <Setter Property="KeyboardNavigation.IsTabStop" Value="False" />
</Style>
8 голосов
/ 07 января 2010

Ваша проблема проистекает из того факта, что каждая ячейка помещает свой редактор в элемент управления контентом, который сначала получает фокус, а затем вы должны снова перейти к редактору. Если вы посмотрите на код для DataGridTemplateColumn в методе GenerateEditingElement, он вызывает метод LoadTemplateContent, который делает это:

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

Посмотрите, как он создает нового предъявителя контента для вставки шаблона. Другие люди решали эту проблему различными способами, я получил свой собственный тип столбца, чтобы справиться с этим. (поэтому я не создаю дополнительный элемент и не настраиваю предъявителя контента на получение фокуса). В этом примере они используют диспетчер фокуса для решения той же проблемы (я не проверял этот код)

<tk:DataGridTemplateColumn.CellEditingTemplate>
   <DataTemplate>
      <Grid FocusManager.FocusedElement="{Binding ElementName=txt1}">
         <TextBox Name="txt1" Text="{Binding XPath=@ISBN}" 
                  BorderThickness="0" GotFocus="TextBox_GotFocus"/>
      </Grid>
   </DataTemplate>
</tk:DataGridTemplateColumn.CellEditingTemplate>

Если у вас есть пользовательский элемент управления в качестве редактора, вы можете использовать шаблон с менеджером фокуса или использовать обработчик событий для события OnLoaded.

3 голосов
/ 28 ноября 2014

Вот мой подход. Это очень близко к ответу @Nalin Jayasuriya, но я не хотел создавать стиль. Также это решение выделяет текст в TextBox. В любом случае - XAML для дыры DataGrid выглядит следующим образом.

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

И код позади.

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

Для получения дополнительной информации посмотрите мой блог: http://blog.baltz.dk/post/2014/11/28/WPF-DataGrid-set-focus-and-mark-text

0 голосов
/ 11 ноября 2011

Мой подход заключается в использовании действия TriggerAction, которое устанавливает фокус на элемент шаблона, который вы хотите при загрузке.

Триггер очень прост:

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

Шаблон данных выглядит так:

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

Вы можете написать другие триггеры для других типов элементов.

...