当 DataGridTemplateColumn 中的编辑文本框获得焦点时,如何选择所有文本?

发布于 2024-08-29 02:18:22 字数 2182 浏览 5 评论 0原文

当单元格进入编辑模式(按 F2)时,我试图让 DataGridTemplateColumn 的行为与 TextColumn 相同,

  • 默认情况下用户可以立即开始输入新值
  • ,选择现有文本内容 - 以便您可以设置新价值观 轻松

完成第一个任务;但是选择所有文本不起作用。正如许多帖子所提到的,尝试挂钩 GotFocus 事件并选择代码隐藏中的所有文本。这适用于独立的文本框;但是,对于作为 TemplateColumn 的编辑控件的文本框,这不起作用。

有什么想法吗? 代码示例:

<Window.Resources>
            <Style x:Key="HighlightTextBoxStyle" TargetType="{x:Type TextBox}">
                <EventSetter Event="GotFocus" Handler="SelectAllText"/>
                <EventSetter Event="GotMouseCapture" Handler="SelectAllText"/>
                <Setter Property="Background" Value="AliceBlue"/>
            </Style>

            <DataTemplate x:Key="DefaultTitleTemplate">
                <TextBlock Text="{Binding Title}"/>
            </DataTemplate>
            <DataTemplate x:Key="EditTitleTemplate">
                    <TextBox x:Name="Fox"
                         FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"  
                         Text="{Binding Path=Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                         Style="{StaticResource HighlightTextBoxStyle}">
                    </TextBox>
            </DataTemplate>
        </Window.Resources>
        <DockPanel>
            <TextBox DockPanel.Dock="Top" x:Name="Test" Text="{Binding Path=(FocusManager.FocusedElement).Name, ElementName=MyWindow}" 
                     Style="{StaticResource HighlightTextBoxStyle}"/>
            <toolkit:DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
                <toolkit:DataGrid.Columns>
                    <toolkit:DataGridTemplateColumn Header="Templated Title" 
                        CellTemplate="{StaticResource DefaultTitleTemplate}"
                        CellEditingTemplate="{StaticResource EditTitleTemplate}" />

                    <toolkit:DataGridTextColumn Header="Title" Binding="{Binding Path=Title}" />
                </toolkit:DataGrid.Columns>
            </toolkit:DataGrid>
        </DockPanel>

I'm trying to get a DataGridTemplateColumn to behave identically to a TextColumn

  • when the cell goes into edit mode (Press F2), the user can immediately start typing in the new value
  • by default, existing text content is selected - so that you can set new values easily

Got the first one done ; however selecting all the text isn't working. As mentioned by a number of posts, tried hooking into the GotFocus event and selecting all the text in code-behind. This worked for a standalone textbox ; however for a Textbox which is the edit control for a TemplateColumn, this doesn't work.

Any ideas?
Code Sample:

<Window.Resources>
            <Style x:Key="HighlightTextBoxStyle" TargetType="{x:Type TextBox}">
                <EventSetter Event="GotFocus" Handler="SelectAllText"/>
                <EventSetter Event="GotMouseCapture" Handler="SelectAllText"/>
                <Setter Property="Background" Value="AliceBlue"/>
            </Style>

            <DataTemplate x:Key="DefaultTitleTemplate">
                <TextBlock Text="{Binding Title}"/>
            </DataTemplate>
            <DataTemplate x:Key="EditTitleTemplate">
                    <TextBox x:Name="Fox"
                         FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"  
                         Text="{Binding Path=Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
                         Style="{StaticResource HighlightTextBoxStyle}">
                    </TextBox>
            </DataTemplate>
        </Window.Resources>
        <DockPanel>
            <TextBox DockPanel.Dock="Top" x:Name="Test" Text="{Binding Path=(FocusManager.FocusedElement).Name, ElementName=MyWindow}" 
                     Style="{StaticResource HighlightTextBoxStyle}"/>
            <toolkit:DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False">
                <toolkit:DataGrid.Columns>
                    <toolkit:DataGridTemplateColumn Header="Templated Title" 
                        CellTemplate="{StaticResource DefaultTitleTemplate}"
                        CellEditingTemplate="{StaticResource EditTitleTemplate}" />

                    <toolkit:DataGridTextColumn Header="Title" Binding="{Binding Path=Title}" />
                </toolkit:DataGrid.Columns>
            </toolkit:DataGrid>
        </DockPanel>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

2024-09-05 02:18:22

错过用答案更新帖子...

问题似乎是,对于自定义数据网格列(又名 DataGridTemplateColumn),网格无法知道编辑控件的确切类型(通过 DataTemplate 指定,并且可以可以是任何东西)。对于 DataGridTextColumn,编辑控件类型是已知的,因此网格可以找到它并调用其中的 SelectAll()。

因此,为了实现 TemplateColumn 的最终目标,您需要提供帮助。我忘记了第一次是如何解决这个问题的……但这是我今天搜索调整的一些内容。 使用PrepareCellForEdit方法的重写创建TemplateColumn的自定义派生,如下所示(用您的确切编辑控件交换文本框)。

public class MyCustomDataColumn : DataGridTemplateColumn
    {
        protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
        {
            var contentPresenter = editingElement as ContentPresenter;

            var editingControl = FindVisualChild<TextBox>(contentPresenter);
            if (editingControl == null)
                return null;

            editingControl.SelectAll();
            return null;
        }

        private static childItem FindVisualChild<childItem>(DependencyObject obj) 
    }

这是FindVisualChild 的实现

