如何在弹出窗口关闭后直接使用组合框来正确设置焦点

Ala*_*ain 5 c# wpf xaml .net-4.0

当用户从组合框中选择值时,如果他们选择了一个值,则会触发"SelectionChanged"事件,并设置新值并且一切正常.但是,如果他们决定不更改值并单击UI上的其他位置(如他们想要编辑的文本框),则必须单击两次 - 第一次单击只需关闭组合框弹出窗口,下一次单击将关注他们想要在第一次点击时激活的元素.

如何防止组合框弹出窗口在第一次点击时劫持焦点目标?

我已经尝试过监视ComboBox_LostFocus事件,但这会在错误的时间触发.当用户单击下拉列表并显示弹出列表时,ComboBox_LostFocus事件将触发 - 它将失去焦点到它自己的下拉列表.我不想做任何改变.当用户点击然后弹出窗口关闭时,ComboBox永远不会重新获得焦点(焦点只是'丢失'到所有东西),因此这个事件是无用的.

Ala*_*ain 6

我想我可能找到了解决方案.组合框确实有一个DropDownClosed事件 - 问题是它不是RoutedEvent,所以你不能为ComboBox创建一个样式并让它们都通过EventSetter继承事件.(你得到错误'DropDownClosed' must be a RoutedEvent registered with a name that ends with the keyword "Event")

但是,Loaded事件一个RoutedEvent,所以我们可以在样式中挂钩:

<Style x:Key="ComboBoxCellStyle" TargetType="ComboBox">
    <EventSetter Event="Loaded" Handler="ComboBox_Loaded" />
</Style>
Run Code Online (Sandbox Code Playgroud)

现在我们有一个事件总是会在ComboBox完成任何其他事情之前触发,我们可以挂钩到我们真正关心的事件:

private void ComboBox_Loaded(object sender, RoutedEventArgs e)
{
    ((ComboBox)sender).DropDownClosed -= ComboBox_OnDropDownClosed;
    ((ComboBox)sender).DropDownClosed += new System.EventHandler(ComboBox_OnDropDownClosed);
}
Run Code Online (Sandbox Code Playgroud)

现在我终于可以访问DropDown关闭时触发的事件,我可以执行我需要的任何操作,以确保焦点在麻烦的ComboBox上终止.在我的情况下,以下内容:

void ComboBox_OnDropDownClosed(object sender, System.EventArgs e)
{
    FrameworkElement visualElement = (FrameworkElement)sender;

    while( visualElement != null && !(visualElement is DataCell) )
        visualElement = (FrameworkElement)visualElement.TemplatedParent;
    if( visualElement is DataCell )
    {
        DataCell dataCell = (DataCell)visualElement;
        dataCell.EndEdit();
        if( !(dataCell.ParentRow is InsertionRow) ) dataCell.ParentRow.EndEdit();
    }
}
Run Code Online (Sandbox Code Playgroud)

我有一个ComboBox作为GridView中DataCell的模板,这个特殊问题阻止了DataRow在用户弹出打开ComboBox然后在网格外部单击时结束编辑.

这是我犯这个bug的最大问题.如果用户单击,则在此事件中设置焦点的次要问题.组合框也可能刚刚关闭,因为用户按Tab键或逃脱,所以我们不能只设置焦点到鼠标位置.我们需要有关导致DropDownClosed事件触发的更多信息.可能意味着在_Loaded事件处理程序中挂钩更多未被路由的事件.