创建未显示的 UserControl 的快照
Create snapshot of a non-shown UserControl
我想拍摄我的 UserControl 的快照,但尚未显示。
那是我的代码:
public Screenshot(MyViewModel viewModel)
{
if (viewModel == null)
return;
// Create a TabControl, where View is hosted in
var visualTab = new TabControl();
visualTab.Width = FrameworkAdjustments.VisualSize.Width;
visualTab.Height = FrameworkAdjustments.VisualSize.Height;
visualTab.TabStripPlacement = Dock.Left;
// Tabs should only be shown, if there are more than one 'SubView'
Visibility tabVisibility = Visibility.Collapsed;
if (viewModel.SubViews.Count > 1)
tabVisibility = Visibility.Visible;
foreach (var subView in viewModel.SubViews)
{
var tab = new TabItem();
tab.Header = subView.TranslatedId; // multilanguage header
tab.Visibility = tabVisibility;
if (subView.Id == viewModel.ActiveSubView.Id)
{
tab.IsSelected = true;
// Without the following line my UI works, but my TabControl is empty.
tab.Content = ViewManager.GetViewById(subView.Id);
// ViewManager.GetViewById(subView.Id); returns a UserControl
}
tab.Measure(FrameworkAdjustments.VisualSize);
tab.Arrange(new Rect(FrameworkAdjustments.VisualSize));
visualTab.Items.Add(tab);
}
_ContentCtrl = new ContentControl() { Width = FrameworkAdjustments.VisualSize.Width, Height = FrameworkAdjustments.VisualSize.Height };
_ContentCtrl.Content = visualTab;
_ContentCtrl.Measure(FrameworkAdjustments.VisualSize);
_ContentCtrl.Arrange(new Rect(FrameworkAdjustments.VisualSize));
RenderTargetBitmap bmp = new RenderTargetBitmap((int)FrameworkAdjustments.VisualSize.Width, (int)FrameworkAdjustments.VisualSize.Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(_ContentCtrl);
this.ItemBrush = new ImageBrush(bmp);
}
当我启动我的应用程序时,此代码针对每个 'MyViewModel' 运行。
'MyViewModel' 包含一个 'SubViews' 的列表,它们是选项卡的内容,它们包含一个 'FunctionKeyBar',可以使用 'F1' 到 'F12' 激活按钮。但是在创建我的屏幕截图后,我不能再使用 F1 到 F12 了。还有其他问题,比如切换语言。
是否有其他方法可以创建尚未出现的控件的快照?
感谢大家的回复。
你好本尼
方法:将 Margin
设置为负值以使其隐藏,将控件添加到网格/任何其他容器。
按照以下步骤操作:
1) 创建一个 Task
以创建并添加您的 ContentControl
到 Grid
.
2) 调用用户定义的CaptureScreen ()
函数。
3) Visibility
不能是 Hidden/Collapsed。 Margin
可以为负隐藏控件。
在这个例子中,我是在 Button.Click
.
中完成的
async private void Button_Click(object sender, RoutedEventArgs e)
{
Task<ContentControl> t = AddContentControl();
ContentControl ctrl = await t;
RenderTargetBitmap bmp = CaptureScreen(ctrl, 5000, 5000);
Img.Source = bmp;
}
/* Add the ContentControl to the Grid, and keep it hidden using neg. Margin */
private Task<ContentControl> AddContentControl()
{
Task<ContentControl> task = Task.Factory.StartNew(() =>
{
ContentControl ctrl = null;
Dispatcher.Invoke(() =>
{
ctrl = new ContentControl() { Content = "Not shown", Width = 100, Height = 25, Margin = new Thickness(-8888, 53, 0, 0) };
Grd.Children.Add(ctrl);
});
return ctrl;
});
return task;
}
/* Important , wont work with Visibility.Collapse or Hidden */
private static RenderTargetBitmap CaptureScreen(Visual target, double dpiX, double dpiY)
{
if (target == null)
{
return null;
}
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
现在我找到了解决方案,感谢 AnjumSKan。
我拿了他的代码,稍微改了一下。正如我所说,我需要在应用程序启动或文化发生变化时创建快照,而且我有多个视图。在我的函数 AddContentControl
中,我将内容添加到具有负边距的 TabControl。添加我调用的结尾 HiddenTab.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new Action(CreateSnapshotOnRender));
('HiddenTab' 是我的 TabControl,未向用户显示)。这会调用一个名为 CreateSnapshotOnRender
的函数,我从中调用 AnjumSKhan 的 CaptureScreen
方法。之后我用我的下一个内容再次调用函数 AddContentControl
。这看起来如下:
private void CreateScreenshotOnRender()
{
HiddenTab.Measure(ViewSize);
HiddenTab.Arrange(new Rect(ViewSize));
var snapshot = CaptureScreen(HiddenTab, dpiX, dpiY);
/* Do anything with snapshot */
_Index++; // counter to know thich view is next
CreateAllScreenshots();
}
再次感谢 AnjumSKan,因为你引导我做到了这一点。这就是为什么我将您的答案标记为正确答案的原因。
我想拍摄我的 UserControl 的快照,但尚未显示。 那是我的代码:
public Screenshot(MyViewModel viewModel)
{
if (viewModel == null)
return;
// Create a TabControl, where View is hosted in
var visualTab = new TabControl();
visualTab.Width = FrameworkAdjustments.VisualSize.Width;
visualTab.Height = FrameworkAdjustments.VisualSize.Height;
visualTab.TabStripPlacement = Dock.Left;
// Tabs should only be shown, if there are more than one 'SubView'
Visibility tabVisibility = Visibility.Collapsed;
if (viewModel.SubViews.Count > 1)
tabVisibility = Visibility.Visible;
foreach (var subView in viewModel.SubViews)
{
var tab = new TabItem();
tab.Header = subView.TranslatedId; // multilanguage header
tab.Visibility = tabVisibility;
if (subView.Id == viewModel.ActiveSubView.Id)
{
tab.IsSelected = true;
// Without the following line my UI works, but my TabControl is empty.
tab.Content = ViewManager.GetViewById(subView.Id);
// ViewManager.GetViewById(subView.Id); returns a UserControl
}
tab.Measure(FrameworkAdjustments.VisualSize);
tab.Arrange(new Rect(FrameworkAdjustments.VisualSize));
visualTab.Items.Add(tab);
}
_ContentCtrl = new ContentControl() { Width = FrameworkAdjustments.VisualSize.Width, Height = FrameworkAdjustments.VisualSize.Height };
_ContentCtrl.Content = visualTab;
_ContentCtrl.Measure(FrameworkAdjustments.VisualSize);
_ContentCtrl.Arrange(new Rect(FrameworkAdjustments.VisualSize));
RenderTargetBitmap bmp = new RenderTargetBitmap((int)FrameworkAdjustments.VisualSize.Width, (int)FrameworkAdjustments.VisualSize.Height, 96, 96, PixelFormats.Pbgra32);
bmp.Render(_ContentCtrl);
this.ItemBrush = new ImageBrush(bmp);
}
当我启动我的应用程序时,此代码针对每个 'MyViewModel' 运行。 'MyViewModel' 包含一个 'SubViews' 的列表,它们是选项卡的内容,它们包含一个 'FunctionKeyBar',可以使用 'F1' 到 'F12' 激活按钮。但是在创建我的屏幕截图后,我不能再使用 F1 到 F12 了。还有其他问题,比如切换语言。 是否有其他方法可以创建尚未出现的控件的快照?
感谢大家的回复。
你好本尼
方法:将 Margin
设置为负值以使其隐藏,将控件添加到网格/任何其他容器。
按照以下步骤操作:
1) 创建一个 Task
以创建并添加您的 ContentControl
到 Grid
.
2) 调用用户定义的CaptureScreen ()
函数。
3) Visibility
不能是 Hidden/Collapsed。 Margin
可以为负隐藏控件。
在这个例子中,我是在 Button.Click
.
async private void Button_Click(object sender, RoutedEventArgs e)
{
Task<ContentControl> t = AddContentControl();
ContentControl ctrl = await t;
RenderTargetBitmap bmp = CaptureScreen(ctrl, 5000, 5000);
Img.Source = bmp;
}
/* Add the ContentControl to the Grid, and keep it hidden using neg. Margin */
private Task<ContentControl> AddContentControl()
{
Task<ContentControl> task = Task.Factory.StartNew(() =>
{
ContentControl ctrl = null;
Dispatcher.Invoke(() =>
{
ctrl = new ContentControl() { Content = "Not shown", Width = 100, Height = 25, Margin = new Thickness(-8888, 53, 0, 0) };
Grd.Children.Add(ctrl);
});
return ctrl;
});
return task;
}
/* Important , wont work with Visibility.Collapse or Hidden */
private static RenderTargetBitmap CaptureScreen(Visual target, double dpiX, double dpiY)
{
if (target == null)
{
return null;
}
Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
(int)(bounds.Height * dpiY / 96.0),
dpiX,
dpiY,
PixelFormats.Pbgra32);
DrawingVisual dv = new DrawingVisual();
using (DrawingContext ctx = dv.RenderOpen())
{
VisualBrush vb = new VisualBrush(target);
ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
}
rtb.Render(dv);
return rtb;
}
现在我找到了解决方案,感谢 AnjumSKan。
我拿了他的代码,稍微改了一下。正如我所说,我需要在应用程序启动或文化发生变化时创建快照,而且我有多个视图。在我的函数 AddContentControl
中,我将内容添加到具有负边距的 TabControl。添加我调用的结尾 HiddenTab.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Render, new Action(CreateSnapshotOnRender));
('HiddenTab' 是我的 TabControl,未向用户显示)。这会调用一个名为 CreateSnapshotOnRender
的函数,我从中调用 AnjumSKhan 的 CaptureScreen
方法。之后我用我的下一个内容再次调用函数 AddContentControl
。这看起来如下:
private void CreateScreenshotOnRender()
{
HiddenTab.Measure(ViewSize);
HiddenTab.Arrange(new Rect(ViewSize));
var snapshot = CaptureScreen(HiddenTab, dpiX, dpiY);
/* Do anything with snapshot */
_Index++; // counter to know thich view is next
CreateAllScreenshots();
}
再次感谢 AnjumSKan,因为你引导我做到了这一点。这就是为什么我将您的答案标记为正确答案的原因。