Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use another control as an opacity mask in WPF?

I'm trying to use the OpacityMask property combined with a VisualBrush so that when you drag an image over another control (such as another image, rectangle, or any other control), the part of the image that is over the second control has a different opacity. That is, the image has some non-zero base opacity, and any part of the image that is over another control has a different (again, non-zero) opacity.

Is this possible simply using VisualBrush and OpacityMask? Or is a more complex approach required?

Thanks!

Edit: I'm trying to make the image have some lower opacity (such as 0.5), and the part being dragged over the control have a higher opacity (such as 1.0). I originally left out this detail, which is important to the approach taken.

like image 785
nsantorello Avatar asked Aug 05 '09 15:08

nsantorello


2 Answers

In addition to ima's answer, I have figured this out using an opacity mask. I use the following code hooked into the LayoutUpdated event for the image.

// Make a visual brush out of the masking control.
VisualBrush brush = new VisualBrush(maskingControl);
// Set desired opacity.
brush.Opacity = 1.0;
// Get the offset between the two controls.
Point offset = controlBeingMasked.TranslatePoint(new Point(0, 0), maskingControl);
// Determine the difference in scaling.
Point scale = new Point(maskingControl.ActualWidth / controlBeingMasked.ActualWidth, 
    maskingControl.ActualHeight / controlBeingMasked.ActualHeight);
TransformGroup group = new TransformGroup();
// Set the scale of the mask.
group.Children.Add(new ScaleTransform(scale.X, scale.Y, 0, 0));
// Translate the mask so that it always stays in place.
group.Children.Add(new TranslateTransform(-offset.X, -offset.Y));
// Rotate it by the reverse of the control, to keep it oriented correctly.
// (I am using a ScatterViewItem, which exposes an ActualOrientation property)
group.Children.Add(new RotateTransform(-controlBeingMasked.ActualOrientation, 0, 0));
brush.Transform = group;
controlBeingMasked.OpacityMask = brush;

If you want a desired base opacity, use two images; one that's always at the base opacity, and another that uses the opacity mask that sits on top of it. If you want the base opacity to be higher than the masked opacity, then it might be easier to use ima's approach.

One advantage of this solution as opposed to the maskless approach is that if the masking control moves, changes size, etc., this will automatically pick up the change without having to keep another control in sync with it.

Here's how it looks:
(source: yfrog.com)

like image 78
nsantorello Avatar answered Nov 16 '22 07:11

nsantorello


  • No masks
  • Define visual brush for the control
  • Paint shape right on top of the control with that brush
  • Drag image between the shape and the control
  • Set opacity of the brush to achieve desired effect
like image 34
ima Avatar answered Nov 16 '22 07:11

ima