我们正在开发WPF中的布局管理器,其具有可由用户移动/调整大小/等的视口.视口通常通过布局管理器中我们控制的提供程序填充数据(图片/电影/等).我的工作是检查它是否也可以在视口中托管任何外部Windows应用程序(即记事本,计算,土坯阅读器等).我遇到了一些问题.
大多数资源都指向使用HwndHost类.我正在试验微软本身的演练:http://msdn.microsoft.com/en-us/library/ms752055.aspx
我已经对此进行了调整,因此列表框将替换为外部应用程序的Windows句柄.任何人都可以帮我解决这些问题:
ListBox放置了该子窗口.我不认为我需要外部应用程序.如果我省略它,我必须使外部应用程序成为子窗口(使用来自user32.dll的Get/SetWindowLong设置GWL_STYLE为WS_CHILD).但是,如果我这样做,应用程序的菜单栏消失(因为WS_CHILD样式),它不再接收输入.HwndHost(因此可以移动到视口外).有什么办法可以阻止吗?HwndHost,但WindowsFormHost作为讨论在这里.它工作(并且更简单!)但我无法控制应用程序的大小?另外,WinFormHost真的不是这个意思吗?感谢您指出正确的方向.
我有一个Win32(OpenGL)控件,我需要嵌入我们的WPF应用程序.它必须响应并传播鼠标和键盘事件.
我已经创建了一个HwndHost派生实例来托管本机窗口并覆盖了这个类中的WndProc函数.要将win32消息传播到WPF,我处理特定的鼠标消息并将它们映射到WPF事件,然后使用静态InputManager类来引发它们.
问题是,当我去处理它们时,鼠标坐标会混乱.
下面是我用来引发事件的代码示例:
IntPtr MyHwndHost::WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, bool% handled)
{
switch (msg)
{
case WM_LBUTTONDOWN:
{
MouseButtonEventArgs^ eventArgs = gcnew MouseButtonEventArgs(
Mouse::PrimaryDevice,
Environment::TickCount,
MouseButton::Left);
eventArgs->RoutedEvent = UIElement::PreviewMouseDownEvent;
eventArgs->Source = this;
// Raise the WPF event from the specified WPF event source.
InputManager::Current->ProcessInput(eventArgs);
eventArgs->RoutedEvent = UIElement::MouseDownEvent;
InputManager::Current->ProcessInput(eventArgs);
CommandManager::InvalidateRequerySuggested();
handled = true;
return IntPtr::Zero;
}
break;
}
return HwndHost::WndProc(hwnd, msg, wParam, lParam, handled);
}
Run Code Online (Sandbox Code Playgroud)
当我的WPF事件处理程序被触发并且我尝试检索鼠标坐标(例如e.GetPosition((IInputElement) sender))时,我收到错误的值(并且无论我的控件中原始事件发生在何处,它们总是相同的值).
我得到的值似乎与托管应用程序的WPF窗口的屏幕位置有关,因为它们在窗口位置发生变化时会发生变化,但它们也不对应于应用程序窗口的实际位置.
我认为这可能与WPF InputManager的内部状态有关,而且私有字段MouseDevice._inputSource是null …
我有一个奇怪的错误,我试图调试没有运气.
我有子类hwndhost显示一些内容,我在该类中有以下功能设置为全屏:
private void SetFullScreen(bool enable)
{
if (enable)
{
fs = new Window();
fs.ResizeMode = ResizeMode.NoResize;
fs.WindowState = System.Windows.WindowState.Maximized;
fs.WindowStyle = System.Windows.WindowStyle.None;
fs.Topmost = true;
fs.PreviewKeyDown += delegate(object sender, KeyEventArgs e) {
if (e.Key==Key.Escape)
FullScreen = false;
};
fs.Show();
}
else
{
fs.Close();
fs = null;
}
}
Run Code Online (Sandbox Code Playgroud)
这在我的原型WPF应用程序中运行良好但是当我在我的主应用程序中使用此代码时,在关闭窗口(转义键)和fs.close()通话时出现此错误:
'{DependencyProperty.UnsetValue}' is not a valid value for property 'FocusVisualStyle'.
奇怪的是它在窗户关闭后大约1500ms发生.我已经尝试将FocusVisualStyle设置fs为null,但它看起来像是其他东西.直觉是它试图将另一个元素集中在我没有这个属性的app中,但我真的不知道!
谢谢!
编辑.问题是我的全屏按钮上的自定义设置FocusVisualStyle.我设置为{x:Null},问题就消失了.
有没有办法将HwndHost上发生的输入事件(主要是鼠标,但最终也是键盘输入)传递回基础WPF控件(例如面板)?我可以在HwndHost中连接到WndProc并重新发送Windows消息.我可以手动创建一个用于鼠标单击的routedevent并将其发送给父级以使其冒泡吗?和想法将不胜感激.谢谢jkersch
我一直在考虑这个问题,但我认为我对Windows和wpf如何在内部工作以解决这个问题缺乏一些基本的了解.
问题是这样的:
我创建了一个窗口,可以让我在空中标题栏(如办公室)上绘制wpf控件.只要我不向窗口添加Hwndhost元素,这种方法就可以正常工作,在这种情况下,每当我调整框架大小并且HwndHost开始闪烁时(其他元素似乎正确渲染).我也尝试使用WPF Shell Integration库中的自定义框架窗口实现,结果是一样的,所以我认为这不完全是我的错.
以下代码是一个简单的可编译程序,可以重现该问题.样本在c#中,但答案不一定是.
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
namespace DwmTest {
class Program {
[STAThread]
static void Main( ) {
var w = new CustomFrameWindow{ Content = new WindowHost() };
w.Show( );
((Border)VisualTreeHelper.GetChild( w, 0 )).Margin = new Thickness( 11, 33, 11, 11 );
Dispatcher.Run( );
}
}
public class CustomFrameWindow : Window {
const int resizeFrameWidth = 11;
const int captionHeight = 33;
public enum …Run Code Online (Sandbox Code Playgroud) 我想在我的 WPF 应用程序中托管一个外部进程的窗口。我是这样推导的HwndHost:
class HwndHostEx : HwndHost
{
[DllImport("user32.dll")]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
private IntPtr ChildHandle = IntPtr.Zero;
public HwndHostEx(IntPtr handle)
{
this.ChildHandle = handle;
}
protected override System.Runtime.InteropServices.HandleRef BuildWindowCore(System.Runtime.InteropServices.HandleRef hwndParent)
{
HandleRef href = new HandleRef();
if (ChildHandle != IntPtr.Zero)
{
SetParent(this.ChildHandle, hwndParent.Handle);
href = new HandleRef(this, this.ChildHandle);
}
return href;
}
protected override void DestroyWindowCore(System.Runtime.InteropServices.HandleRef hwnd)
{
}
}
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
HwndHostEx host = new HwndHostEx(handle);
this.PART_Host.Child = host;
Run Code Online (Sandbox Code Playgroud)
handle我想托管的外部窗口的句柄在哪里,是PART_Host我的 WPF …
在我的WPF应用程序中,我使用HwndHost托管Win32内容.但是,创建HwndHost不会创建本机窗口.相反,这是在重写的BuildWindowCore()方法中完成的,该方法稍后由WPF调用.
我的托管内容需要本机窗口的窗口句柄以进行自己的初始化.不幸的是,我无法强制创建窗口(即让WPF调用BuildWindowCore),所以我有第二个线程轮询HwndHost,直到它被初始化.
在.NET 4.0/WPF 4.0中,WindowInteropHelper.EnsureHandle()添加了一种新方法.我希望这可以解决这种情况,但它只适用于Window,而不适用于HwndHost(它不是从Window派生的).你有建议我可以做什么吗?
编辑:
我忘了为可能的解决方案添加更多约束:
我们有一个带有 Hwndhost 元素的 Wpf 应用程序,用于通过 DirectX 渲染 3D 内容。我们向客户端公开一个“Panel”接口,其中包含 MouseEnter 和 MouseLeave 事件。对于 Hwndhost“面板”,当我们第一次收到 HwndHost.WndProc 的 WM_MOUSEMOVE 事件时,我们模拟 MouseEnter 事件,因为 win32 没有 WM_MOUSEENTER 事件。另外,对于 HwndHost,我们通过 TrackMouseEvent() 请求 WM_MOUSELEAVE 事件,该事件在我们的“面板”界面上模拟 MouseLeave 事件。
问题是,当用户非常快速地将鼠标移动到 HwndHost 面板或从 HwndHost 面板移出时,我们会先收到鼠标移动到的面板的 Enter 事件,然后再收到鼠标移动的面板的离开事件。 当源面板和目标面板都是 wpf 元素时,不会发生这种情况,仅当涉及 hwndhost 元素时。另外,如果有两个 HwndHost 元素彼此相邻,则会发生相同的行为,因此看起来 win32 没有按照消息发生的顺序发送消息。
有谁知道解决这个问题的方法吗? 如果有一种方法可以让 Win32 按照事件发生的顺序发送事件,那就太好了。
下面是一个示例应用程序,它演示了向调试器输出窗口打印消息的问题:
// App.xaml.cs
using System;
using System.Windows;
using System.Runtime.InteropServices;
namespace WpfHostingWin32Control
{
public partial class App : Application
{
[DllImport("comctl32.dll", EntryPoint = "InitCommonControls", CharSet = CharSet.Auto)]
public static extern …Run Code Online (Sandbox Code Playgroud) hwndhost ×8
wpf ×8
.net ×2
c# ×2
winapi ×2
aero-glass ×1
dwm ×1
hwnd ×1
mouseenter ×1
mouseleave ×1
mousemove ×1
routedevent ×1
wpf-4.0 ×1