Получение скриншота структуры внутри TreeView

228
17 декабря 2017, 07:59

Как получить скриншот всей структуры дерева TreeView? Делал это следующим кодом, но он получает изображение только видимой области дерева:

RenderTargetBitmap renderTargetBitmap = new RenderTargetBitmap((int)TreeElement.ActualWidth, (int)TreeElement.ActualHeight, 96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(TreeElement);
JpegBitmapEncoder jpegBitmapEncoder = new JpegBitmapEncoder
{
    QualityLevel = 100
};
jpegBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (FileStream fileStream = new FileStream("Tree.jpg", FileMode.Create))
{
    jpegBitmapEncoder.Save(fileStream);
    fileStream.Close();
}

Answer 1

Проблема вот в чём.

Вы получаете правильный скриншот: ваш TreeView именно так и выглядит. У него внутри есть ScrollViewer, который и ограничивает видимость.

Есть несколько путей решения проблемы. Самый простой, вероятно — просмотреть дочерние элементы нашего TreeView и найти «внутреннюю часть» ScrollViewer'а.

Это делается так:

IEnumerable<FrameworkElement> GetChildren(FrameworkElement fe)
{
    int nChildren = VisualTreeHelper.GetChildrenCount(fe);
    for (int i = 0; i < nChildren; i++)
        yield return (FrameworkElement)VisualTreeHelper.GetChild(fe, i);
}
IEnumerable<FrameworkElement> GetAllChildren(FrameworkElement fe) =>
    new[] { fe }.Concat(GetChildren(fe).SelectMany(GetAllChildren));

Или, если вы работаете с новой .NET 4.7.1, то

IEnumerable<FrameworkElement> GetAllChildren(FrameworkElement fe) =>
    GetChildren(fe).SelectMany(GetAllChildren).Prepend(fe);

Подсмотрев в визуальное дерево при помощи Live Visual Tree, видим, что нам нужен дочерний элемент типа ScrollContentPresenter.

Пишем:

var presenter = GetAllChildren(TreeElement).OfType<ScrollContentPresenter>().First();
var content = (FrameworkElement)VisualTreeHelper.GetChild(presenter, 0);
RenderTargetBitmap renderTargetBitmap =
    new RenderTargetBitmap((int)content .ActualWidth,
                           (int)content .ActualHeight,
                           96, 96, PixelFormats.Pbgra32);
renderTargetBitmap.Render(content);
JpegBitmapEncoder jpegBitmapEncoder = new JpegBitmapEncoder { QualityLevel = 100 };
jpegBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
using (var fileStream = File.Create("Tree.jpg"))
    jpegBitmapEncoder.Save(fileStream);

Недостаток: вы не получаете цвет фона, т. к. фон рисуется выше по визуальному дереву. Но «подложить» фон на картинку вы уж сможете сами, хорошо?

READ ALSO
Как преобразовать json в объект?

Как преобразовать json в объект?

Есть json, для которого Visual Studio сгенерировал вот такой класс

329
Метод расширения для UIElementCollection

Метод расширения для UIElementCollection

Есть метод расширения:

268
Отправка параметров JSON на веб-сервис из C#

Отправка параметров JSON на веб-сервис из C#

Мне нужно из C# отправить сделать то, что делается через CURL таким образом:

212