Как получить скриншот всех элементов в сгенерированном списке в wpf - PullRequest
1 голос
/ 17 мая 2019

У меня есть список со 150 элементами.Каждый элемент имеет свой цвет фона.Если я прокручиваю вниз вертикальную полосу прокрутки в виде списка, я могу разделить элементы на три части:

  1. верхние скрытые элементы, элементы скрыты в верхней части списка.
  2. отображаемые элементы.
  3. нижние скрытые элементы, элементы скрыты в нижней части списка.

Я хочу сохранить все элементы в изображение.

Я пытаюсь реализовать базу наэто руководство Как отобразить пользовательский элемент управления WPF в растровое изображение без создания окна 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);
            }
        }
    }
}

Iожидается, что я получу изображение всех элементов с цветом фона, как показано в пользовательском интерфейсе, но на самом деле я получаю изображение только отображаемых элементов и нижних скрытых элементов.

Проблема: скрытые на дне элементы не имеют фонового формата.Топ скрытых предметов не в изображении.Может кто-нибудь, пожалуйста, помогите мне сделать правильное изображение.Спасибо!

1 Ответ

0 голосов
/ 20 мая 2019

Я получаю изображение только отображаемых предметов и нижних скрытых предметов

Это происходит потому, что ListView, когда он не ограничен размерами контейнера, будет пытаться изменить его размер, чтобы вместить как можно больше предметовкак может начиная с первого отображаемого элемента.Другими словами, он не пытается каким-то образом отобразить «верхние скрытые элементы» (как вы их называете).

Я не уверен, возможно ли изменить это поведение, чтобы сделать true auto-sizable ListView, но простой обходной путь - это прокрутить до самого первого элемента, сделать скриншот, а затем восстановить положение.

Добавьте это перед измерением (вам потребуется метод FindChild ):

var scroll = ListViewCtrl.FindChild<ScrollViewer>(); 
var offset = scroll.VerticalOffset; // store offset
scroll.ScrollToTop();
Dispatcher.Invoke(() => { }, DispatcherPriority.Background); // do events

И затем после рендеринга восстановить положение:

scroll.ScrollToVerticalOffset(offset);

Почему "делать события"?Вы должны подождать, пока wpf фактически выполнит прокрутку, прежде чем измерять.Как много вещей в wpf, что тоже откладывается, т.е. не происходит мгновенно.

...