У меня есть программа, в которой есть несколько вкладок, динамически добавляемых к объекту TabControl
программным способом. Что я хочу сделать, это отобразить значение Content каждой из этих вкладок в PNG. Я использую скрипт, который я нашел в другом месте на StackOverflow или, возможно, Google (потерял источник). Мой код выглядит так:
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. Есть ли какая-нибудь хитрость, которую я могу выполнить, чтобы обойти это?
Я также пытался «обмануть» WPF при рисовании содержимого вкладок, добавив следующий код при создании вкладок в обработчик событий Page_Loaded:
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
, определенное для ее содержимого. Когда последняя строка не закомментирована, первая вкладка находится в фокусе, с тем же поведением. Другие вкладки не содержат никакой информации об отрисовке.