Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# WPF UserControl的服务器端呈现_C#_Wpf_Xaml_Console Application_Oxyplot - Fatal编程技术网

C# WPF UserControl的服务器端呈现

C# WPF UserControl的服务器端呈现,c#,wpf,xaml,console-application,oxyplot,C#,Wpf,Xaml,Console Application,Oxyplot,我正在C#/.NET4.5中编写一个服务器端控制台应用程序,它获取一些数据并创建静态图表图像,这些图像将被保存以供web服务器显示 我主要使用这里描述的方法: 但是,我添加了一个mainContainer.UpdateLayout();在Arrange()之后,以便数据绑定将更新并在渲染图像中可见,以及在其之前的Measure()中永久显示。。。啊,我不会去那里的 以下是执行渲染的方法: void RenderAndSave(UIElement target, string filename,

我正在C#/.NET4.5中编写一个服务器端控制台应用程序,它获取一些数据并创建静态图表图像,这些图像将被保存以供web服务器显示

我主要使用这里描述的方法:

但是,我添加了一个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的一个实例——在这一点上相当简单,只是一个带有一些文本数据绑定到我分配给DataContext的ViewModel对象的网格

磁盘上保存的图像看起来不错,除了OxyPlot对象-它是完全白色的

现在,当我在Visual Studio 2013的designer中时,我可以看到它。我添加了一个设计时DataContext,它与我在运行时使用的对象相同(这是我正在做的一个峰值-viewmodel还没有达到最终形式,只是在我解决问题时有一堆默认数据)。在designer中,我看到OxyPlot绘制的图表

为了让我的渲染也包含这个OxyPlot图表,我需要做什么特殊的事情吗?这或多或少是这个练习的重点,所以让它真正展示出来会很棒


提前感谢您的任何见解和建议

如果您在运行时也正确绑定了数据,那么它应该可以工作

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

我对OxyPlat一无所知,但我知道大多数图表通常使用硬件API呈现。在预期环境之外工作时(即客户端显示可见桌面窗口),硬件加速通常容易出错

在应用程序初始化时,尝试禁用硬件加速:

RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
另一个可能的调整是在渲染位图之前调用
DoEvents()
。可能将
优先级设置为
SystemIdle
。这将确保您的
DataContext
已成功绑定

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

鉴于支持的平台种类繁多,我怀疑问题在于OxyPlot WPF控件是如何实现的。可能是嵌入在WPF控件中的WinForms控件,这可能有问题。我不知道这是否有帮助。当然,你可能是对的——如果没有完整WPF环境中存在的控件,就不可能做到这一点。在这种情况下,我将寻找另一个图表组件。然而,如果我能找出设计师做了什么而我没有做,那么我希望我能触发它来画自己。@swiszcz:你能解释一下为什么这里提供的答案对你不起作用吗?我们的应用程序非常繁重,因此另外删除硬件支持不是最好的主意。很抱歉对您的回答发表了评论!谢谢你的回答,也很抱歉我最近对此发表了评论。好吧,你的例子显然有效。我有两个例子(不幸的是,专有代码)没有。。。我希望在不久的将来,我能抽出一些时间来制作一个最小的可复制的示例,以找出它何时(以及为什么)不起作用。非常欢迎。很抱歉听到这个。。。当然,只要你有机会,就给我发一封信,我很乐意再看一次。干杯
public static void DoEvents(
    DispatcherPriority priority = DispatcherPriority.Background)
{
    Dispatcher.CurrentDispatcher.Invoke(new Action(delegate { }), priority);
}