2015-07-11 13 views
15

Piszę aplikację konsoli po stronie serwera w C#/.NET 4.5, która pobiera pewne dane i tworzy statyczne obrazy wykresu, które są zapisywane do wyświetlania przez serwer WWW.Renderowanie po stronie serwera WPF UserControl

ja głównie za pomocą metody opisanej tutaj: http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html

Jednak dodano mainContainer.UpdateLayout(); po aranżacji(), aby databindings zaktualizowały się i były widoczne w renderowanym obrazie, jak również Measure() przed nim na dobre ... ach, nie zamierzam tam iść.

Oto metoda, która robi rendering:

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); 
    } 
} 

Parametr target metody będzie instancją WPF/XAML UserControl zrobiłem - dość proste, w tym momencie, tylko siatka z niektórych tekstowe powiązanie danych z obiektem ViewModel, który został przypisany do DataContext.

Zapisany obraz na dysku wygląda dobrze, Z WYJĄTKIEM obiektu OxyPlot Plot - jest całkowicie biały.

Teraz, gdy jestem w projektancie w Visual Studio 2013, widzę to. Dodałem obiektowy obiekt DataContext, który jest tym samym obiektem, którego używam w środowisku wykonawczym (jest to skok, który robię - model podglądu nie jest jeszcze w ostatecznej formie, po prostu ma masę domyślnych danych, podczas gdy ja pracuję nad supłami). W projektancie widzę wykres, jak OxyPlot go maluje.

Czy jest coś szczególnego, co muszę zrobić, aby moje renderowanie zawierało również ten wykres OxyPlot? To jest mniej więcej punkt ćwiczenia, więc byłoby wspaniale, gdyby to się pojawiło!

Z góry dziękujemy za wszelkie uwagi i sugestie!

+0

Givens szeroki wachlarz obsługiwanych platform, to podejrzewam, że problem jest w tym, jak kontrola OxyPlot WPF został wdrożony. Być może jest to kontrolka WinForms osadzona w formancie WPF, co może być problematyczne. Nie wiem, czy to pomaga. –

+0

Oczywiście możesz mieć rację - istnieje szansa, że ​​nie da się tego zrobić bez kontroli istniejącej w pełnym środowisku WPF. W takim przypadku będę szukał innego składnika wykresów.Jednak gdybym mógł po prostu dowiedzieć się, co projektant robi, czego ja nie mam, to mam nadzieję, że uda mi się go samemu namalować. –

+0

@swiszcz: Czy mógłbyś wyjaśnić, dlaczego podane tutaj odpowiedzi nie będą dla ciebie skuteczne? –

Odpowiedz

5

Jeśli poprawnie włączysz dane w środowisku wykonawczym, to powinno działać.

enter image description here

[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; 
    } 
} 
+0

Dziękuję za odpowiedź i przepraszam za mój spóźniony komentarz na ten temat. Twój przykład oczywiście działa. I mam dwa przykłady (kod zastrzeżony, niestety), gdzie nie ma ... Mam nadzieję, że znajdę trochę czasu w niedalekiej przyszłości, aby stworzyć minimalny powtarzalny przykład, aby dowiedzieć się kiedy (i dlaczego) nie działa. –

+0

Bardzo proszę. Przykro mi to słyszeć ... Na pewno opublikuj [MCVE] (https://stackoverflow.com/help/mcve) za każdym razem, gdy masz szansę, i wyślij mi notatkę na ten temat, z przyjemnością na nie spojrzę jeszcze raz. Twoje zdrowie. – jsanalytics

+0

Dzięki! Będę! –

3

Nie wiem nic o tym OxyPlat wiem, ale wiem, że większość wykresy są ofte n renderowane za pomocą sprzętowych interfejsów API. Akceleracja sprzętowa jest zwykle podatna na błędy podczas pracy poza oczekiwanym środowiskiem (np. Klient wyświetlający widoczne okno pulpitu).

Na inicjalizacji aplikacji, spróbuj wyłączyć akcelerację sprzętową:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; 
+0

Nasza aplikacja jest bardzo ciężka, więc dodatkowe usunięcie sprzętu nie byłoby najlepszym pomysłem. Przepraszamy za spóźniony komentarz na twoją odpowiedź! –

Powiązane problemy