如何在elementthost中托管一个没有窗口的WPF用户控件
本文关键字:一个 窗口 控件 用户 WPF elementthost | 更新日期: 2023-09-27 18:12:33
我使用ElementHost将子属性设置为自定义用户控件,在windows应用程序中嵌入了一个WPF用户控件。
不幸的是,我的文本框没有从按键接收任何输入,所以我根本不能使用我的加载项。
当我发现下面一行代码时,我以为我找到了一个解决方法。
ElementHost.EnableModelessKeyboardInterop([System.Windows.Window]);
这将不工作,因为我没有使用窗口。事实上,没有办法在元素宿主中驻留System.Windows.Window,或者使用该窗口作为宿主。
这个插件没有任何文本输入功能,直到开发到相当长的一段时间,所以事情已经完全停滞不前。
我怎样才能让输入被我的文本框接受?
我在网上找到了一个链接,子类TextBox和允许按键原创文章
我稍微改变了一些东西,但它几乎是一样的。它还没有完全测试过,但是按键进入了文本框。
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插件,并且不关注内存管理,那么你会对那些不得不关心垃圾收集的人有一个全新的认识。用c#说的。网络开发人员!