Fade away - Opacity Blending von Masken
Um Masken ein- oder auszublenden scheint die entsprechende Animations sehr simpel. Man nehme schlicht und ergreifend die Maske, schenke ihr eine DoubleAnimation und reduziere das OpacityProperty in einem angemessenen Zeitraum auf den Wert 0. Doch leider stellt man fest, dass die auszublendende Maske im Ausblenden genauso anklickbar ist, wie im normalen Maskenleben.
Einfallsreiche legen dann einen Canvas als Klickschutz darüber, um das Klicken zu unterbinden und es scheint, dass nun das unverklickbare Ausblenden gerettet ist. Doch damit das gut funktioniert müssen folgende Bedingungen gültig sein.
- Der neue Klickschutz-Canvas muss im Z-Layer über allen anderen Masken liegen.
- Die nun anzuzeigenden Masken (Einblendung) müssen im Z-Layer unter den alten Masken liegen.
Will man die gesamte Maske aus- oder einblenden, dann ist das noch relativ leicht machbar. Doch will man einzelne Masken nachladen und dabei einblenden, so muss man diese in einen neuen Canvas kopieren (parent, ist hier im Codebeispiel ein Panel, welches die auszublendenden Maskenteile enthält).
blender = new Canvas();blender.Width = ((Panel)parent).ActualWidth;
blender.Height = ((Panel)parent).ActualHeight;
newblender = true;UIElement[] arr =
new UIElement[((Panel)parent).Children.Count];
((Panel)parent).Children.CopyTo(arr,0);
((Panel)parent).Children.Clear();
foreach (UIElement ele in arr)
{
blender.Children.Add(ele);
}
Insgesamt eine recht einfache Sache, doch irgendwie lästig. Das geht auch eleganter.
Man nehme die wunderbare Klasse “RenderTargetBitmap”, verwende die festgezimmerte Bildschirmauflösung von 96dpi und mache einen Screenshot von den Elementen, die auszublenden sind.
void SnapIt(Panel blender){
RenderTargetBitmap rtb = new
RenderTargetBitmap((int)blender.ActualWidth,
(int) blender.ActualHeight,
96d, 96d, PixelFormats.Pbgra32);
rtb.Render(blender);
Image img = new Image();
img.Source = rtb; blender.Children.Clear();
blender.Children.Add(img);
DoubleAnimation dba = new DoubleAnimation(1d, 0,
new Duration(TimeSpan.FromSeconds(opacityBlendingSeconds)));
dba.Completed += new EventHandler(blender_Completed);
blender.BeginAnimation(Image.OpacityProperty, dba);
}
Damit sich das auch sauber beendet wird noch am Ende der Animation der Eventhandler aufgerufen, der schließlich das Image wieder entfernt.
void blender_Completed(object sender, EventArgs e)
{
if (sender != null && sender is Image
&& ((Image)sender).Parent != null
&& ((Image)sender).Parent is Panel)
{
lock (sender)
{
((Image)sender).Visibility = Visibility.Hidden;
((Panel)((Image)sender).Parent).Children.Remove(((Image)sender));
}
}
}
Nicht vergessen sollte man, dasss man mit mehreren Threads arbeitet, also munter Exception fangen und behandeln (hier im Codebeispiel verzichte ich aus Platzgründen auf die entsprechende Fehlerbehandlung).
Insgesamt kann man mit den Screenshots (genauer dem Rendern in eine Bitmap) recht gut arbeiten. Es sind eine Menge Effekte denkbar, nicht nur das Aus- und Einblenden.