将UserControl保存为JPG - 结果是“压扁”

时间:2012-06-25 10:27:39

标签: silverlight windows-phone-7

我将UserControl另存为JPG时遇到了一个奇怪的问题。基本上我想要做的是创建一个Live Tile,我可以使用后台代理(以及应用程序本身)更新。

我已经按照this blog post中的步骤进行操作,这些步骤在创建磁贴时效果很好;我有一个带有一些TextBlocks的自定义UserControl,它被保存为一个JPG到IsolatedStorage,就像帖子所说的那样。

创建磁贴没有问题 - UserControl的渲染效果非常好。但是,当我尝试更新磁贴时(使用完全相同的方法 - 将新控件保存为JPG,然后将该JPG用作BackgroundImage),事情就会崩溃。

放置在磁贴上的结果图像(并保存在IsolatedStorage中)如下所示:squished tile(使用Isolated Storage Explorer工具从IsolatedStorage中拉出)

背景为黑色,所有文字都沿着图像的一侧向下(并且相互重叠) - 预期的结果是背景是手机的强调色,而文字在顶部附近显得水平

用于生成和保存图像的代码在两个实例中完全相同 - 我将其抽象为一个返回StandardTileData的静态方法。唯一的区别在于调用它的位置:在创建磁贴的工作情况下,它从主应用程序中的页面调用;在非工作情况下(更新磁贴),从一个只能通过磁贴本身深层链接访问的页面调用它。

有什么想法?我猜测将控制渲染到JPG会出现问题,因为实际图像是这样出现的。

生成图像的代码片段在这里:

StandardTileData tileData = new StandardTileData();

// Create the Control that we'll render into an image.
TileImage image = new TileImage(textA, textB);
image.Measure(new Size(173, 173));
image.Arrange(new Rect(0, 0, 173, 173));

// Render and save it as a JPG.
WriteableBitmap bitmap = new WriteableBitmap(173, 173);
bitmap.Render(image, null);
bitmap.Invalidate();

IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication();
String imageFileName = "/Shared/ShellContent/tile" + locName + ".jpg";

using (IsolatedStorageFileStream stream = storage.CreateFile(imageFileName))
{
    bitmap.SaveJpeg(stream, 173, 173, 0, 100);
}

tileData.BackgroundImage = new Uri("isostore:" + imageFileName, UriKind.Absolute);

return tileData;

我尝试转换的控件的XAML在这里:

<UserControl x:Class="Fourcast.TileImage"
    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"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    d:DesignHeight="173" d:DesignWidth="173" FontStretch="Normal" Height="173" Width="173">

    <Border Background="{StaticResource PhoneAccentBrush}">
        <StackPanel>
            <TextBlock  HorizontalAlignment="Stretch"
              TextWrapping="Wrap" VerticalAlignment="Stretch" Style="{StaticResource PhoneTextLargeStyle}" x:Name="Temperature"></TextBlock>
            <TextBlock x:Name="Condition" HorizontalAlignment="Stretch"
              TextWrapping="Wrap" VerticalAlignment="Stretch" Style="{StaticResource PhoneTextNormalStyle}">
            </TextBlock>
        </StackPanel>
    </Border>
</UserControl>

更新:在使用调试程序进行一些调查后,当调用此方法时,MeasureArrange的调用似乎无法执行任何操作更新磁贴的类。但是,在创建切片时,这些调用将按预期运行(控件的ActualWidth和ActualHeight将更改为173)。

3 个答案:

答案 0 :(得分:1)

不确定这里到底发生了什么,但这是我最终要解决的问题。

我从尝试渲染控件转换为在代码中定义StackPanel,向其中添加元素,然后将其渲染为图像。但奇怪的是,ArrangeMeasure方法除非已将其应用于,并且UpdateLayout已调用,否则不执行任何操作。

完整的结果代码(减去TextBlock的内容并写入图像)如下所示。

StandardTileData tileData = new 

// None of this actually does anything, but for some reason the StackPanel
// won't render properly without it.
Border image = new Border();
image.Measure(new Size(173, 173));
image.Arrange(new Rect(0, 0, 173, 173));
image.UpdateLayout();
// End of function-less code.

StackPanel stpContent = new StackPanel();      

TextBlock txbTemperature = new TextBlock();
txbTemperature.Text = temperature;
txbTemperature.Style = (Style)Application.Current.Resources["PhoneTextLargeStyle"];
stpContent.Children.Add(txbTemperature);

TextBlock txbCondition = new TextBlock();
txbCondition.Text = condition;
txbCondition.Style = (Style)Application.Current.Resources["PhoneTextNormalStyle"];
stpContent.Children.Add(txbCondition);

stpContent.Measure(new Size(173, 173));
stpContent.Arrange(new Rect(0, 0, 173, 173));

答案 1 :(得分:0)

获取图像背景以使用手机强调色的方法是使其透明。这将要求您保存PNG而不是JPG。

输出图像看起来就像所有东西都包含它需要的东西。您可能需要调整控件中包含的元素的宽度。没有XAML,很难更具体。

答案 2 :(得分:0)

我也得到了这种奇怪的行为 - 压扁了瓷砖(使用Ree7 Tile工具包),

尝试将调用更新磁贴调用到Dispatcher:

Deployment.Current.Dispatcher.BeginInvoke(() =>
{
    CustomTile tile = GetTile(card);
    StandardTileData tileData = tile.GetShellTileData();
    shellTile.Update(tileData);
});

为我工作