RenderTargetBitmap + Resource'd VisualBrush =不完全な画像
-
27-09-2019 - |
質問
「Visual to RenderTargetBitmap」という質問に新しいひねりを加えました!
デザイナーのためにWPFのプレビューをレンダリングしています。つまり、WPFビジュアルを採用して、そのビジュアルが表示されずにビットマップにレンダリングする必要があります。ここでそれを見るのが好きでそれをするのに素敵な小さな方法を手に入れました
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;
}
1つのLeeetleのものを除いて、正常に動作します...私のフレームワークセレメントにVisualBrushがある場合、そのブラシは最終レンダリングされたビットマップに終わりません。このようなもの:
<UserControl.Resources>
<VisualBrush
x:Key="LOLgo">
<VisualBrush.Visual>
<!-- blah blah -->
<Grid
Background="{StaticResource LOLgo}">
<!-- yadda yadda -->
他のすべてはビットマップにレンダリングされますが、そのビジュアルブラシは表示されません。明らかなGoogleソリューションは試みられ、失敗しました。 rtb'd bitmapsに欠けているビジュアルブラシについて特に言及しているものでさえ。
これは、そのリソースであり、その怠zyなリソースがインラキングされていないという事実によって引き起こされるかもしれない卑劣な疑いがあります。したがって、可能な修正は、どういうわけか(???)、レンダリング前にすべての静的リソース参照を強制的に解決することです。しかし、私はそれを行う方法をまったく知りません。
誰かがこれの修正を持っていますか?
解決
2つの問題があります。
- 視覚的にプレゼンテーションソースを設定しなかったため、ロードされたイベントが発生しません。
- ディスパッチャーキューを洗い流しませんでした。ディスパッチャーキューをフラッシュせずに、ディスパッチャーコールバックを使用する機能は機能しません。
あなたの問題の当面の原因は、VisualBrushがそれを使用するため、ディスパッチャーキューをフラッシュできないことですが、おそらくあなたはおそらくプレゼンテーションソースの問題に遭遇するので、これらの両方を修正します。
これが私がそれをする方法です:
// 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;
}
参考までに、stateCresourceルックアップはいかなる状況でも遅延することはありません。XAMLがロードされた瞬間に処理され、Resourcedictionaryから取得された値にすぐに置き換えられます。 それだけ stateCresourceができる方法 おそらく 2つのリソースが同じキーを持っていたため、間違ったリソースを受け取った場合は関連しています。私はこれを説明するべきだと思っただけです - それはあなたの実際の問題とは何の関係もありません。
他のヒント
それをインラインで、このようなことをすることができます:
<Grid>
<Grid.Background>
<VisualBrush>
<VisualBrush.Visual>
<!-- blah blah -->
</VisualBrush.Visual>
</VisualBrush>
</Grid.Background>
</Grid>
それがうまくいかない場合、私の推測では、 Visual
使用しているインスタンス(そして、より良い診断にはさらなるコードが必要になります)。