I'm trying to render a WPF based object as a PNG inside an ASP.NET image handler. We've created a designer in WPF that creates XAML based templates. Using the XAML serializer to store the templates on disk is simple. Pulling those same serialized XAML based objects and reconstituting them in an ASP.NET HTTP handler has proved difficult.
我试图将基于WPF的对象呈现为ASP中的PNG。网络图像处理程序。我们已经在WPF中创建了一个设计器来创建基于XAML的模板。使用XAML序列化器将模板存储在磁盘上是很简单的。提取那些基于XAML的序列化对象并在ASP中重构它们。NET HTTP处理程序被证明是困难的。
The XAML deserialization process needs to run on a STA thread. Creating a thread and setting it to STA and doing the deserialization and image composition worked, the first time. I get the reconstituted XAML based image created, passed back and sent to the browser. Subsequent calls to the HTTP handler crash the web server with "The calling thread cannot access this object because a different thread owns it."
XAML反序列化过程需要在STA线程上运行。创建一个线程并将其设置为STA并进行反序列化和图像合成,第一次成功。我得到了重新生成的基于XAML的映像创建,返回并发送到浏览器。随后对HTTP处理程序的调用会使web服务器与“调用线程无法访问这个对象,因为不同的线程拥有它”。
Are there any libraries out there that will generate an image from a simple XAML based object?
是否有一些库可以从一个简单的基于XAML的对象生成图像?
3 个解决方案
#1
2
I had answered this a while ago on the MSDN forums, but I'll copy that and tweak here for the prosterity of *. :)
我之前在MSDN论坛上回答过这个问题,但我会复制这个,并在这里对*的后代进行调整。:)
The simplest approach is spinning up a new STA thread everytime, letting that process one image and then the thread terminates and everything is cleaned up. That won't really scale so great though as the spin-up costs for the thread as well as all WPF Dispatcher infrastructure setup will add obvious overhead. You would want to look into having a pool of render ready threads that you farm the jobs out to. You should be able to basically spin up threads that just call Dispatcher::Run, and leave them sitting there. When a job comes in, you basically pull a thread out of the pool and call Invoke on the associated Dispatcher instance (you can get this by calling Dispatcher::FromThread) passing a delegate that contains all the rendering logic you want to execute in the context of that thread. When that finishes, the thread will remain running, because of Disptacher::Run call you made earlier, and you can return it to the pool for the next job to use. To clean up threads, just go to them and call Dispatcher::InvokeShutdown.
最简单的方法是每次都旋转一个新的STA线程,让这个线程处理一个映像,然后线程终止,所有的东西都清理干净。这并不是很好,因为线程的附带成本以及所有WPF分派器基础设施设置都会增加明显的开销。您可能希望查看是否有一个呈现就绪线程池,您可以将作业分配给它。您应该能够将只调用Dispatcher::Run的线程旋转起来,并将它们放在那里。当一个作业进入时,您基本上会从池中取出一个线程,并调用关联的分派器实例(您可以通过调用Dispatcher::FromThread)上的调用来传递一个委托,该委托包含您希望在该线程上下文中执行的所有呈现逻辑。当该操作完成时,线程将继续运行,这是由于前面调用的distacher:Run,您可以将其返回到池中,以便下一个作业使用。要清理线程,只需访问它们并调用Dispatcher:::InvokeShutdown。
#2
2
I have some example code in an answer to a similar question. Though as Drew pointed out, you would probably be better off re-using your threads by passing delegates to them. Also I think you could use XamlReader.Parse()
instead of programmatic creation.
对于类似的问题,我有一些示例代码。尽管正如Drew指出的,您最好通过将委托传递给线程来重用您的线程。我还认为可以使用XamlReader.Parse()而不是编程式创建。
#3
0
Have you considered creating a WPF shell application that just loads the templates you've created, screen shots them, and then saves the screenshot to disk? Then allow the application to accept command line args and pass in the template you want it to render and the name of the file you want it to generate.
您是否考虑过创建一个WPF shell应用程序,该应用程序只加载您创建的模板,对它们进行屏幕截图,然后将屏幕截图保存到磁盘?然后,允许应用程序接受命令行args并传入您希望它呈现的模板和要它生成的文件的名称。
Your web app could then just spin it off as a separate process, wait for it to complete, and grab the file. That way you wouldn't have to worry about running multiple STA threads.
然后,您的web应用程序可以将它作为一个单独的进程进行分离,等待它完成,然后获取文件。这样,您就不必担心运行多个STA线程。
#1
2
I had answered this a while ago on the MSDN forums, but I'll copy that and tweak here for the prosterity of *. :)
我之前在MSDN论坛上回答过这个问题,但我会复制这个,并在这里对*的后代进行调整。:)
The simplest approach is spinning up a new STA thread everytime, letting that process one image and then the thread terminates and everything is cleaned up. That won't really scale so great though as the spin-up costs for the thread as well as all WPF Dispatcher infrastructure setup will add obvious overhead. You would want to look into having a pool of render ready threads that you farm the jobs out to. You should be able to basically spin up threads that just call Dispatcher::Run, and leave them sitting there. When a job comes in, you basically pull a thread out of the pool and call Invoke on the associated Dispatcher instance (you can get this by calling Dispatcher::FromThread) passing a delegate that contains all the rendering logic you want to execute in the context of that thread. When that finishes, the thread will remain running, because of Disptacher::Run call you made earlier, and you can return it to the pool for the next job to use. To clean up threads, just go to them and call Dispatcher::InvokeShutdown.
最简单的方法是每次都旋转一个新的STA线程,让这个线程处理一个映像,然后线程终止,所有的东西都清理干净。这并不是很好,因为线程的附带成本以及所有WPF分派器基础设施设置都会增加明显的开销。您可能希望查看是否有一个呈现就绪线程池,您可以将作业分配给它。您应该能够将只调用Dispatcher::Run的线程旋转起来,并将它们放在那里。当一个作业进入时,您基本上会从池中取出一个线程,并调用关联的分派器实例(您可以通过调用Dispatcher::FromThread)上的调用来传递一个委托,该委托包含您希望在该线程上下文中执行的所有呈现逻辑。当该操作完成时,线程将继续运行,这是由于前面调用的distacher:Run,您可以将其返回到池中,以便下一个作业使用。要清理线程,只需访问它们并调用Dispatcher:::InvokeShutdown。
#2
2
I have some example code in an answer to a similar question. Though as Drew pointed out, you would probably be better off re-using your threads by passing delegates to them. Also I think you could use XamlReader.Parse()
instead of programmatic creation.
对于类似的问题,我有一些示例代码。尽管正如Drew指出的,您最好通过将委托传递给线程来重用您的线程。我还认为可以使用XamlReader.Parse()而不是编程式创建。
#3
0
Have you considered creating a WPF shell application that just loads the templates you've created, screen shots them, and then saves the screenshot to disk? Then allow the application to accept command line args and pass in the template you want it to render and the name of the file you want it to generate.
您是否考虑过创建一个WPF shell应用程序,该应用程序只加载您创建的模板,对它们进行屏幕截图,然后将屏幕截图保存到磁盘?然后,允许应用程序接受命令行args并传入您希望它呈现的模板和要它生成的文件的名称。
Your web app could then just spin it off as a separate process, wait for it to complete, and grab the file. That way you wouldn't have to worry about running multiple STA threads.
然后,您的web应用程序可以将它作为一个单独的进程进行分离,等待它完成,然后获取文件。这样,您就不必担心运行多个STA线程。