XAML:

   <WPFTestBed:MyCustomDataColumn Header="CustomColumn"
                    CellTemplate="{StaticResource DefaultTitleTemplate}"
                    CellEditingTemplate="{StaticResource EditTitleTemplate}"/>
</DataGrid.Columns>

大量代码导致恼人的不一致。

Missed updating the post with an answer...

The problem seems to be that for a custom data grid column (aka a DataGridTemplateColumn) the grid has no way of knowing the exact type of the editing control (which is specified via a DataTemplate and could be anything). For a DataGridTextColumn, the editing control type is known and hence the grid can find it and invoke a SelectAll() in it.

So to achieve the end-goal for a TemplateColumn, you need to provide an assist. I forgotten how I solved it the first time around.. but here is something that I searched-tweaked out today. Create a custom derivation of a TemplateColumn with an override of the PrepareCellForEdit method as shown below (Swap Textbox with your exact editing control).

public class MyCustomDataColumn : DataGridTemplateColumn
    {
        protected override object PrepareCellForEdit(FrameworkElement editingElement, RoutedEventArgs editingEventArgs)
        {
            var contentPresenter = editingElement as ContentPresenter;

            var editingControl = FindVisualChild<TextBox>(contentPresenter);
            if (editingControl == null)
                return null;

            editingControl.SelectAll();
            return null;
        }

        private static childItem FindVisualChild<childItem>(DependencyObject obj) 
    }

Here's an implementation for FindVisualChild.

XAML:

   <WPFTestBed:MyCustomDataColumn Header="CustomColumn"
                    CellTemplate="{StaticResource DefaultTitleTemplate}"
                    CellEditingTemplate="{StaticResource EditTitleTemplate}"/>
</DataGrid.Columns>

Lot of code for an annoying inconsistency.

迷迭香的记忆 2024-09-05 02:18:22

有点晚了...只是把它放在这里以防有人可以使用它

我在编辑时也有类似的需要在 DataGridTextColumn 中取消选择(或全选)文本

只需将该方法添加到 DataGrid 的 PreparingCellForEdit 事件

        DataGrid.PreparingCellForEdit += DataGrid_PreparingCellForEdit;

然后分配 ( e.EditingElement as TextBox),然后设置我的选项

 private void DataGrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
    {
        var txtBox = e.EditingElement as TextBox;
        txtBox.Select(txtBox.Text.Length, 0); //to DeSelect all and place cursor at end
        txtBox.SelectAll(); // to selectall
    }

Kinda VERY late...just putting this out here in case someone can use this

I had a similar need to DeSelect (or Select All) text in a DataGridTextColumn on editing

Just added the method to the PreparingCellForEdit event of the DataGrid

        DataGrid.PreparingCellForEdit += DataGrid_PreparingCellForEdit;

Then assigned the (e.EditingElement as TextBox) and then set my options

 private void DataGrid_PreparingCellForEdit(object sender, DataGridPreparingCellForEditEventArgs e)
    {
        var txtBox = e.EditingElement as TextBox;
        txtBox.Select(txtBox.Text.Length, 0); //to DeSelect all and place cursor at end
        txtBox.SelectAll(); // to selectall
    }
孤君无依 2024-09-05 02:18:22

我知道这已经太晚了,但我采取了不同的方法并创造性地扩展了 TextBox 类。我不太喜欢使用布尔值来检查文本是否已定义,但问题是选择事件在从绑定设置文本之前全部触发,因此 SelectAll() 没有任何内容可供选择!此类可能仅用作 DataGridTemplateColumn 等内容中的编辑模板。我针对这个问题找到的每一个解决方案几乎都是一种破解,所以我对此并没有感到太糟糕......:)

class AutoSelectTextBox : TextBox
{
    private bool _autoSelectAll= true;

    protected override void OnInitialized(EventArgs e)
    {
        // This will cause the cursor to enter the text box ready to
        // type even when there is no content.
        Focus();
        base.OnInitialized(e);
    }

    protected override OnKeyDown(System.Windows.Input.KeyEventArgs e)
    {
        // This is here to handle the case of an empty text box.  If
        // omitted then the first character would be auto selected when
        // the user starts typing.
        _autoSelectAll = false;
        base.OnKeyDown(e);
    }


    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        if (_autoSelectAll)
        {
            SelectAll();
            Focus();
            _autoSelectAll= false;
        }
        base.OnTextChanged(e);
    }
}

I know this is way late but I took a different approach and creatively extended the TextBox class. I don't really like using the boolean to check if the text is already defined but the problem is that the selection events all fire before the text is set from the binding so SelectAll() doesn't have anything to select! This class is probably only useful as a editing template in something like a DataGridTemplateColumn. Every solution I found for this issue is pretty much a hack so I don't feel too bad about this one ... :)

class AutoSelectTextBox : TextBox
{
    private bool _autoSelectAll= true;

    protected override void OnInitialized(EventArgs e)
    {
        // This will cause the cursor to enter the text box ready to
        // type even when there is no content.
        Focus();
        base.OnInitialized(e);
    }

    protected override OnKeyDown(System.Windows.Input.KeyEventArgs e)
    {
        // This is here to handle the case of an empty text box.  If
        // omitted then the first character would be auto selected when
        // the user starts typing.
        _autoSelectAll = false;
        base.OnKeyDown(e);
    }


    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        if (_autoSelectAll)
        {
            SelectAll();
            Focus();
            _autoSelectAll= false;
        }
        base.OnTextChanged(e);
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文