C# 在TabControl的另一个选项卡中呈现内容控件

C# 在TabControl的另一个选项卡中呈现内容控件,c#,wpf,tabcontrol,render,contentcontrol,C#,Wpf,Tabcontrol,Render,Contentcontrol,我有一个程序,其中有多个选项卡以编程方式动态添加到TabControl对象。我要做的是将每个选项卡的内容值呈现为PNG。我使用的脚本是我在StackOverflow或Google(丢失了源代码)上的其他地方找到的。我的代码如下所示: if (tabPanel.Items.Count > 0) { SaveFileDialog fileDialog = new SaveFileDialog(); fileDialog.Filter = "PNG|*.png"; fil

我有一个程序,其中有多个选项卡以编程方式动态添加到
TabControl
对象。我要做的是将每个选项卡的内容值呈现为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
        }
    }
}
如果我在调用此代码之前查看了所有必须呈现的选项卡,则此代码可以按预期工作。它继续使用从TabContentControl呈现的正确内容创建filePrefix_1.png、filePrefix_2.png等。但是,如果我在查看所有选项卡之前调用使用此代码的处理程序,我的代码会在
新建RenderTargetBitmap(…)
处引发异常,因为
content.RenderSize
{0.0,0.0}
。当我试图将未查看选项卡的渲染大小强制设置为“已查看一次”选项卡之一时,输出的PNG尺寸正确,但完全为空

所以我想我需要一些方法来强制呈现TabContentControl。似乎只有在需要渲染UIElement时才运行渲染事件,这是应该的。他们有什么诡计可以让我绕过这件事吗

我还试图通过在页面加载的事件处理程序中创建选项卡时添加以下代码来“欺骗”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;
}

当加载的
页面\u处理程序中的最后一行被注释掉时,最后一个选项卡处于焦点位置,并为其内容定义了
RenderSize
属性。当最后一行未注释掉时,第一个选项卡处于焦点,具有相同的行为。其他选项卡没有任何呈现信息。

这不是一个理想的解决方案,但当您创建选项卡并将其添加到选项卡控件时,您只需存储当前打开的选项卡,然后切换到刚刚创建的选项卡,然后切换回。对用户来说,这只是一个轻微的闪烁,但实际上,您只是在欺骗winforms(或wpf相应地)来绘制对象。

终于找到了,这要归功于。解决方案涉及为UIElement创建一个扩展方法,该方法使用一个刷新方法调用具有呈现优先级的空委托。显然,安排具有渲染优先级的内容会导致执行所有其他更重要的项,从而更改选项卡

删除博客时在此复制的代码:

public static class ExtensionMethods
{
   private static Action EmptyDelegate = delegate() { };

   public static void Refresh(this UIElement uiElement)
   {
      uiElement.Dispatcher.Invoke(DispatcherPriority.Render, EmptyDelegate);
   }
}

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;
        tabItem.Refresh();
    }
    // tabPanel.SelectedIndex = 0;
}

要使用它,只需将扩展名称空间包含在使用此功能所需的代码文件中,它就会出现在方法列表中。

我尝试过类似的操作,但我一直不知道如何以编程方式更改“可见”选项卡。尝试设置
TabControl。选择editem
TabItem
并增加
TabControl。选择了dex
属性。实际上。。。。。我刚刚意识到我所做的是在点击save按钮后,在处理程序中尝试更改选项卡。。。所以我想没有机会重新粉刷标签了?我想如果我在添加标签时这样做,这不会是一个问题。只是尝试了一下,它不起作用。WPF似乎进行了优化,并且只绘制最后打开的选项卡。在这种情况下,您可以始终逐个查看选项卡,并按需保存每个选项卡。我很确定我已经尝试过了,但我会再次尝试。我找到的最佳解决方案,谢谢。如果有人知道一个解决方案而不修改所选项目,这将是完美的。