C# 如何在wpf中获取生成的listview中所有项目的屏幕截图

C# 如何在wpf中获取生成的listview中所有项目的屏幕截图,c#,wpf,listview,screenshot,C#,Wpf,Listview,Screenshot,我有一个包含150个项目的列表视图。每个项目有不同的背景色。如果我向下滚动列表视图的垂直滚动条,我可以将项目分为三个部分: 顶部隐藏项,项隐藏在listview顶部 显示的项目 底部隐藏项,项隐藏在listview的底部 我想将所有项目保存到图像 我试着根据这个指南来实现 MainWindow.xaml: <Window x:Class="CaptureListEx.MainWindow" xmlns="http://schemas.microsoft.com/winfx/

我有一个包含150个项目的列表视图。每个项目有不同的背景色。如果我向下滚动列表视图的垂直滚动条,我可以将项目分为三个部分:

  • 顶部隐藏项,项隐藏在listview顶部
  • 显示的项目
  • 底部隐藏项,项隐藏在listview的底部
  • 我想将所有项目保存到图像

    我试着根据这个指南来实现 MainWindow.xaml:

    <Window x:Class="CaptureListEx.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:CaptureListEx"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="80"/>
            </Grid.RowDefinitions>
            <ListView Grid.Row="0"
                      Name="ListViewCtrl"
                      Margin="10"
                      BorderThickness="1"
                      ItemsSource="{Binding listViewItem}"
                      ScrollViewer.VerticalScrollBarVisibility="Auto"
                      ScrollViewer.HorizontalScrollBarVisibility="Auto">
    
            </ListView>
            <Button Grid.Row="1"
                    Width="60"
                    Height="30"
                    Content="Capture"
                    Name="Capture"
                    Click="Capture_Click"
                    >
    
            </Button>
        </Grid>
    </Window>
    
    
    
    MainWindow.xaml.cs:

    using Microsoft.Win32;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.Windows;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    
    namespace CaptureListEx
    {
        public partial class MainWindow : Window
        {
            public ObservableCollection<string> listViewItem { get; set; } = new ObservableCollection<string>();
            public MainWindow()
            {
                InitializeComponent();
                DataContext = this;
    
                for(int i = 0; i <= 150; i++)
                {
                    string temp = "This is item" + i;
                    listViewItem.Add(temp);
                }
            }
    
            private void Capture_Click(object sender, RoutedEventArgs e)
            {
                SaveFileDialog dlg = new SaveFileDialog()
                {
                    DefaultExt = ".jpg",
                    Filter = "JPG image (*.jpg)|*.jpg|All files (*.*)|*.*"
                };
                Nullable<bool> result = dlg.ShowDialog();
                if (result == false) return;
                if (File.Exists(dlg.FileName) && new FileInfo(dlg.FileName).Length != 0)
                    File.Delete(dlg.FileName);
    
                double actualWidth = ListViewCtrl.ActualWidth;
                ListViewCtrl.Measure(new System.Windows.Size(Double.PositiveInfinity, Double.PositiveInfinity));
                ListViewCtrl.Arrange(new Rect(0, 0, actualWidth, ListViewCtrl.DesiredSize.Height));
                double actualHeight = ListViewCtrl.ActualHeight;
    
                RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)ListViewCtrl.ActualWidth, (int)ListViewCtrl.ActualHeight, 96, 96, PixelFormats.Pbgra32);
    
                renderTarget.Render(ListViewCtrl);
    
                PngBitmapEncoder encoder = new PngBitmapEncoder();
                encoder.Frames.Add(BitmapFrame.Create(renderTarget));
    
                using (System.IO.FileStream stream = new System.IO.FileStream(dlg.FileName, System.IO.FileMode.Create, System.IO.FileAccess.Write))
                {
                    encoder.Save(stream);
                }
            }
        }
    }
    
    使用Microsoft.Win32;
    使用制度;
    使用System.Collections.Generic;
    使用System.Collections.ObjectModel;
    使用System.IO;
    使用System.Windows;
    使用System.Windows.Media;
    使用System.Windows.Media.Imaging;
    命名空间CaptureListEx
    {
    公共部分类主窗口:窗口
    {
    public ObservableCollection listViewItem{get;set;}=new ObservableCollection();
    公共主窗口()
    {
    初始化组件();
    DataContext=this;
    对于(int i=0;i
    我只得到显示项目和底部隐藏项目的图像

    这是因为
    ListView
    在不受容器尺寸限制的情况下,只会尝试调整自身大小以适应从第一个显示的项目开始的尽可能多的项目。换句话说,它不会尝试以某种方式显示“顶部隐藏项目”(您如何称呼它们)

    我不确定是否可以更改此行为以使ListView真正自动调整大小,但一个简单的解决方法是滚动到第一项,制作屏幕截图,然后恢复位置

    测量前添加此项(您将需要):

    为什么要“做事件”?您必须等到wpf实际执行滚动后才能进行测量。wpf中的许多事情也会延迟,即不会立即发生

    我只得到显示项目和底部隐藏项目的图像

    这是因为
    ListView
    在不受容器尺寸限制的情况下,只会尝试调整自身大小以适应从第一个显示的项目开始的尽可能多的项目。换句话说,它不会尝试以某种方式显示“顶部隐藏项目”(您如何称呼它们)

    我不确定是否可以更改此行为以使ListView真正自动调整大小,但一个简单的解决方法是滚动到第一项,制作屏幕截图,然后恢复位置

    测量前添加此项(您将需要):


    为什么“做事件”?在测量之前,您必须等待wpf实际执行滚动。wpf中的许多事情也会延迟,即不会立即发生。

    您确定要创建图像,而不是更适合于XML或xls等数据存储的东西吗?@DenisSchaf谢谢。我真的需要创建图像。@Sinatr能否提供您的合作伙伴删除调整大小的ListView,将其绘制并保存到好看的屏幕截图。这与我的代码不同吗?不,我用鼠标滚动ListView。我的测试项目非常简单。它有一个按钮和一个包含150行项目的ListView。单击按钮,它调用上面的函数来拍摄图像。@Sinatr您是否尝试过与我的代码相同的解决方案,并且无法重现问题?@Sinatr我已经创建了一个简单的项目来解决这个问题,并在我的帖子中更新代码。当向下滚动滚动条到中间并捕获图像时,我仍然会遇到问题。你确定要创建一个图像,而不是像XML或xls这样更适合数据存储的图像吗?@denischaf谢谢。我真的需要创建图像。@Sinatr你能提供吗您的代码调整了ListView的大小,绘制并保存到了好看的屏幕截图。它与我的代码不同吗?不,我用鼠标滚动ListView。我的测试项目非常简单。它有一个按钮和一个包含150行项目的ListView。单击按钮,它调用上面的函数来拍摄图像。@Sinatr您是否尝试过与我的代码相同的解决方案,但无法复制问题?@Sinatr我已经创建了一个简单的项目来关注这个问题并在我的帖子中更新代码。当向下滚动滚动条到中间并捕获图像时,我仍然会遇到问题。是的。谢谢你的清晰解释和解决方案。是的。谢谢你的清晰解释和解决方案。
    var scroll = ListViewCtrl.FindChild<ScrollViewer>(); 
    var offset = scroll.VerticalOffset; // store offset
    scroll.ScrollToTop();
    Dispatcher.Invoke(() => { }, DispatcherPriority.Background); // do events
    
    scroll.ScrollToVerticalOffset(offset);