简体   繁体   English

WPF:如何在 ItemsControl 中生成项目的屏幕截图(在 TabView 中)

[英]WPF: How to generate screenshots of items within a ItemsControl (within a TabView)

I have a TabControl where each tab is a user control that has an ItemsControl in it.我有一个 TabControl,其中每个选项卡都是一个用户控件,其中包含一个 ItemsControl。 The TabControl is bound to a collection and has an ItemTemplate: TabControl 绑定到一个集合并有一个 ItemTemplate:

<DataTemplate x:Key="tabContentTemplate">
            <tabs:VisualizationTab x:Name="VisualizationTab"/>
        </DataTemplate>

<TabControl x:Name="tabControl" SelectionChanged="tabControl_SelectionChanged"
     ItemsSource="{Binding TabViewModels, Mode=TwoWay}" ItemHeaderTemplate="{StaticResource tabHeaderTemplate}"
     ItemTemplate="{StaticResource tabContentTemplate}"/>

Likewise, the ItemsControl in each tab is bound to data (complicated by a TemplateSelector).同样,每个选项卡中的 ItemsControl 都绑定到数据(由 TemplateSelector 复杂化)。

    <UserControl.Resources>
        <DataTemplate x:Key="classOneTemplate">
            <charts:PlotOne DataContext="{Binding Converter={StaticResource plotOneViewModelConverter}}" />
        </DataTemplate>
        <DataTemplate x:Key="classTwoTemplate">
            <charts:PlotTwo DataContext="{Binding Converter={StaticResource plotTwoViewModelConverter}}" />
        </DataTemplate>
    <local:VisualizationTemplateSelector ClassOneTemplate="{StaticResource classOneTemplate}" ClassTwoTemplate="{StaticResource classTwoTemplate}"
                                                 x:Key="visualizationTemplateSelector" />
    </UserControl.Resources>

<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <ItemsControl x:Name="visualizationItemsControl" ItemsSource="{Binding Path=VisualizationSpecs}" ItemTemplateSelector="{StaticResource visualizationTemplateSelector}">
            <!-- ItemsPanelTemplate -->
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="{ Binding Path=ColumnCount}" Rows="{ Binding Path=RowCount}" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
        </ItemsControl>
    </Grid>

I'd like to get a collection of collection of images for all the items (to use as scaled down images in another part of UI).我想获取所有项目的图像集合(在 UI 的另一部分用作按比例缩小的图像)。 I am having difficulty for two reasons: 1) trying to access the items of the TabControl/ItemsControl gives the dataitems not the visual items and 2) the visual elements of the TabControl are only created for the currently selected tab.我遇到困难有两个原因:1) 尝试访问 TabControl/ItemsControl 的项目给出的是数据项而不是视觉项目,以及 2) TabControl 的视觉元素仅为当前选定的选项卡创建。

My thought was to capture each Tab when the Tab is selected and store this with something like:我的想法是在选择选项卡时捕获每个选项卡并将其存储为:

private void tabControl_SelectionChanged(object sender, TabControlSelectionChangedEventArgs e)
{
    WorkspaceViewModel workspaceViewModel = tabControl.SelectedItem as WorkspaceViewModel;
    if (workspaceViewModel is null)
        return;
    tabControl.Dispatcher.BeginInvoke(new Action(() =>
    {
        VisualizationTab visualizationTab = FindVisualChild<VisualizationTab>(tabControl);
        workspaceViewModel.SetVisualizationTab(visualizationTab);
    }));
}

Is there a better way of doing this?有更好的方法吗?

And do I have to do the same thing with getting the visual children of the ItemsControl to get an image for each item?我是否必须做同样的事情来让 ItemsControl 的视觉子项为每个项目获取图像?

Here is some code that I have used in the past to generate pictures from controls/screen (I usually wrap the control I am trying to take a picture of in a grid/border for simplicity)这是我过去用来从控件/屏幕生成图片的一些代码(为简单起见,我通常将要拍摄的控件包装在网格/边框中)

using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

public enum EncodingTypes : int
{
    BMP,
    GIF,
    JPEG,
    PNG,
    TIFF,
    WMP
}

public static class ImageHelper
{
    #region " FrameworkElementToBitmap "
    /// <summary>
    /// FrameworkElementToBitmap
    /// During signature capture, boundary does not get calculated correctly when user draws off the canvas.
    /// Use a hidden border to determine the canvas boundary when capturing signature.
    /// </summary>
    /// <param name="border"></param>
    /// <returns>byte[]</returns>
    public static byte[] FrameworkElementToBitmap(UIElement border, EncodingTypes encType, double scale = 1.0)
    {
        byte[] bitmapBytes;
        int width = (int)(border.RenderSize.Width * scale);
        int height = (int)(border.RenderSize.Height * scale);

        BitmapEncoder encoder;
        switch (encType)
        {
            case EncodingTypes.GIF:
                encoder = new GifBitmapEncoder();
                break;

            case EncodingTypes.JPEG:
                encoder = new JpegBitmapEncoder();
                break;

            case EncodingTypes.PNG:
                encoder = new PngBitmapEncoder();
                break;

            case EncodingTypes.TIFF:
                encoder = new TiffBitmapEncoder();
                break;

            case EncodingTypes.WMP:
                encoder = new WmpBitmapEncoder();
                break;

            default:
            case EncodingTypes.BMP:
                encoder = new BmpBitmapEncoder();
                break;
        }

        //render ink to bitmap
        RenderTargetBitmap renderBitmap = new RenderTargetBitmap(width, height, 96d, 96d, PixelFormats.Default);

        Rect bounds = VisualTreeHelper.GetDescendantBounds(border);

        //Use DrawingVisual to prevent having to move the control to the top of the screen to grab the bitmap
        DrawingVisual dv = new DrawingVisual();
        using (DrawingContext ctx = dv.RenderOpen())
        {
            ctx.PushTransform(new ScaleTransform(scale, scale));
            ctx.DrawRectangle(
                new VisualBrush(border), 
                null, 
                new Rect(new Point(), bounds.Size)); //new Rect(border.RenderSize));
        }

        renderBitmap.Render(dv);

        //save the ink to a memory stream
        encoder.Frames.Add(BitmapFrame.Create(renderBitmap));
        using (MemoryStream ms = new MemoryStream())
        {
            encoder.Save(ms);

            //get the bitmap bytes from the memory stream
            bitmapBytes = ms.ToArray();
            //Uncomment to save images when debugging
            //#if DEBUG
            //              string savePath = Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData);
            //              string testFileName = Path.Combine(savePath, string.Format("{0}.{1}", DateTime.Now.ToString("yyyyMMdd_hhmmss"), encType.ToString().ToLower()));
            //              File.WriteAllBytes(testFileName, bitmapBytes);
            //#endif
        }

        return bitmapBytes;
    }
    #endregion
}

Usage:用法:

byte[] bytes = ImageHelper.FrameworkElementToBitmap(mygrid, EncodingTypes.JPEG);

Xaml: Xaml:

<Grid x:Name="mygrid" Background="White">***controls you want to take pics of***</Grid>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM