2010-05-17 33 views
7

Tôi đã tìm thấy một bước ngoặt mới về câu hỏi "Visual to RenderTargetBitmap"!RenderTargetBitmap + Resource'd VisualBrush = hình ảnh không đầy đủ

Tôi đang hiển thị xem trước nội dung WPF cho một nhà thiết kế. Điều đó có nghĩa là tôi cần phải có một hình ảnh WPF và đưa nó vào một bitmap mà không có hình ảnh đó từng được hiển thị. Có một phương pháp ít tốt đẹp để làm điều đó muốn nhìn thấy nó ở đây nó đi

private static BitmapSource CreateBitmapSource(FrameworkElement visual) 
{ 
    Border b = new Border { Width = visual.Width, Height = visual.Height }; 
    b.BorderBrush = Brushes.Black; 
    b.BorderThickness = new Thickness(1); 
    b.Background = Brushes.White; 
    b.Child = visual; 

    b.Measure(new Size(b.Width, b.Height)); 
    b.Arrange(new Rect(b.DesiredSize)); 

    RenderTargetBitmap rtb = new RenderTargetBitmap(
           (int)b.ActualWidth, 
           (int)b.ActualHeight, 
           96, 
           96, 
           PixelFormats.Pbgra32); 

    // intermediate step here to ensure any VisualBrushes are rendered properly 
    DrawingVisual dv = new DrawingVisual(); 
    using (var dc = dv.RenderOpen()) 
    { 
     var vb = new VisualBrush(b); 
     dc.DrawRectangle(vb, null, new Rect(new Point(), b.DesiredSize)); 
    } 
    rtb.Render(dv); 
    return rtb; 
} 

Hoạt động tốt, ngoại trừ một điều leeetle ... nếu FrameworkElement tôi có một VisualBrush, bàn chải mà không kết thúc trong trận chung kết bitmap được hiển thị. Một cái gì đó như thế này:

<UserControl.Resources> 
    <VisualBrush 
     x:Key="LOLgo"> 
     <VisualBrush.Visual> 
      <!-- blah blah --> 
<Grid 
    Background="{StaticResource LOLgo}"> 
<!-- yadda yadda --> 

Mọi thứ khác hiển thị với bitmap, nhưng VisualBrush đó sẽ không hiển thị. Các giải pháp google rõ ràng đã được thử và đã thất bại. Ngay cả những cái mà đề cập cụ thể VisualBrushes thiếu từ bitmap RTB'd.

Tôi có một sự nghi ngờ lén lút điều này có thể là do thực tế là Tài nguyên của nó và tài nguyên lười biếng đó không được gạch chân. Vì vậy, một sửa chữa có thể sẽ được, bằng cách nào đó (???), lực lượng giải quyết tất cả các tài liệu tham khảo tài nguyên tĩnh trước khi dựng hình. Nhưng tôi hoàn toàn không có ý tưởng làm thế nào để làm điều đó.

Mọi người có khắc phục sự cố này không?

Trả lời

13

Bạn có hai vấn đề:

  1. Bạn đã không thiết lập một PresentationSource vào các sự kiện để Loaded hình ảnh của bạn sẽ không cháy.
  2. Bạn không xóa hàng đợi Bộ điều phối. Nếu không xả hàng đợi Dispatcher, bất kỳ chức năng nào sử dụng gọi lại Dispatcher sẽ không hoạt động.

Nguyên nhân trực tiếp của sự cố của bạn là không xóa hàng đợi Bộ điều phối, vì VisualBrush sử dụng nó, nhưng có thể bạn sẽ gặp sự cố PresentationSource trước khi lâu nên tôi sẽ sửa cả hai.

Sau đây là cách tôi làm điều đó:

// Create the container 
var container = new Border 
{ 
    Child = contentVisual, 
    Background = Brushes.White, 
    BorderBrush = Brushes.Black, 
    BorderThickness = new Thickness(1), 
}; 

// Measure and arrange the container 
container.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); 
container.Arrange(new Rect(container.DesiredSize)); 

// Temporarily add a PresentationSource if none exists 
using(var temporaryPresentationSource = new HwndSource(new HwndSourceParameters()) { RootVisual = (VisualTreeHelper.GetParent(container)==null ? container : null) }) 
{ 
    // Flush the dispatcher queue 
    Dispatcher.Invoke(DispatcherPriority.SystemIdle, new Action(() => { })); 

    // Render to bitmap 
    var rtb = new RenderTargetBitmap((int)b.ActualWidth, (int)b.ActualHeight, 96, 96, PixelFormats.Pbgra32); 
    rtb.Render(container); 

    return rtb; 
} 

FYI, StaticResource tra cứu không bao giờ trì hoãn trong mọi trường hợp: Nó được xử lý thời điểm XAML được nạp và ngay lập tức thay thế bằng giá trị lấy từ ResourceDictionary. Chỉ chỉ cách StaticResource có thể có thể là có liên quan là nếu nó nhặt nhầm tài nguyên vì hai tài nguyên có cùng khóa. Tôi chỉ nghĩ rằng tôi nên giải thích điều này - nó không liên quan gì đến vấn đề thực tế của bạn.

+0

Vâng, tôi đã đọc và thử xả bộ điều phối, nhưng điều đó không giúp ích gì cho chính nó. Tôi sẽ thử thêm nguồn trình bày mà tôi không làm. Cảm ơn. – Will

+0

Hãy chắc chắn rằng bạn xả điều phối cuối cùng, sau khi tất cả các bước khác được thực hiện.Ngoài ra tôi nhận thấy bạn thiết lập chiều cao và với biên giới của bạn một cách rõ ràng, trong khi tôi đo bằng PositiveInfinity. –

+0

@ray vâng, tôi đã làm điều đó một lúc rồi nhận ra rằng biện pháp chỉ cần biết tối đa, chứ không phải là thực tế. Tôi đã làm nó với + inf kể từ khi tôi học được điều đó. Sẽ sớm cố gắng này. – Will

0

Vâng để inline nó, bạn chỉ có thể làm điều gì đó như thế này:

<Grid> 
    <Grid.Background> 
     <VisualBrush> 
      <VisualBrush.Visual> 
       <!-- blah blah --> 
      </VisualBrush.Visual> 
     </VisualBrush> 
    </Grid.Background> 
</Grid> 

Nếu điều đó không làm việc, tôi đoán sẽ được rằng nó phải là một cái gì đó cụ thể với các Visual dụ bạn đang sử dụng (và sẽ yêu cầu thêm mã để chẩn đoán tốt hơn).

+1

Tôi không muốn phải giải thích cho mọi người "Này, tôi biết hình thu nhỏ chưa hoàn chỉnh. Tại sao bạn không tiếp tục và không sử dụng tài nguyên brush kthx." – Will

Các vấn đề liên quan