【问题标题】:Silverlight 4 Render to WriteableBitmap returns empty bitmapSilverlight 4 渲染到 WriteableBitmap 返回空位图
【发布时间】:2012-02-29 20:54:32
【问题描述】:

我有一些代码旨在将 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。

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

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

有什么想法吗?

【问题讨论】:

    标签: c# silverlight writeablebitmap


    【解决方案1】:

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

    我发现 this link 表明 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();
            });
    

    【讨论】:

    • 计算 ActualWidth/ActualHeight 的 Silverlight Measurement pass 可能是第一次将它们重置为 0,然后重新计算新值并在返回之前设置它们。所以我猜如果您的代码在该代码之外的其他线程上执行,您可能会在重新计算期间读取这些值并因此读取 0。但是,如果某些调整大小事件导致重新计算发生,那就是这种情况,不明白为什么它会一直重新计算这些值
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多