如何使用自定义布局创建WP8 Live Tile?

时间:2013-04-28 01:54:23

标签: windows-phone-8 live-tile

我正在寻找一个类似于Iconic tile的Live Tile,但允许我使用自定义Count值(即非整数字符串)。

我最接近的是我必须使用位图创建内容,然后使用该图像作为图块。不幸的是,我不知道这是如何做到的。

我正在寻找类似于此问题中描述的瓷砖(虽然这个问题与我的问题正交):Custom live tile rendering issue on Windows Phone (7/8)

简而言之,

  • WriteableBitmap是创建Live Tile布局的最佳方式吗?
  • 我是否有机制可以将XAML转换为Live Tile?

我希望实现的布局示例在Skype Live Tile中显示here

1 个答案:

答案 0 :(得分:4)

据我所知,创建自定义位图是最佳选择。我发现this answerthis article以及我在使用实时图块时非常有帮助。

如果您不介意购买第三方控件,可以查看Telerik的LiveTileHelper控件(如果您是诺基亚开发人员计划的成员,则您已经可以访问它)。

对于我的第一个应用程序,我选择根据前两个链接推出自己的解决方案。我有一个基类来处理获取FrameworkElement的工作(每个派生类负责生成包含要呈现的信息的FrameworkElement并创建相应的WritableBitmap实例然后使用ToolStack C#PNG Writer Library保存为.PNG。

作为示例,这是我的代码,用于生成代表我的某个应用中的小固定辅助磁贴的控件:

    /// <summary>
    /// Returns the fully populated and initialized control that displays
    /// the information that should be included in the tile image.
    /// </summary>
    /// <remarks>
    /// We manually create the control in code instead of using a user control
    /// to avoid having to use the XAML parser when we do this work in our
    /// background agent.
    /// </remarks>
    /// <returns>
    /// The fully populated and initialized control that displays
    /// the information that should be included in the tile image.
    /// </returns>
    protected override FrameworkElement GetPopulatedTileImageControl()
    {
        var layoutRoot = new Grid()
                            {
                                Background          = new System.Windows.Media.SolidColorBrush( System.Windows.Media.Color.FromArgb( 0, 0, 0, 0 ) ),
                                HorizontalAlignment = HorizontalAlignment.Stretch,
                                VerticalAlignment   = VerticalAlignment.Stretch,
                                Height              = TileSize.Height,
                                Width               = TileSize.Width,
                                Margin              = new Thickness( 0, 12, 0, 0 )
                            };
        var stopName = new TextBlock()
                            {
                                Text                = Stop.Description,
                                TextTrimming        = TextTrimming.WordEllipsis,
                                TextWrapping        = TextWrapping.Wrap,
                                Margin              = new Thickness( 7, 0, 7, 12 ),
                                MaxHeight           = 135,
                                Width               = TileSize.Width - 14,
                                VerticalAlignment   = VerticalAlignment.Bottom,
                                HorizontalAlignment = HorizontalAlignment.Stretch,
                                FontFamily          = (System.Windows.Media.FontFamily) Application.Current.Resources[ "PhoneFontFamilySemiBold" ],
                                FontSize            = (double) Application.Current.Resources[ "PhoneFontSizeMediumLarge" ],
                                Style               = (Style) Application.Current.Resources[ "PhoneTextNormalStyle" ]
                            };

        Grid.SetColumn( stopName, 0 );
        Grid.SetRow( stopName, 0 );

        layoutRoot.Children.Add( stopName );
        return layoutRoot;
    }

这是一个只有TextBlock的超简单控件,但您可以轻松扩展它。请注意,我在这里不使用UserControl,因为我还在后台代理中运行此代码,在后台代理中存在大量内存限制。

一旦我有了控件,我会生成一个WritableBitmap,如下所示:

    /// <summary>
    /// Renders the tile image to a <see cref="WritableBitmap"/> instance.
    /// </summary>
    /// <returns>
    /// A <see cref="WritableBitmap"/> instance that contains the rendered
    /// tile image.
    /// </returns>
    private WriteableBitmap RenderTileImage()
    {
        var tileControl = GetPopulatedTileImageControl();
        var controlSize = new Size( TileSize.Width, TileSize.Height );
        var tileImage   = new WriteableBitmap( (int) TileSize.Width, (int) TileSize.Height );

        // The control we're rendering must never be smaller than the tile
        // we're generating.
        tileControl.MinHeight   = TileSize.Height;
        tileControl.MinWidth    = TileSize.Width;

        // Force layout to take place.
        tileControl.UpdateLayout();
        tileControl.Measure( TileSize );
        tileControl.Arrange( new Rect( new Point( 0, 0 ), TileSize ) );
        tileControl.UpdateLayout();

        tileImage.Render( tileControl, null );
        tileImage.Invalidate();

        tileControl = null;
        GC.Collect( 2, GCCollectionMode.Forced, true );

        // Adjust the rendered bitmap to handle the alpha channel better.
        CompensateForRender( tileImage );

        return tileImage;
    }

同样,我正在对GC.Collect进行显式调用,以便在将此代码作为后台代理程序的一部分运行时帮助控制内存消耗。 CompensateForRender方法基于链接文章中的代码。

希望这有帮助。