WPF数据表格中弹出窗口的焦点问题

6

我正在创建一个自定义的UserControl,用于在DataGrid编辑模板中使用。它看起来像这样:

<UserControl
   x:Class="HR.Controls.UserPicker"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:tk="http://schemas.microsoft.com/wpf/2008/toolkit"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <Grid>
        <TextBlock x:Name="PART_TextBox" Text="Hello WOrld" />
        <Popup Width="234" Height="175" IsOpen="True" StaysOpen="True"

             Placement="Bottom"
             PlacementTarget="{Binding ElementName=PART_TextBox}"
         >
            <TextBox
                  x:Name="searchTextBox"
                  Text="&gt;Enter Name&lt;"/>
        </Popup>
    </Grid>
</UserControl>

编辑: 我已经缩小了代码范围。 看起来,如果我在CellEditingTemplate中直接放置带有文本框的弹出窗口,文本框就可以轻松获得焦点。但是当我将该代码移动到UserControl中时,在编辑单元格时就无法再选择文本框了。

UserControl是否对焦点进行了某些奇怪的处理?


问题在于,当我在数据网格中编辑单元格时,用户控件会显示出来,但我无法单击TextBox searchTextBox。当我单击它时,弹出窗口关闭并且单元格返回默认状态。

我尝试将用户控件内的所有代码复制并粘贴到CellEditingTemplate中,这样就可以按预期交互。

我只是想知道UserControl是否做了一些奇怪的事情,阻止弹出窗口获得焦点,因为直接放置在CellEditingTemplate中时可以正常工作。

谢谢, Raul


1
用户控件有点奇怪,不能将弹出窗口的焦点视为其自身的一部分。因此,我最终不得不创建一个自定义控件来代替用户控件。虽然费了些周折,但是获得的自由度是值得的。 - HaxElit
4个回答

4

不确定这是否会对任何人有帮助,但如果您在数据网格中使用自定义控件并带有弹出窗口,则可以使用此方法......这解决了我的问题,只需要一行xaml代码。我花了整整一天重新阅读了这个论坛,然后查看了DataGridCell的源代码。希望这能帮助到你。

    <Style TargetType="{x:Type DataGridCell}">
        <Setter Property="Focusable" Value="False"></Setter>
    </Style>

1
这是在DataGridCell内部拥有弹出窗口的最简单工作解决方案。 - Abbas

3
我曾遇到一个类似的问题,当在UserControl中嵌入一个Popup作为单元格编辑模板时,点击其某些区域会关闭它。问题在于 WPF Toolkit (以及 WPF4)的 DataGrid 处理左键点击时非常贪婪。即使您处理了它们并将 Handled 设置为 true,网格也可能将它们解释为单击不同的单元格。
这个线程有详细的信息,但修复的方法是钩入 DataGrid.CellEditEnding 事件并取消结束编辑。
private static void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
    if (e.Column.GetType() == typeof(DataGridTemplateColumn))
    {
        var popup = GetVisualChild<Popup>(e.EditingElement);
        if (popup != null && popup.IsOpen)
        {
            e.Cancel = true;
        }
    }   
}

private static T GetVisualChild<T>(DependencyObject visual)
    where T : DependencyObject
{
    if (visual == null)
        return null;

    var count = VisualTreeHelper.GetChildrenCount(visual);
    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(visual, i);

        var childOfTypeT = child as T ?? GetVisualChild<T>(child);
        if (childOfTypeT != null)
            return childOfTypeT;
    }

    return null;
}

这完全归功于Actipro线程


3

2
我曾经遇到一个类似的问题,我创建了一个包含文本框、按钮和日历的用户控件。基本上,我使用自定义验证逻辑创建了自己的日期选择器。
我把这个组件放在CellEditingTemplate中。当我按下按钮时,弹出窗口出现了,但是点击弹出窗口的任何地方都会导致单元格停止编辑(因为弹出窗口夺取了文本框的焦点)。我通过添加代码解决了这个问题,该代码表示如果弹出窗口打开,则不能丢失文本框的焦点。这对我起了作用。
此外,在用户控件的on loaded事件处理程序中,我将焦点设置给了文本框。在你的情况下,可能是用户控件本身获得了焦点。
protected override void OnPreviewLostKeyboardFocus(KeyboardFocusChangedEventArgs e) {
             // Don't allow focus to leave the textbox if the popup is open
             if (Popup.IsOpen) e.Handled = true;  
}

private void Root_Loaded(object sender, RoutedEventArgs e) {
       TextBox.Focus();
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接