J'ai un programme dans lequel plusieurs onglets sont ajoutés dynamiquement à un objet TabControl
par programmation. Ce que je veux faire est de rendre la valeur de contenu de chacun de ces onglets à un PNG. J'utilise un script que j'ai récupéré ailleurs sur StackOverflow ou peut-être Google (perdu la source). Mon code ressemble à ceci:Rendu d'un contrôle de contenu dans un autre onglet de TabControl
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
}
}
}
Ce code fonctionne comme vous le souhaitez si je suis allé à travers et vu tous les onglets qui doivent être rendus avant d'invoquer ce code. Il va de l'avant et crée filePrefix_1.png, filePrefix_2.png, etc. avec le contenu correct rendu à partir de TabContentControl. Toutefois, si j'appelle le gestionnaire qui utilise ce code avant d'avoir consulté tous les onglets, mon code envoie une exception au new RenderTargetBitmap(...)
car content.RenderSize
est {0.0, 0.0}
. Lorsque j'essaie de forcer la taille de rendu d'un onglet non consulté à l'une des vues une fois, mon PNG en sortie est de dimensions correctes mais complètement vide.
Donc je suppose que j'ai besoin d'un moyen de forcer le rendu de TabContentControl. On dirait que l'événement Render est seulement exécuté, comme il se doit, lorsque l'UIElement doit être rendu. Est-ce que leur tromperie que je peux effectuer pour contourner cela?
J'ai aussi essayé de « truc » WPF dans la peinture d'un contenu de l'onglet en ajoutant le code suivant lorsque les onglets sont créés, dans un gestionnaire d'événements 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;
}
Lorsque la dernière ligne dans le gestionnaire Page_Loaded
est mis en commentaire, le dernier onglet est en évidence et la propriété RenderSize
est définie pour son contenu. Lorsque la dernière ligne n'est pas commentée, le premier onglet est en focus, avec le même comportement. Les autres onglets n'ont aucune information de rendu.
J'ai essayé de faire quelque chose de similaire mais pour la vie de moi, je n'arrivais pas à comprendre comment changer l'onglet visible par programmation. Essayé de mettre 'TabControl.SelectedItem' dans' TabItem' et d'incrémenter la propriété 'TabControl.SelectedIndex'. – sohum
En fait ... Je viens juste de réaliser que ce que je faisais était de changer les onglets après avoir cliqué sur le bouton de sauvegarde, depuis le gestionnaire ... donc je suppose qu'il n'y avait aucune possibilité de repeindre l'onglet? Je suppose que si je fais cela en ajoutant les onglets, ce ne sera pas un problème. – sohum
Juste essayé, ça n'a pas fonctionné. WPF semble optimiser et ne peindre que le dernier onglet ouvert. – sohum