我有一个程序,其中有多个标签动态添加到一个TabControl
对象编程。我想做的是呈现这些标签的内容值为PNG。我使用的脚本我拿起其他地方的StackOverflow或谷歌(丢失的源代码)。我的代码看起来像这样:
if (tabPanel.Items.Count > 0)
{
SaveFileDialog fileDialog = new SaveFileDialog();
fileDialog.Filter = "PNG|*.png";
fileDialog.Title = "Save Tabs";
fileDialog.ShowDialog();
if (fileDialog.FileName.Trim().Length > 0)
{
try
{
string filePrefix = fileDialog.FileName.Replace(".png", "");
int tabNo = 1;
foreach (TabItem tabItem in tabPanel.Items)
{
string filename = filePrefix + "_" + tabNo + ".png";
TabContentControl content = tabItem.Content as TabContentControl;
Rect rect = new Rect(content.RenderSize);
RenderTargetBitmap rtb = new RenderTargetBitmap((int)rect.Right, (int)rect.Bottom, 96d, 96d, System.Windows.Media.PixelFormats.Default);
rtb.Render(content);
BitmapEncoder pngEncoder = new PngBitmapEncoder();
pngEncoder.Frames.Add(BitmapFrame.Create(rtb));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
pngEncoder.Save(ms);
System.IO.File.WriteAllBytes(filename, ms.ToArray());
ms.Close();
tabNo++;
}
}
catch (Exception ex)
{
// log exception
}
}
}
这段代码可以按预期工作 * 如果 * 我已经浏览并查看了在调用这段代码之前必须呈现的所有选项卡。它会继续并创建filePrefix_1.png,filePrefix_2.png等。从TabContentControl呈现正确的内容。然而,如果我在查看所有选项卡之前调用使用此代码的处理程序,我的代码在new RenderTargetBitmap(...)
处抛出了一个异常,因为content.RenderSize
是{0.0, 0.0}
。当我试图将未查看的标签的渲染大小强制为已查看的标签之一时,我输出的PNG具有正确的尺寸,但完全为空。
所以我想我需要一些方法来强制渲染TabContentControl。似乎Render事件只在需要渲染UIElement时运行,因为它应该是。我可以执行任何技巧来解决这个问题吗?
我还尝试在创建选项卡时,在Page_Loaded事件处理程序中添加以下代码,“欺骗”WPF来绘制选项卡内容:
void Page_Loaded(object sender, RoutedEventArgs e)
{
// irrelevant code
foreach (// iterate over content that is added to each tab)
{
TabItem tabItem = new TabItem();
// load content
tabPanel.Items.Add(tabItem);
tabItem.IsSelected = true;
}
// tabPanel.SelectedIndex = 0;
}
当Page_Loaded
处理程序中的最后一行被注解掉时,最后一个选项卡处于焦点中,并为其内容定义了RenderSize
属性。当最后一行没有被注解掉时,第一个选项卡处于焦点中,具有相同的行为。其他选项卡没有任何呈现信息。
2条答案
按热度按时间txu3uszq1#
最后,多亏了this blog post,解决方案涉及到为UIElement创建一个扩展方法,该方法使用Refresh方法调用一个具有渲染优先级的空委托。显然,使用Render优先级调度某些内容会导致执行所有其他更重要的项目,从而更改选项卡。
在博客被删除的情况下复制以下代码:
要使用它,只需在需要使用此功能的代码文件中包含扩展名称空间,它就会出现在方法列表中。
elcex8rz2#
这并不是一个理想的解决方案,但是当你创建标签并将它们添加到标签控件时,你可以只保存当前打开的标签,然后切换到你刚刚创建的标签,然后再切换回来。对于用户来说,这只是一个轻微的 Flink ,但实际上你只是欺骗了winforms(或相应的wpf)来绘制对象。