2

我希望创建一个与 Iconic 磁贴类似的动态磁贴,但允许我使用自定义计数值(即非整数字符串)。

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

我希望创建类似于此问题中描述的图块(尽管此问题与我的问题正交):Windows Phone 上的自定义实时图块渲染问题 (7/8)

简而言之,

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

我想要实现的布局示例显示在此处看到的 Skype Live Tile 中。

4

1 回答 1

4

据我所知,创建自定义位图是可行的方法。我发现这个答案这篇文章在我做动态图块时非常有帮助。

如果您不介意购买第三方控件,您可以查看 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,但您可以轻松地对此进行扩展。请注意,我在这里不使用 a 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方法基于链接文章中的代码。

希望这可以帮助。

于 2013-04-29T14:01:36.303 回答