Просмотр на стороне сервера WPF UserControl

Я пишу приложение на стороне сервера на С#/.NET 4.5, которое получает некоторые данные и создает статические изображения диаграммы, которые сохраняются для отображения веб-сервером.

В основном я использую описанный здесь метод: http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html

Однако я добавил mainContainer.UpdateLayout(); после Arrange(), чтобы привязки данных обновлялись и отображались в визуализированном изображении, а также в методе Measure() перед этим навсегда... ах, я не собираюсь туда идти.

Вот метод, который выполняет рендеринг:

void RenderAndSave(UIElement target, string filename, int width, int height)
{
    var mainContainer = new Grid
    {
        HorizontalAlignment = HorizontalAlignment.Stretch,
        VerticalAlignment = VerticalAlignment.Stretch
    };

    mainContainer.Children.Add(target);

    mainContainer.Measure(new Size(width, height));
    mainContainer.Arrange(new Rect(0, 0, width, height));
    mainContainer.UpdateLayout();

    var encoder = new PngBitmapEncoder();
    var render = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);

    render.Render(mainContainer);
    encoder.Frames.Add(BitmapFrame.Create(render));
    using (var s = File.Open(filename, FileMode.Create))
    {
        encoder.Save(s);
    }
}

Целевым параметром метода будет экземпляр созданного мной элемента управления WPF/XAML UserControl - довольно простой в данный момент, просто сетка с некоторой привязкой текстовой привязки к объекту ViewModel, который я назначил DataContext.

Сохраненное изображение на диске выглядит хорошим ИСКЛЮЧИТЬ для объекта OxyPlot Plot - он полностью белый.

Теперь, когда я нахожусь в дизайнере в Visual Studio 2013, я это вижу. Я добавил TimeContext времени разработки, который является тем же самым объектом, который я использую во время выполнения (это - шип, который я делаю - модель представления еще не имеет окончательной формы, просто имея кучу данных по умолчанию, пока я разрабатываю изломы). В дизайнере я вижу диаграмму в качестве OxyPlot.

Есть ли что-то особенное, что мне нужно сделать, чтобы мой рендеринг также содержал эту диаграмму OxyPlot? Это более или менее точка упражнения, поэтому было бы здорово отобразить его!

Заранее благодарим за любые идеи и предложения!

Ответы

Ответ 1

Если вы правильно привязываете данные во время выполнения, тогда он должен работать.

введите описание изображения здесь

 [STAThread]
 static void Main(string[] args)
 {
     string filename = "wpfimg.png";

     RenderAndSave(new UserControl1(), filename, 300, 300);

     PictureBox pb = new PictureBox();
     pb.Width = 350;
     pb.Height = 350;
     pb.Image = System.Drawing.Image.FromFile(filename);

     Form f = new Form();
     f.Width = 375;
     f.Height = 375;
     f.Controls.Add(pb);
     f.ShowDialog();
 }

XAML:

<UserControl x:Class="WpfApp92.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:oxy="http://oxyplot.org/wpf"
             xmlns:local="clr-namespace:WpfApp92"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">

    <Grid>
        <oxy:PlotView Model="{Binding Model}"/>
    </Grid>
</UserControl>

CS:

public partial class UserControl1 : UserControl
{
    public PlotModel Model { get; set; }

    public UserControl1()
    {
        InitializeComponent();

        Model = new PlotModel();
        Model.LegendBorderThickness = 0;
        Model.LegendOrientation = LegendOrientation.Horizontal;
        Model.LegendPlacement = LegendPlacement.Outside;
        Model.LegendPosition = LegendPosition.BottomCenter;
        Model.Title = "Simple model";
        var categoryAxis1 = new CategoryAxis();
        categoryAxis1.MinorStep = 1;
        categoryAxis1.ActualLabels.Add("Category A");
        categoryAxis1.ActualLabels.Add("Category B");
        categoryAxis1.ActualLabels.Add("Category C");
        categoryAxis1.ActualLabels.Add("Category D");
        Model.Axes.Add(categoryAxis1);
        var linearAxis1 = new LinearAxis();
        linearAxis1.AbsoluteMinimum = 0;
        linearAxis1.MaximumPadding = 0.06;
        linearAxis1.MinimumPadding = 0;
        Model.Axes.Add(linearAxis1);
        var columnSeries1 = new ColumnSeries();
        columnSeries1.StrokeThickness = 1;
        columnSeries1.Title = "Series 1";
        columnSeries1.Items.Add(new ColumnItem(25, -1));
        columnSeries1.Items.Add(new ColumnItem(137, -1));
        columnSeries1.Items.Add(new ColumnItem(18, -1));
        columnSeries1.Items.Add(new ColumnItem(40, -1));
        Model.Series.Add(columnSeries1);
        var columnSeries2 = new ColumnSeries();
        columnSeries2.StrokeThickness = 1;
        columnSeries2.Title = "Series 2";
        columnSeries2.Items.Add(new ColumnItem(12, -1));
        columnSeries2.Items.Add(new ColumnItem(14, -1));
        columnSeries2.Items.Add(new ColumnItem(120, -1));
        columnSeries2.Items.Add(new ColumnItem(26, -1));
        Model.Series.Add(columnSeries2);

        DataContext = this;
    }
}

Ответ 2

Я ничего не знаю об этом OxyPlat, но я знаю, что большинство диаграмм часто визуализируются с использованием аппаратных API. Аппаратное ускорение обычно подвержено ошибкам при работе за пределами ожидаемой среды (например, клиент, отображающий видимое окно рабочего стола).

При инициализации приложений попробуйте отключить аппаратное ускорение:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;