2012-02-29 48 views
0

我有一些代码旨在将ControlTemplate渲染为writeableBitmap。创建WBMP的代码如下:Silverlight 4渲染为WriteableBitmap返回空位图

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   
    } 

和标记被定义为一个空的控制

public class Marker : Control 
{   
} 

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

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

仅供参考标记和控制模板从未将其设置到视觉树上。这是一个纯粹缓存的位图实现。

任何想法?

回答

0

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

我发现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(); 
     }); 
+1

很可能计算ActualWidth/ActualHeight的Silverlight测量通过第1次重新设置为0,然后重新计算新值并在返回前设置它们。所以我猜如果你的代码在其他线程上执行而不是代码,你可能会在重新计算过程中读取这些值,从而读取0.但是,如果某个resize事件导致重新计算发生,那么这将是一种情况,不明白为什么它会一直重新计算这些值 – 2013-08-04 04:42:44