How to render a checked CheckBox (Aero theme) to a RenderTargetBitmap?
My checkbox is rendered without a check mark. If I use only one checkbox (instance object) to render then I can get the check mark to show, but I cannot use this solution. I need be able to render it using the local checkbox. This checkbox has the Aero theme applied to it via "/PresentationFramework.Aero;component/themes/Aero.NormalColor.xaml" and this is also a must have for me. Other themes built-in themes like Royal, and Luna render with a check mark.
XAML
<Canvas Name="canvas">
<Button Click="Button_Click" Canvas.Left="440" Canvas.Top="277">
Do Paint
</Button>
<Image Name="image"/>
</Canvas>
C#
private void Button_Click(object sender, RoutedEventArgs e) {
var checkBox = new CheckBox { Width = 100, Height = 30, IsChecked = true, };
var rectangle = new Rect(0, 0, checkBox.Width, checkBox.Height);
//need this
var visualBrush = new VisualBrush(checkBox);
checkBox.Arrange(rectangle);
var renderTargetBitmap = new RenderTargetBitmap((int)rectangle.Width, (int)rectangle.Height, 96, 96, PixelFormats.Default);
renderTargetBitmap.Render开发者_开发技巧(checkBox);
renderTargetBitmap.Freeze();
image.Source = renderTargetBitmap;
}
I used Reflector to look at the content of the PresentationFramework.Aero assembly, and I found out what's going on here. I have a solution, but you're probably not going to like it...
In the Aero theme, checkboxes are rendered with a BulletChrome
control. This control uses animations when it switches from one state to another, so when you render the checkbox, the animation from unchecked to checked is not complete, and the tick mark is not yet visible. So you need to wait for the animation to complete...
Just putting a Thread.Sleep
before rendering won't work, because while the dispatcher thread is sleeping, the animation will be stopped. So you need to start a new thread where you wait before rendering the checkbox:
private void Button_Click(object sender, RoutedEventArgs e)
{
var checkBox = new CheckBox { Width = 100, Height = 30, IsChecked = true, };
var rectangle = new Rect(0, 0, checkBox.Width, checkBox.Height);
//need this
var visualBrush = new VisualBrush(checkBox);
checkBox.Arrange(rectangle);
new Thread(() =>
{
Thread.Sleep(300); // the animation lasts 300ms
Dispatcher.Invoke(() =>
{
var renderTargetBitmap =
new RenderTargetBitmap((int)rectangle.Width,
(int)rectangle.Height, 96, 96,
PixelFormats.Default);
renderTargetBitmap.Render(checkBox);
renderTargetBitmap.Freeze();
image.Source = renderTargetBitmap;
});
}).Start();
}
(this code uses the DispatcherExtensions.Invoke
extension method, so you need to reference the System.Windows.Presentation assembly and import the System.Windows.Threading
namespace)
Note that the animation doesn't occur if SystemParameters.ClientAreaAnimation
is false. But since this property is readonly, it doesn't really help you...
精彩评论