c# wpf xaml console-application oxyplot

c# - Representación del lado del servidor de WPF UserControl



xaml console-application (2)

Estoy escribiendo una aplicación de consola del lado del servidor en C # /. Net 4.5 que obtiene algunos datos y crea imágenes de gráficos estáticos que se guardan para ser mostradas por un servidor web.

Estoy utilizando principalmente el método descrito aquí: http://lordzoltan.blogspot.com/2010/09/using-wpf-to-render-bitmaps.html

Sin embargo, agregué un mainContainer.UpdateLayout (); después de Organizar () para que los enlaces de datos se actualicen y sean visibles en la imagen renderizada, así como en una Medida () antes de que esté lista ... ah, no voy a ir allí.

Aquí está el método que hace la representación:

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

El parámetro de destino del método será una instancia de un control de usuario WPF / XAML que hice, bastante simple en este punto, solo una cuadrícula con un enlace de datos de texto a un objeto ViewModel que asigné al DataContext.

La imagen guardada en el disco se ve bien EXCEPTO para el objeto OxyPlot Plot, es completamente blanco.

Ahora, cuando estoy en el diseñador en Visual Studio 2013, puedo verlo. He agregado un DataContext en tiempo de diseño que es el mismo objeto que uso en el tiempo de ejecución (es un pico que estoy haciendo; el modelo de vista aún no está en su forma final, solo tengo un montón de datos predeterminados mientras trabajo los problemas) ). En el diseñador veo el cuadro como lo pinta OxyPlot.

¿Hay algo especial que deba hacer para que mi representación también contenga este gráfico OxyPlot? Es más o menos el objetivo del ejercicio, ¡así que sería genial lograr que aparezca!

Gracias de antemano por cualquier información y sugerencias!


No sé nada acerca de este OxyPlat, pero sí sé que la mayoría de los gráficos a menudo se procesan utilizando API de hardware. La aceleración de hardware suele ser propensa a errores cuando se trabaja fuera del entorno esperado (es decir, un cliente que muestra una ventana de escritorio visible).

En la inicialización de la aplicación, intente deshabilitar la aceleración de hardware:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;

Otro posible ajuste es llamar a DoEvents() antes de representar su mapa de bits. Posiblemente con la priority establecida en SystemIdle . Esto asegurará que su DataContext haya sido enlazado exitosamente.

public static void DoEvents( DispatcherPriority priority = DispatcherPriority.Background) { Dispatcher.CurrentDispatcher.Invoke(new Action(delegate { }), priority); }


Si también está vinculando correctamente los datos en tiempo de ejecución, entonces debería funcionar.

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