我已经使用 ElementHost 在Windows应用程序中嵌入了WPF用户控件,方法是将 Child 属性设置为自定义用户控件。
不幸的是,我的文本框没有从按键接收任何输入,所以我根本不能使用我的加载项。
当我找到以下代码行时,我以为找到了解决办法。
ElementHost.EnableModelessKeyboardInterop([System.Windows.Window]);
这不起作用,因为我没有使用窗口。实际上,无法在元素主机中托管System.Windows.Window或使用该窗口作为主机。
这个加载项在开发过程中没有任何文本输入功能,所以事情已经完全停滞不前了。
如何让输入被我的文本框接受?
答案 0 :(得分:1)
我在网上找到了一个分包TextBox的链接,并允许按键original post
我略微改变了一些东西,但它几乎是一样的。它没有经过全面测试,但按键进入文本框。
class TextInput : TextBox
{
private const UInt32 DLGC_WANTARROWS = 0x0001;
private const UInt32 DLGC_WANTTAB = 0x0002;
private const UInt32 DLGC_WANTALLKEYS = 0x0004;
private const UInt32 DLGC_HASSETSEL = 0x0008;
private const UInt32 DLGC_WANTCHARS = 0x0080;
private const UInt32 WM_GETDLGCODE = 0x0087;
public TextInput()
{
Loaded += delegate
{
var s = PresentationSource.FromVisual(this) as HwndSource;
s?.AddHook(ChildHwndSourceHook);
};
}
static IntPtr ChildHwndSourceHook(IntPtr hwnd, int msg,
IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg != WM_GETDLGCODE) return IntPtr.Zero;
handled = true;
return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL);
}
}
另一个角度是创建元素主机的子类并在那里添加代码。这样,如果有任何进一步的钩子定制,你可以在一个地方进行调整,它将级联到你所有的wpf控件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Forms.Integration;
using System.Windows.Interop;
using Automated.ToolWindow;
namespace Automated
{
public class MyElementHost : ElementHost
{
protected override void Dispose(bool disposing)
{
if (_contentControl != null)
{
_contentControl.Loaded -= OnContentControlOnLoaded;
_contentControl = null;
}
base.Dispose(disposing);
}
private ContentControl _contentControl;
// Hide the child element.
public new UIElement Child
{
get { return base.Child; }
set
{
_contentControl = new ContentControl();
_contentControl.Loaded += OnContentControlOnLoaded;
_contentControl.Content = value;
base.Child = _contentControl;
}
}
private void OnContentControlOnLoaded(object sender, RoutedEventArgs e)
{
var s = PresentationSource.FromVisual(_contentControl) as HwndSource;
s?.AddHook(ChildHwndSourceHook);
}
private const UInt32 DLGC_WANTARROWS = 0x0001;
private const UInt32 DLGC_WANTTAB = 0x0002;
private const UInt32 DLGC_WANTALLKEYS = 0x0004;
private const UInt32 DLGC_HASSETSEL = 0x0008;
private const UInt32 DLGC_WANTCHARS = 0x0080;
private const UInt32 WM_GETDLGCODE = 0x0087;
static IntPtr ChildHwndSourceHook(IntPtr hwnd,
int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg != WM_GETDLGCODE) return IntPtr.Zero;
handled = true;
return new IntPtr(DLGC_WANTCHARS | DLGC_WANTARROWS | DLGC_HASSETSEL);
}
}
}
我在实施后添加主机的代码如下所示。
ElementHost = new MyElementHost()
{
Child = new RootXamlControl()
};
TaskPanes.Add(_host.TaskPanes.Add((int) ElementHost.Handle, "",
TaskPaneCaption, "Auto"));
旁注,如果您正在编写COM AddIn并且不注意内存管理,那么对于那些不得不关心垃圾收集的人来说,您将获得全新的欣赏。从C#.Net开发人员那里说出来!