windows-phone-8 - 如何创建具有自定义布局的 WP8 动态磁贴?

标签 windows-phone-8 live-tile

我正在创建一个与标志性图 block 类似的动态图 block ,但允许我使用自定义计数值(即非整数字符串)。

我最接近的是我必须使用位图创建内容,然后使用该图像作为图 block 。不幸的是我不知道这通常是如何完成的。

我正在寻找创建类似于此问题中描述的图 block (尽管此问题与我的问题正交):Custom live tile rendering issue on Windows Phone (7/8)

简而言之,

  • WriteableBitmap 是创建动态磁贴布局的最佳方式吗?
  • 是否有一种机制可以将 XAML 转换为动态磁贴?

我想要实现的布局示例在 Skype Live Tile 中有所显示,如 here .

最佳答案

据我所知,创建自定义位图是正确的方法。我发现this answer以及this 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;
    }

这是一个 super 简单的控件,只有一个 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 方法基于链接文章中的代码。

希望这有帮助。

关于windows-phone-8 - 如何创建具有自定义布局的 WP8 动态磁贴?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16258758/

相关文章:

rss - IE11/Windows 8.1 带照片的动态磁贴

c# - 在 Windows Phone 8.1 中更新动态磁贴

c# - 如何在 Windows 8 中设置默认磁贴大小?

c# - 尝试从 Windows Phone 8.1 : "The application identifier provided is invalid" 中的 backgroundaudiotask 更新 livetile

c# - 即使在使用任务时也无法等待 'Void'

Windows 8.1 Professional Hyper-V 无法启动

javascript - Windows Azure 移动服务 : dont insert more than once the same data

windows-phone-8 - 当我的 WP8 应用程序使用本地 linq to sql 数据库时,如何将其迁移到通用版本?

windows-phone-8 - 接收 2.1 : How to subscribe and observe on Dispatcher correctly