问题描述:

I have a problem when trying to create writeable bitmap form Silverlight toolkit Graph.

When using textBlock, everything is fine, but after trying to use Chart, generated bitmap is empty :( .

var data = new List<Point>(100);

for (int i = 0; i < 100; i++)

{

data.Add(new Point(i, Math.Sin(i * Math.PI / 50)));

}

Chart chart_ = new Chart()

{

Name = "Chart",

Width = 512,

Height = 512

};

LineSeries line = new LineSeries()

{

Name = "Line",

Title = "test",

IndependentValuePath = "X",

DependentValuePath = "Y",

ItemsSource = data

};

chart_.Series.Add(line);

This code creates chart with sinusoid in it. Then Im trying to create bitmap from it.

LayoutRoot.Children.Add(chart_); // I tried to add chart_ to visual tree, It doesn't help

//creates bitmap

ScaleTransform t = new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0 };

//bitmap = new WriteableBitmap(chart_, t); Tried it also with this way

bitmap = new WriteableBitmap(512, 512);

bitmap.Render(chart_, t);

texture = new Texture2D(GraphicsDeviceManager.Current.GraphicsDevice, bitmap.PixelWidth, bitmap.PixelHeight, false, SurfaceFormat.Color);

bitmap.CopyTo(texture);

All this code creates Empty Bitmap.But when I use TextBlock or some primitives like Ellipse, everything works. Im sure, that code generating chart is fine, cause chart is generated fine in Silverlight control.

EDIT:

I tried to create bitmap this way, but it dont help.

chart_.InvalidateMeasure();

bitmap = new WriteableBitmap(512, 512);

bitmap.Render(chart_, null);

bitmap.Invalidate();

EDIT 2:

I don't want graph to be in visual tree. I just need generate image of it an than use it in XNA part of my application.

网友答案:

Just a couple of small changes, but I suspect the big change is manually adding a reference to System.Windows.Controls after using NuGet to add the Charting package.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.DataVisualization.Charting;
using System.Windows.Media.Imaging;

namespace SilverlightApplication1
{
    public partial class MainPage : UserControl
    {
        Chart chart_;

        public MainPage()
        {
            InitializeComponent();

            var data = new List<Point>(100);
            for (int i = 0; i < 100; i++)
            {
                data.Add(new Point(i, Math.Sin(i * Math.PI / 50)));
            }

            chart_ = new Chart()
            {
                Name = "Chart",
                Width = 512,
                Height = 512
            };
            LineSeries line = new LineSeries()
            {
                Name = "Line",
                Title = "test",
                IndependentValuePath = "X",
                DependentValuePath = "Y",
                ItemsSource = data
            };
            chart_.Series.Add(line);
            LayoutRoot.Children.Add(chart_); // I tried to add chart_ to visual tree, It doesn't help  
        }

        private void LayoutRoot_Loaded(object sender, RoutedEventArgs e)
        {
            //creates bitmap 
            WriteableBitmap bitmap;
            ScaleTransform t = new ScaleTransform() { ScaleX = 1.0, ScaleY = 1.0 };
            //bitmap = new WriteableBitmap(chart_, t); Tried it also with this way 
            bitmap = new WriteableBitmap(512, 512);
            bitmap.Render(chart_, t);
            //texture = new Texture2D(GraphicsDeviceManager.Current.GraphicsDevice, bitmap.PixelWidth, bitmap.PixelHeight, false, SurfaceFormat.Color);
            //bitmap.CopyTo(texture); 
            image1.Source = bitmap;
        }
    }
}

And

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
    xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">

    <Grid x:Name="LayoutRoot" Background="White" Loaded="LayoutRoot_Loaded">
        <Image Height="150" HorizontalAlignment="Left" Margin="97,109,0,0" Name="image1" Stretch="Fill" VerticalAlignment="Top" Width="200" />
    </Grid>
</UserControl>

That should get you going...

Don't forget to delete all of the attempted workarounds - I don't think any of them are necessary. The only code I did not use from your example had to do with the textures - I didn't know what to do with that and it wasn't the problem you were having anyways...

David

网友答案:

I believe that by the time you are creating WriteableBitmap object & calling Render method, Chart has not be rendered yet. You can check this by moving these lines of code to some other event like Button_Click etc. Have a look at below codes as it is creating the WriteableBitmap and then passes it to image control as source....

XAML Code.....

<UserControl x:Class="TryBitmap.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<Grid x:Name="LayoutRoot" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="35"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Button Grid.Row="0" Height="25" Width="100" Content="Capture" Click="Button_Click"/>
    <Grid x:Name="grdGraphs" Grid.Row="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Image x:Name="img" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
    </Grid>
</Grid>

Code Behind....

public partial class MainPage : UserControl
{
    private Chart chart_;

    public MainPage()
    {
        InitializeComponent();
        Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

    void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var data = new List<Point>(100);
        for (int i = 0; i < 100; i++)
        {
            data.Add(new Point(i, Math.Sin(i * Math.PI / 50)));
        }

        chart_ = new Chart()
        {
            Name = "Chart",
            Width = 512,
            Height = 512
        };
        LineSeries line = new LineSeries()
        {
            Name = "Line",
            Title = "test",
            IndependentValuePath = "X",
            DependentValuePath = "Y",
            ItemsSource = data
        };
        chart_.Series.Add(line);

        chart_.SetValue(Grid.ColumnProperty, 0);
        grdGraphs.Children.Add(chart_);
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        var bitmap = new WriteableBitmap((int)(chart_.RenderSize.Width), (int)(chart_.RenderSize.Height));
        bitmap.Render(chart_, new MatrixTransform());
        bitmap.Invalidate();

        img.Source = bitmap;
    }
}
网友答案:

I'm afraid this is only going to be half an answer. I can solve your immediate problem but I'm afraid you'll just end up with another one I haven't managed to solve.

Creating the bitmap after a call to Dispatcher.BeginInvoke should ensure that your bitmap isn't completely blank, i.e.:

// do stuff with chart_ ...

Dispatcher.BeginInvoke(() =>
{
    bitmap = new WriteableBitmap(512, 512);
    bitmap.Render(chart_, null);
    bitmap.Invalidate();

    // At this point, the bitmap shouldn't be blank.
});

However, the results of this likely to be less than satisfactory. I ran your code and I found that the LineSeries was missing from the chart image, although the rest of the chart was there. This remained true even after I set all Durations of the various animations in the ControlTemplate for the LineSeries to 0 and additionally set the following properties on the chart:

    chart_.AnimationSequence = AnimationSequence.Simultaneous;
    chart_.TransitionDuration = new TimeSpan(0);

I tried wrapping the WriteableBitmap operations in further calls to Dispatcher.BeginInvoke(), and after doing this the data points started to appear more clearly. However, I can't believe that an approach like this is the right solution to the problem.

相关阅读:
Top