0

我有一些旨在将 ControlTemplate 呈现为 writeableBitmap 的代码。创建WBMP的代码如下:

    private static void OnMarkerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var template = e.NewValue as ControlTemplate;
        if (template != null)
        {
            var c = new Marker();
            c.Template = template;
            c.ApplyTemplate();
            c.MeasureArrange();
            c.Width = c.DesiredSize.Width;
            c.Height = c.DesiredSize.Height;

            // _cachedBitmap is of type WriteableBitmap
            _cachedBitmap = c.RenderToBitmap();
        }
    }   

其中定义了以下扩展方法:

    internal static void MeasureArrange(this UIElement element)
    {
        element.Measure(new Size(Double.PositiveInfinity, Double.PositiveInfinity));
        element.Arrange(new Rect(new Point(0, 0), element.DesiredSize));
    }

    public static WriteableBitmap RenderToBitmap(this FrameworkElement element)
    {
        int width = (int)element.DesiredSize.Width;
        int height = (int)element.DesiredSize.Height;

#if SILVERLIGHT
        var result = new WriteableBitmap(width, height);
        result.Render(element, new TranslateTransform());
        result.Invalidate();
        return result;
#else
        // WPF Impl works just fine
        var bmp = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);

        bmp.Render(element);
        return new WriteableBitmap(bmp);
#endif         
    }

并且 Marker 被定义为一个空控件

public class Marker : Control
{         
}

问题是这样的。在 WPF 中,这一切都可以正常工作,就像在第一次尝试创建位图后在 Silverlight 中一样。但是,第一次尝试失败,返回正确大小(7*7 或 49 像素)但int[] Pixels数组中全为零的 WriteableBitmap。

一些可能有用的东西。在 WriteableBitmap 创建之前RenderToBitmap,元素的宽度/高度为 7,7,所需大小为 (7,7),但实际宽度/实际高度为 (0,0)。在 WPF 中,我相信都是(7,7)。所以这可能是布局问题而不是

仅供参考,Marker 和 ControlTemplate 永远不会进入可视化树。这是一个纯粹的缓存位图实现。

有任何想法吗?

4

1 回答 1

0

啊哈!我找到了答案。虽然我不知道为什么。任何能解释它的人都可以回答“答案”。

我发现这个链接表明 ActualWidth / ActualHeight 是异步评估的,因此一个很好的 BeginInvoke 可以解决这个问题。为什么这在 WPF 中有效,但在 Silverlight 中无效?

        var c = new PointMarker();
        c.Template = pointMarkerTemplate;
        c.ApplyTemplate();

        // DispatcherUtil is just a proxy around Dispatcher.BeginInvoke
        DispatcherUtil.Instance.BeginInvoke(() =>
        {
            c.MeasureArrange();
            c.Width = c.DesiredSize.Width;
            c.Height = c.DesiredSize.Height;
            series._pointMarkerCache = c.RenderToBitmap();
            series.OnInvalidateParentSurface();
        });
于 2012-02-29T21:21:59.590 回答