我有一个带有Helix3DToolkit图形的WPF UI。
我有两个按钮,
第一个按钮 - 向其中添加一些Visual3D对象。
第二个按钮 - 使用
将当前UI的屏幕截图保存为jpeg图像
截图代码:
Viewport3DHelper.Export(vp.Viewport, filename);
所有这些都可以手动完成。但现在我想让它自动化。 (按钮1和2的几个交替轮次动作,即我只想按一个按钮,这将添加一些框,保存屏幕截图,添加更多,保存屏幕截图等。)
我可以使用以下命令以编程方式控制按钮:
ButtonAutomationPeer peer = new ButtonAutomationPeer(MyButton);
IInvokeProvider invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProv.Invoke();
但是当我这样做时,我得到的只是同一个UI的几个副本。 (这是由于UI线程的性质,我相信)
我找到了一个部分解决方案,即使用
TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
CancellationToken cancellationToken = new CancellationToken();
Task.Factory.StartNew(() => GetScreenShotAction()).ContinueWith(w =>
{
AddBoxes();
}, cancellationToken, TaskContinuationOptions.None, scheduler);
但是,这也不能正常工作(它只是随机工作,当我只拍摄2张截图时,但从不超过2张时)。这可能是因为前后操作都在UI线程上。
有关如何完成此任务的任何想法都将受到高度赞赏。
我也在使用VC#2010和.NET 4框架。因此无法使用async
和await
。
谢谢!
我已经在this.Dispatcher.Invoke((Action)(() => { ... }));
方法中使用了GetScreenShotAction
。而且,另一个动作AddBoxes
在同一个帖子上。
此外,它随机工作,所以我猜测因为我调用Dispatcher,两者在技术上仍然在同一个线程上发生。
答案 0 :(得分:0)
使用Task
进行多线程操作,您在正确的轨道上。问题是您需要在正确的Invoke
上Thread
代码。使用Dispatcher
(又名WPF UI线程)通过Application.Current.Dispatcher
拨打Invoke()
或BeginInvoke()
,根据需要执行此操作。
答案 1 :(得分:0)
我怀疑在你拍摄截图之前,你需要等待UI渲染(在通过添加按钮修改可视树之后,等等)。
This article显示了如何使用调度程序DispatcherPriority.Render
来让代码在继续之前等待所有渲染完成。
引用文章:
当DispatcherPriority设置为Render(或更低)时,代码将 然后执行具有该优先级或更高优先级的所有操作。在 例如,代码已经将label1.Content设置为其他内容, 这将导致渲染操作。所以通过电话 Dispatcher.Invoke,代码本质上要求系统执行所有操作 渲染或更高优先级的操作,因此控件将 然后渲染自己(绘制新内容)。之后,它会 然后执行提供的委托(这是我们的空方法)。
Refresh扩展方法的代码:
public static class ExtensionMethods
{
private static Action EmptyDelegate = delegate() { };
public static void Refresh(this UIElement uiElement)
{
uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
}
}
使用类似:
AddBoxes();
MyControlContainer.Refresh();
TakeScreenShot();
MyControlContainer
是UIElement
的位置,也就是您将这些框添加到的容器?