2015-07-11 15 views
15

Sto scrivendo un'app console lato server in C# /. Net 4.5 che ottiene alcuni dati e crea immagini di grafici statici che vengono salvati per essere visualizzati da un server web.Rendering lato server di WPF UserControl

sto per lo più con il metodo descritto qui: http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html

Tuttavia, ho aggiunto un mainContainer.UpdateLayout(); dopo Arrange() in modo che i database si aggiornino e siano visibili nell'immagine renderizzata, così come un Measure() prima di esso per bene ... ah, non ci andrò.

Ecco il metodo che fa il 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); 
    } 
} 

Il parametro target per il metodo sarà un'istanza di un WPF/XAML UserControl feci - abbastanza semplice, a questo punto, solo una griglia con una certa assegnamento di testo ad un oggetto ViewModel che ho assegnato al DataContext.

L'immagine salvata sul disco sembra buona ECCETTO per l'oggetto Plot OxyPlot - è completamente bianco.

Ora, quando sono nella finestra di progettazione in Visual Studio 2013, posso vederlo. Ho aggiunto un DataContext in fase di progettazione che è lo stesso oggetto che utilizzo in runtime (questo è un picco che sto facendo - il viewmodel non è ancora nella sua forma definitiva, avendo solo una serie di dati predefiniti mentre risolvo i nodi). Nel designer vedo il grafico come OxyPlot lo dipinge.

C'è qualcosa di speciale che devo fare per far sì che il mio rendering contenga anche questo grafico OxyPlot? È più o meno il punto dell'esercizio, quindi sarebbe fantastico vederlo apparire!

Grazie in anticipo per eventuali approfondimenti e suggerimenti!

+0

Givens la vasta gamma di piattaforme supportate, io sospetto che il problema è nel modo è stato attuato il controllo OxyPlot WPF. Forse è un controllo WinForms incorporato in un controllo WPF, che può essere problematico. Non so se questo aiuti. –

+0

Si potrebbe avere ragione su questo, naturalmente - c'è la possibilità che non ci sia modo di farlo senza il controllo esistente in un ambiente WPF completo. In tal caso, andrò a cercare un altro componente grafico.Tuttavia, se potessi scoprire che cosa fa il progettista, io spero di poterlo attivare per dipingere se stesso .. –

+0

@swiszcz: Potresti spiegare perché le risposte fornite qui non funzioneranno per te? –

risposta

5

Se si stanno vincolando correttamente i dati anche in runtime, dovrebbe funzionare.

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

Grazie per la risposta, e mi dispiace per il mio commento in ritardo su di esso. Bene, il tuo esempio ovviamente funziona. E ho due esempi (codice proprietario, sfortunatamente) dove non ... Spero di trovare un po 'di tempo in un prossimo futuro per produrre un esempio riproducibile minimo per scoprire quando (e perché) non funziona. –

+0

Sei il benvenuto. Mi spiace saperlo ... Certamente pubblichi un [MCVE] (https://stackoverflow.com/help/mcve) ogni volta che ne hai la possibilità, e mandami una nota a riguardo, sarò felice di guardarlo ancora. Saluti. – jsanalytics

+0

Grazie! Lo farò! –

3

non so nulla di questo OxyPlat, ma so che la maggior parte i grafici sono gratuiti n reso utilizzando le API hardware. L'accelerazione hardware di solito è soggetta a errori quando si lavora all'esterno dell'ambiente previsto (ad esempio, un client che mostra una finestra del desktop visibile).

In inizializzazione dell'applicazione, provate disattivando l'accelerazione hardware:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; 
+0

La nostra app è molto pesante, quindi rimuovere ulteriormente un supporto hardware non sarebbe l'idea migliore. Scusa per un commento in ritardo sulla tua risposta! –