【问题标题】:Hosting XNA inside WPF - Weird "Phantom" Window issue在 WPF 中托管 XNA - 奇怪的“幻影”窗口问题
【发布时间】:2011-11-05 08:12:48
【问题描述】:

我正在尝试使用 Windows 窗体主机控件在 WPF 窗口中托管 XNA 游戏。我有一个奇怪的问题,当我运行游戏时会创建一个“幻影”窗口。它是在第一次调用游戏的Update 方法退出时创建的。

这是更新代码,来自新 XNA 项目的默认代码:

    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();

        // TODO: Add your update logic here

        base.Update(gameTime);
    }

窗口是在 我从最底部的最后一个花括号开始创建之后创建的。 (是的,奇怪的是它不在base.Update 中,而是在它之后的} 之后。)

如前所述,我有一个 Windows 窗体主机,代码如下:

相关的 XAML 在这里(我显然已经设置了 Forms 命名空间等,因此无需在此处粘贴):

<WindowsFormsHost Margin="12" Name="windowsFormsHost1">
    <forms:Panel x:Name="p"></forms:Panel>
</WindowsFormsHost>

在代码隐藏中:

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        Viewer v = new Viewer(p.Handle);
        v.Run();
    }

Viewer 是我的 Game 类(来自 XNA),其中:

    public Viewer(IntPtr handle)
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        panelHandle = handle;
        graphics.PreparingDeviceSettings += new EventHandler<PreparingDeviceSettingsEventArgs>(graphics_PreparingDeviceSettings);
    }

    void graphics_PreparingDeviceSettings(object sender, PreparingDeviceSettingsEventArgs e)
    {
        e.GraphicsDeviceInformation.PresentationParameters.DeviceWindowHandle = panelHandle;
    }

这项技术来自我几天前发现的一篇博文(我现在再也找不到了,完全一样——除了这篇文章很旧并且没有我遇到的问题)。

问题是,我构建并运行,但与我的“正常”窗口一起,创建了一个幻像窗口。在我的主窗口中,XNA 正确渲染。但是幻像窗口(窗口标题是我的程序集的名称),里面没有任何东西,不可调整大小,光标不会在其中呈现,并且在我最小化这个窗口时它就像主窗口一样,我的主窗口停止呈现 XNA 内容,直到我取消最小化该幻像窗口。在我关闭两个窗口之前,我的程序不会退出。 (如果我只关闭幻像,我的主窗口,如你所料,会停止渲染我的 XNA 内容)。我尝试使用“App.Current.Windows”迭代我的应用程序窗口,而我所拥有的只是在那里列出的主窗口,这就是为什么我将那个半响应窗口称为“幻像”窗口。它在我的 WPF 对象模型中不可见。

当我写“XNA WPF 幻象窗口”时,我得到的第一个是:WPF: How to determine the origin of a phantom window?

所以我去尝试了 Snoop。但是 Snoop 可能还依赖于 Windows 迭代,并且它也看不到任何额外的窗口。我使用十字准线拖动功能(您在屏幕上拖动光标,Snoop 告诉它属于哪个进程和窗口),Snoop 告诉 Phantom Window 实际上是我的 MainWindow。但根据 Snoop 的说法,我的 MainWindow 也是同一个窗口。所以这个幻象与我的 MainWindow 实例有点密切相关(或者可能是“孩子”?),但我需要一种方法来关闭它(或者至少隐藏它)。

有什么想法吗?

【问题讨论】:

    标签: c# wpf xna xna-4.0


    【解决方案1】:

    我所知道的在 WPF 中嵌入 XNA 的两种好方法在这篇文章中(一种在文章本身中描述,另一种在文章的第一个链接中描述):

    http://blogs.msdn.com/b/nicgrave/archive/2011/03/25/wpf-hosting-for-xna-game-studio-4-0.aspx

    两者都有代码示例,我之前使用过 WriteableBitmap 版本,效果很好。 (我正在创建一个不需要显示大于 384x384 的任何东西的开发工具,因此 FPS 是可以接受的;如果您需要高 FPS 和较大的后台缓冲区(例如 800x600、720p 等),您肯定会想要使用HwndHost 方法)。

    我建议您尝试这两种中最适合您需求的一种。当您尝试使用 XNA 创建的窗口时,XNA 的 WinForms 窗口应该是一个顶级窗口。我尝试过解决诸如您过去发布的解决方案,但从未超出幻像窗口问题。

    【讨论】:

    • 嗯,一定有办法在某处纠正它。我想在执行此操作时尽可能保持高水平,而且我已经让事情正常工作了,只是有一个幻像窗口,所以应该有一个“单行代码”在某处将其关闭..
    【解决方案2】:

    我写了这个,现在才完成,也许这对你有帮助。我写它的目的是明确 XNA WPF 兼容性;也就是说,让 XNA 能够在 WPF 上的特定控件中呈现。试一试:

    https://xnaml.codeplex.com/

    【讨论】:

    • 看起来很酷。我会试一试,如果我喜欢它,我会用它来制作我的地图编辑器。
    • 很高兴知道。尽情享受吧,如果有什么需要补充的,请告诉我。
    【解决方案3】:

    除了只是一种解决方法之外,我认为我们坚持这是最好的,直到有新的东西出现..

    经过进一步调查,我发现幻象窗口是游戏实例的“窗口句柄”,是游戏持续运行所必需的。它可以作为游戏的窗口句柄访问,并从中创建(实际上是引用现有的)表单。游戏还阻止了 WPF TextBox 等对象的输入机制,我得到了一个非常不方便(但现在对我有用)的解决方法,方法是派生 TextBox 类并手动覆盖 OnKeyDown(它抓住了偶数但奇怪的是没有放在文本输入中。)并手动引发 TextInput 事件。有点hacky,但有效。使用表单,我可以将不透明度设置为零并将其移动到不在中间的某个位置,它会一直留在那里。

    但我的解决方案只是一个 hacky 解决方法,Mike 的解决方案肯定更好,所以如果您正在阅读本文并准备开始这样的新项目,请按照他的回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 2019-02-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多