WriteableBitmap.Savejpeg不渲染网格文本(图像正常)

时间:2013-02-01 14:47:12

标签: wpf silverlight windows-phone-7 writeablebitmap

我在用户控件中有一个Grid:

<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneAccentBrush}">
    <Image 
        x:Name="imgBack"
        Opacity=".25" />
    <Grid VerticalAlignment="Top" HorizontalAlignment="Left">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
        </Grid.ColumnDefinitions>
        <!-- Some textblocks -->
</Grid>

网格的大小&amp;图像源在运行时动态设置:

public void ChangeSizeAndImage(int width, int height, string backImagePath)
{
    // Set the height and width
    LayoutRoot.Width = width;
    LayoutRoot.Height = height;

    // Set the background image
    imgBack.Source = new BitmapImage(new Uri(backImagePath, UriKind.RelativeOrAbsolute));

    this.UpdateLayout();
}

然后我调用一个从ui元素生成jpeg的方法&amp;将其保存到IsolatedStorage(稍后添加到Windows Phone Live Tile)

public static Uri CreateImageFromUIElement(UIElement element, int width, int height)
{
    // Instance to store the image in
    IsolatedStorageFile userStore = IsolatedStorageFile.GetUserStoreForApplication();

    // Random ID to use for the file name
    string id = Guid.NewGuid().ToString("n");

    // create directory to read/write from
    const string shellContentDirectory = "Shared\\ShellContent";
    userStore.CreateDirectory(shellContentDirectory);

    // Render the UIElement into a writeable bitmap
    WriteableBitmap bitmap = new WriteableBitmap(element, new CompositeTransform());

    // Save the bitmap to a file. This stream must be closed in order to be read later
    string imagePath = shellContentDirectory + "\\" + id + ".jpg";
    using (IsolatedStorageFileStream stream = userStore.OpenFile(imagePath, System.IO.FileMode.Create))
    {
        bitmap.SaveJpeg(stream, width, height, 0, 100);
    }

    // Uri to get us to the image
    Uri imageUri = new Uri("isostore:/" + imagePath.Replace('\\', '/'));
    return imageUri;
}

我能够在瓷砖上成功使用图像,除了我只看到带有黑色背景的图像,我看不到任何文字。我认为这与jpeg和透明PNG有关,但是,我在上面的网格上用一种颜色设置背景,所以我不确定为什么它会被认为是透明的。

修改1 我正在以编程方式初始化此用户控件,设置一些属性,并将其传递给create image方法。我发现如果我将这个用户控件添加到页面,然后使用调用create image方法,它工作得很好。必须有一些关于它在页面上呈现的东西,导致所有内容正确排列。不幸的是,这种方法在我的情况下是不可能的。我可以采取哪些步骤来实现这一目标吗?控件上的UpdateLayout();不起作用。

2 个答案:

答案 0 :(得分:1)

您正在以背景方式呈现XAML的巨大挑战。在最终意识到它是什么之前,我跑来跑去绕过同样的问题。更糟糕的是,每隔一段时间它就能正常工作!

问题是图像的加载方式。创建控件时,将创建Image元素,并将图像加载/解码启动到另一个线程。与此同时,您的线程继续运行。您将控件渲染到文件并保存,片刻之后(此处是您不会看到的部分)图像完成加载,并进行实际渲染。太令人沮丧了!

你不能在那里坚持延迟,因为你不知道需要多长时间(而且我不确定它是否会以那种方式工作。你要做的就是将您的工作分成多个部分,并在Image上订阅ImageOpened事件。当事件触发时,您可以相信一切正常并保存位图。

在后台代理中,这很棘手,因为在此之前您需要暂停调用NotifyComplete(),当然,由于多种原因,图像可能无法加载。为了完整性,您还需要订阅ImageFailed事件并处理它!

在WP8应用程序中,您应该使用async / await模式来简化整个流程。在WP7中,您需要自己同步事物。如果需要,我可以发布一些代码。

我希望我能为您提供更简单的解决方案,但希望这会让您朝着正确的方向前进!

答案 1 :(得分:0)

这对我有用:

UserControl myControl = new UserControl();
myControl.Arrange(new Rect(0, 0, Width, Height));

WriteableBitmap writeable = new WriteableBitmap(Width, Height);
Writeable.Render(Control, null);
writeable.Invalidate();

IsolatedStorageFileStream fileStream = myIsolatedStorage.CreateFile("/Shared/ShellContent/" + Filename);

System.Windows.Media.Imaging.Extensions.SaveJpeg(writeable, fileStream, Width, Height, 0, 100);
fileStream.Close();

希望这有帮助。