【问题标题】:How to render a WPF UserControl to a bitmap without creating a window如何在不创建窗口的情况下将 WPF UserControl 呈现为位图
【发布时间】:2011-03-04 02:52:38
【问题描述】:

如何在不创建窗口的情况下将 WPF UserControl 呈现为位图?我需要渲染一个 WPF UserControl 并将其上传到另一个程序。位图将通过 Windows 服务呈现,因此创建窗口不是一种选择(我知道有“虚拟”创建窗口的方法,但不幸的是,在我的情况下,任何调用命令来创建窗口的方法都不是一种选择)。有没有办法在不将其绑定到 Window 的情况下渲染 UserControl?

【问题讨论】:

  • 也许您可以提供更多信息。如果无法呈现用户控件,为什么它甚至存在?它是一种视觉元素。
  • 需要渲染,但不能直接渲染到显示器上(所以不能有窗口)。它被渲染到一个 OpenGL 立方体。立方体渲染有效,但目前我必须创建一个单独的窗口来进行渲染。如果我不需要单独的窗口来进行 WPF 渲染,那就太好了。

标签: c# .net wpf windows graphics


【解决方案1】:

您是否尝试过启动用户控件的实例并执行以下操作:

UserControl control = new UserControl1();

control.Measure(new Size(300, 300));
control.Arrange(new Rect(new Size(300,300)));

RenderTargetBitmap bmp = new RenderTargetBitmap(300, 300, 96, 96, PixelFormats.Pbgra32);

bmp.Render(control);

var encoder = new PngBitmapEncoder();

encoder.Frames.Add(BitmapFrame.Create(bmp));

using (Stream stm = File.Create(@"c:\test.png"))
   encoder.Save(stm);

看来您需要测量、安排。这对我有用。

【讨论】:

  • Google search to export a user control to a JPG 把我带到了这里,这个答案很完美。非常感谢。
  • 这非常有效,但是底层样式没有正确地应用于用户控件。目前我不确定如何克服这个问题,否则是一个完美的解决方案!
  • 要完成这项工作,您是否必须让控件先前显示?我正在创建一个窗口,除非我以前 Show() 和 Close() 窗口,否则将得到黑色输出。
  • 如果对某人有帮助,请在 Arrange() 之后立即致电 control.UpdateLayout() 对我有用。
  • @SteveRobbins 有趣的是,当我从控件本身的 main 方法调用它时,我得到了相同的结果。但是,当我将代码移到 Control 中并仅在特定元素(即我想要的控件中的特定 Control)上调用该方法时,它的行为与描述的一样。这是除了必须根据 (at)dotNET 的建议调用 control.UpdateLayout() 之外,它还可以从我的 DataContext 中获取我的数据,而不仅仅是一个空白网格。
【解决方案2】:

最终使用了没有实际窗口的 HwndHost。

void cwind()
    {
        Application myapp = new Application();
        mrenderer = new WPFRenderer();
        mrenderer.Width = 256;
        mrenderer.Height = 256;

        HwndSourceParameters myparms = new HwndSourceParameters();
        HwndSource msrc = new HwndSource(myparms);
        myparms.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

        msrc.RootVisual = mrenderer;
        myapp.Run();
    }
    static IntPtr ApplicationMessageFilter(
IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        return IntPtr.Zero;
    }

【讨论】:

  • 我不得不稍微修改您的解决方案以使其适合我,但使用 Win32 包装器强制 WPF 在隐藏窗口中加载是个好主意。
  • @floele:也许对于某些解决方案,Win32 包装器是个好主意。但在这种情况下,我认为@RQDQ 有合适的解决方案。
  • 请告诉我什么是WPFRenderer? (那个程序集文件和命名空间在哪里)
  • 两个 cmets:1) WPFRenderer 似乎是一个自定义 UserControl。 2)这个解决方案是最好的,因为它支持绑定。简单地创建、测量和安排 UserControl(如@RQDQ 所建议的)是一种更简单、更优雅的解决方案,但不支持绑定。所以我想这取决于你的用例你应该做什么。
  • 如果您想在 xaml 中渲染动画\故事板,这也是解决方案。
【解决方案3】:

显然,如果您在测量和排列之后调用control.UpdateLayout(),则用户控件不需要在任何窗口中。

【讨论】:

    【解决方案4】:

    基于 IDWMaster 的解决方案,我使用 System.Windows.Forms.UserControl 做了一些不同的事情。否则,当导出到位图时,绑定不是最新的。这对我有用(this 是要呈现的 WPF 控件):

    System.Windows.Forms.UserControl controlContainer = new System.Windows.Forms.UserControl();
    controlContainer.Width = width;
    controlContainer.Height = height;
    controlContainer.Load += delegate(object sender, EventArgs e)
    {
        this.Dispatcher.BeginInvoke((Action)delegate
        {
            using (FileStream fs = new FileStream(path, FileMode.Create))
            {
                RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
                bmp.Render(this);
                BitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(bmp));
                encoder.Save(fs);
                controlContainer.Dispose();
            }
        }, DispatcherPriority.Background);
    };
    
    controlContainer.Controls.Add(new ElementHost() { Child = this, Dock = System.Windows.Forms.DockStyle.Fill });
    IntPtr handle = controlContainer.Handle;
    

    【讨论】:

      猜你喜欢
      • 2015-01-13
      • 2012-05-01
      • 2011-08-28
      • 1970-01-01
      • 1970-01-01
      • 2016-07-03
      • 1970-01-01
      • 2012-09-13
      • 1970-01-01
      相关资源
      最近更新 更多