One way to make this a universal and reusable way is to use OpacityMask with VisualBrush and associate the values ββin VisualBrush with the image and the grid. This way it will work when the image and grid are moved and resized, etc. VisualBrush can contain a canvas and a rectangle to achieve opacity 0.8 and 1.0. Opacity cannot be used on the canvas, as it will affect the opacity of the rectangle so that Background is executed instead. 0.8 is # CC000000. I used # 50,000,000 to show the effect more clearly.

Update
Some workarounds were needed for Silverlight, so I downloaded my application for an example here: http://www.mediafire.com/?8pbj5b9t72m5191
WPF version (Silverlight version will also work in WPF)
<Canvas x:Name="LayoutRoot" Background="White"> <Canvas.Resources> <local:SubtractMultiConverter x:Key="SubtractMultiConverter"/> <local:MaxValueMultiConverter x:Key="MaxValueMultiConverter"/> </Canvas.Resources> <Image Name="image" Source="C:\FG.png" Stretch="Fill" Height="300" Width="310" Canvas.Left="100" Canvas.Top="200"> <Image.OpacityMask> <VisualBrush> <VisualBrush.Visual> <Canvas Background="#50000000" Width="{Binding ElementName=image, Path=ActualWidth}" Height="{Binding ElementName=image, Path=ActualHeight}"> <Rectangle Fill="#FF000000"> <Rectangle.Width> <MultiBinding Converter="{StaticResource MaxValueMultiConverter}"> <Binding ElementName="rectToGetXAndY" Path="ActualWidth"/> <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Left)"/> <Binding ElementName="image" Path="ActualWidth"/> </MultiBinding> </Rectangle.Width> <Rectangle.Height> <MultiBinding Converter="{StaticResource MaxValueMultiConverter}"> <Binding ElementName="rectToGetXAndY" Path="ActualHeight"/> <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Top)"/> <Binding ElementName="image" Path="ActualHeight"/> </MultiBinding> </Rectangle.Height> <Canvas.Left> <MultiBinding Converter="{StaticResource SubtractMultiConverter}"> <Binding ElementName="rectToGetXAndY" Path="(Canvas.Left)"/> <Binding ElementName="image" Path="(Canvas.Left)"/> </MultiBinding> </Canvas.Left> <Canvas.Top> <MultiBinding Converter="{StaticResource SubtractMultiConverter}"> <Binding ElementName="rectToGetXAndY" Path="(Canvas.Top)"/> <Binding ElementName="image" Path="(Canvas.Top)"/> </MultiBinding> </Canvas.Top> </Rectangle> </Canvas> </VisualBrush.Visual> </VisualBrush> </Image.OpacityMask> </Image> <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143" Canvas.Left="123" Canvas.Top="272" Opacity="0.6"/> </Canvas>
SubtractMultiConverter
public class SubtractMultiConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double value = (double)values[0]; double subtractValue = (double)values[1]; return value - subtractValue; } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { return null; } }
MaxValueMultiConverter
public class MaxValueMultiConverter : IMultiValueConverter { public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture) { double desiredWidth = (double)values[0]; double canvasValue = (double)values[1]; double actualWidth = (double)values[2]; return Math.Min(desiredWidth, actualWidth - canvasValue); } public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture) { return null; } }
Update
I noticed that you want this to work in Silverlight as well. Silverlight does not have MultiBinding, but fortunetely Colin E. has a very good solution for this .
VisualBrush is also missing, but Chris C. has a great solution for this . I had to make some changes to VisualImage to make this work.
The changes were in OnVisualChanged, I added an EventHandler for LayoutUpdated and changed the RenderSize to ActualWidth / ActualHeight
private FrameworkElement visual = null; private void OnVisualChanged(DependencyPropertyChangedEventArgs args) {
Silverlight xaml
<UserControl.Resources> <local:SubtractMultiConverter x:Key="SubtractMultiConverter"/> <local:MaxValueMultiConverter x:Key="MaxValueMultiConverter"/> <Canvas x:Key="testBorder" Background="#50000000" Width="{Binding ElementName=image, Path=ActualWidth}" Height="{Binding ElementName=image, Path=ActualHeight}"> <Rectangle Fill="#FF000000"> <binding:BindingUtil.MultiBindings> <binding:MultiBindings> <binding:MultiBinding TargetProperty="Width" Converter="{StaticResource MaxValueMultiConverter}"> <binding:MultiBinding.Bindings> <binding:BindingCollection> <Binding ElementName="rectToGetXAndY" Path="ActualWidth"/> <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Left)"/> <Binding ElementName="image" Path="ActualWidth"/> </binding:BindingCollection> </binding:MultiBinding.Bindings> </binding:MultiBinding> <binding:MultiBinding TargetProperty="Height" Converter="{StaticResource MaxValueMultiConverter}"> <binding:MultiBinding.Bindings> <binding:BindingCollection> <Binding ElementName="rectToGetXAndY" Path="ActualHeight"/> <Binding RelativeSource="{RelativeSource self}" Path="(Canvas.Top)"/> <Binding ElementName="image" Path="ActualHeight"/> </binding:BindingCollection> </binding:MultiBinding.Bindings> </binding:MultiBinding> <binding:MultiBinding TargetProperty="Canvas.Left" Converter="{StaticResource SubtractMultiConverter}"> <binding:MultiBinding.Bindings> <binding:BindingCollection> <Binding ElementName="rectToGetXAndY" Path="(Canvas.Left)"/> <Binding ElementName="image" Path="(Canvas.Left)"/> </binding:BindingCollection> </binding:MultiBinding.Bindings> </binding:MultiBinding> <binding:MultiBinding TargetProperty="Canvas.Top" Converter="{StaticResource SubtractMultiConverter}"> <binding:MultiBinding.Bindings> <binding:BindingCollection> <Binding ElementName="rectToGetXAndY" Path="(Canvas.Top)"/> <Binding ElementName="image" Path="(Canvas.Top)"/> </binding:BindingCollection> </binding:MultiBinding.Bindings> </binding:MultiBinding> </binding:MultiBindings> </binding:BindingUtil.MultiBindings> </Rectangle> </Canvas> </UserControl.Resources> <Canvas x:Name="LayoutRoot" Background="White"> <local:VisualImage x:Name="visualImage" Visual="{Binding Source={StaticResource testBorder}}" ImageBrush="{Binding ElementName=brush}"/> <Image Name="image" Source="/GridImageOpacityMask;component/Images/FG.png" Stretch="Fill" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200"> <Image.OpacityMask> <ImageBrush x:Name="brush" /> </Image.OpacityMask> </Image> <Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143" Opacity="0.6" Canvas.Left="223" Canvas.Top="272"/> </Canvas>