You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何恢复Outlook VSTO插件中WPF MaterialDesign DialogContent的输入焦点

这个问题是WPF控件在非WPF宿主(比如Outlook VSTO、WinForm宿主)中常见的Win32焦点与WPF键盘路由不同步问题,根源是切换到外部窗口后,Win32层面的活动窗口没有切回WPF控件所在的任务窗格窗口,导致键盘消息被定向到之前的活动窗口,仅修改WPF内部的焦点状态无效。
可按以下步骤依次尝试修复:

步骤1:引入Win32 API声明

首先在你的WPF控件的后台代码类中添加Win32 API导入:

[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);

步骤2:绑定Dialog内容控件的鼠标点击事件

给你的DialogContentControl添加PreviewMouseDown事件绑定,事件处理逻辑如下:

private void DialogContentControl_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    // 获取当前WPF控件绑定的Win32窗口句柄源
    var hwndSource = HwndSource.FromVisual(sender as Visual) as HwndSource;
    if (hwndSource == null) return;
    
    // 先将Win32层面的活动窗口切到当前WPF控件所在窗口
    SetForegroundWindow(hwndSource.Handle);
    
    // 同步WPF输入上下文的焦点状态
    hwndSource.DocumentInput?.KeyboardFocus?.Navigate(new TraversalRequest(FocusNavigationDirection.First));
    
    // 给当前点击的控件设置焦点
    if (e.OriginalSource is UIElement targetElement)
    {
        targetElement.Focus();
        Keyboard.Focus(targetElement);
        e.Handled = true;
    }
}

步骤3:调整DialogHost的XAML配置

在materialDesign:DialogHost节点上补充以下焦点相关属性,优化WPF内部的焦点路由:

<materialDesign:DialogHost
    Focusable="True"
    IsTabStop="True"
    KeyboardNavigation.TabNavigation="Cycle"
    KeyboardNavigation.ControlTabNavigation="Local"
    <!-- 保留你原来的其他属性配置 -->
    >
    <!-- 你原来的DialogContent配置不变 -->
    <materialDesign:DialogHost.DialogContent>
        <ContentControl x:Name="DialogContentControl"
            ContentTemplateSelector="{StaticResource  DTSDialogObject}"
            Focusable="True"
            Content="{Binding DialogViewModel,
            UpdateSourceTrigger=PropertyChanged,
            Mode=OneWay}"
            HorizontalAlignment="Center"
            Width="300"
            VerticalAlignment="Center"
            HorizontalContentAlignment="Center"
            VerticalContentAlignment="Center" />
    </materialDesign:DialogHost.DialogContent>
</materialDesign:DialogHost>

可选补充方案

如果弹窗打开时就需要默认定位到第一个输入框,可在DialogViewModel赋值后调用以下逻辑,延迟设置焦点避免视觉树未渲染导致的设置失效:

Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
{
    // 自己实现FindChild扩展方法查找弹窗内第一个可输入的文本框
    var firstInput = DialogContentControl.FindChild<TextBox>();
    if (firstInput != null)
    {
        firstInput.Focus();
        Keyboard.Focus(firstInput);
    }
}));

内容的提问来源于stack exchange,提问作者buks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 02:54:03