2012-02-29 23 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