2015-07-11 31 views
15

我正在編寫一個服務器端控制檯應用程序在C#/ .Net 4.5中獲取一些數據並創建保存以供Web服務器顯示的靜態圖表圖像。WPF用戶控件服務器端呈現

我主要是用在這裏所描述的方法: 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用戶控件的一個實例,我做了 - 在這一點上相當簡單,只是一些網格將文本數據綁定到我分配給DataContext的ViewModel對象。

磁盤上保存的圖像看起來不錯,除了OxyPlot Plot對象外 - 它完全是白色的。

現在,當我在Visual Studio 2013中的設計師時,我可以看到它。我添加了一個設計時DataContext,它是我在運行時使用的同一個對象(這是我正在做的一個高峯 - viewmodel還沒有達到最終形式,只是有一堆默認數據,而我正在解決這些問題)。在設計師中,我看到了OxyPlot繪製的圖表。

爲了讓我的渲染也包含這個OxyPlot圖表,有什麼特別的我需要做的嗎?這或多或少是練習的重點,所以真正讓它出現的真棒!

在此先感謝您的任何見解和建議!

+0

吉文斯的平臺支持廣泛,我會懷疑,這個問題是在OxyPlot WPF控件是如何實現的。也許它是嵌入在WPF控件中的WinForms控件,可能會有問題。我不知道這是否有幫助。 –

+0

當然,如果沒有完整的WPF環境中的控件,就沒有辦法做到這一點。在那種情況下,我會去尋找另一個製圖組件。但是,如果我只能找出設計師所做的事情,那麼我就不會那麼做,那麼我希望我能觸發它自己繪畫。 –

+0

@swiszcz:你能解釋爲什麼這裏提供的答案不適合你嗎? –

回答

5

如果您在運行時正確綁定數據,那麼它應該可以工作。

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

感謝您的回答,並對我遲到的評論感到抱歉。那麼,你的例子顯然有效。我有兩個例子(不幸的是,專有代碼),我不希望我會在不久的將來找到一些時間來產生一個最小的可重複的例子,以找出什麼時候(以及爲什麼)它不工作。 –

+0

非常歡迎。很抱歉聽到這個......當你有機會時,肯定會發佈一個[MCVE](https://stackoverflow.com/help/mcve),併發給我一個關於它的註釋,我會很高興看到它再次。乾杯。 – jsanalytics

+0

謝謝!我會! –

3

我不知道這個OxyPlat什麼,但我知道,最圖表是徒勞的n使用硬件API呈現。在預期環境之外工作時(例如,客戶端顯示可見的桌面窗口),硬件加速通常容易出錯。

在應用程序初始化,嘗試禁用硬件加速:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly; 
+0

我們的應用程序非常笨重,因此除去硬件支持並不是最好的主意。很抱歉對您的回答發表了遲到的評論! –

相關問題