如何在没有 Window 的情况下使用 KeyPresses 在 ElementHost 中托管 WPF UserControl
How to host a WPF UserControl in ElementHost without Window with KeyPresses
我使用 ElementHost 通过设置 Child [=32] 在 windows 应用程序中嵌入了 WPF 用户控件=] 到自定义用户控件。
不幸的是,我的文本框没有接收到任何按键输入,所以我根本无法使用我的加载项。
当我发现以下代码行时,我以为我找到了解决方法。
ElementHost.EnableModelessKeyboardInterop([System.Windows.Window]);
这将不起作用,因为我没有使用 window。其实没有办法在element host中托管一个System.Windows.Window或者用window作为host.
此插件在开发相当长一段时间之前没有任何文本输入功能,因此它已经完全停滞了。
如何让我的文本框接受输入?
我在网上找到了 link 子类 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);
}
}
另一个角度是创建元素主机的子class 并在那里添加代码。这样,如果有任何进一步的挂钩自定义,您可以在一个地方进行调整,它将级联到您所有的 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 加载项并且不注意内存管理,那么对于那些不得不关心垃圾收集的人来说,您将获得全新的赞赏。来自 C#.Net 开发人员的演讲!
我使用 ElementHost 通过设置 Child [=32] 在 windows 应用程序中嵌入了 WPF 用户控件=] 到自定义用户控件。
不幸的是,我的文本框没有接收到任何按键输入,所以我根本无法使用我的加载项。
当我发现以下代码行时,我以为我找到了解决方法。
ElementHost.EnableModelessKeyboardInterop([System.Windows.Window]);
这将不起作用,因为我没有使用 window。其实没有办法在element host中托管一个System.Windows.Window或者用window作为host.
此插件在开发相当长一段时间之前没有任何文本输入功能,因此它已经完全停滞了。
如何让我的文本框接受输入?
我在网上找到了 link 子类 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);
}
}
另一个角度是创建元素主机的子class 并在那里添加代码。这样,如果有任何进一步的挂钩自定义,您可以在一个地方进行调整,它将级联到您所有的 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 加载项并且不注意内存管理,那么对于那些不得不关心垃圾收集的人来说,您将获得全新的赞赏。来自 C#.Net 开发人员的演讲!