以通用且可重复使用的方式执行此操作的一种方法是将 OpacityMask 与 VisualBrush 结合使用,并将 VisualBrush 中的值绑定到图像和网格。这样,当图像和网格移动并改变大小等时,它就会起作用。VisualBrush 可以包含一个画布和一个矩形来实现 0.8 和 1.0 的不透明度。然而,不透明度不能在画布上使用,因为它会影响矩形的不透明度,所以背景会代替。 0.8 等于#CC000000。我用#50000000 来更清楚地展示效果。
更新
Silverlight 版本需要一些解决方法,因此我在此处上传了我的示例应用程序:http://www.mediafire.com/?8pbj5b9t72m5191
WPF 版本(Silverlight 版本也适用于 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;
}
}
更新
我注意到你希望它也能在 Silverlight 中工作。 Silverlight 没有 MultiBinding,但幸运的是 Colin E. 有一个 very nice solution for this。
VisualBrush 也不见了,但 Chris C. 有一个nice solution to that。我必须对 VisualImage 进行一些更改才能完成这项工作。
更改在 OnVisualChanged 中,我为 LayoutUpdated 添加了一个 EventHandler 并将 RenderSize 更改为 ActualWidth/ActualHeight
private FrameworkElement visual = null;
private void OnVisualChanged(DependencyPropertyChangedEventArgs args)
{
//if (args.OldValue != null) ((FrameworkElement)args.OldValue).SizeChanged -= VisualImage_SizeChanged;
if (args.NewValue != null)
{
visual = (FrameworkElement)args.NewValue;
visual.SizeChanged += VisualImage_SizeChanged;
visual.LayoutUpdated += new EventHandler(visual_LayoutUpdated);
PrepareBitmap((int)visual.ActualWidth, (int)visual.ActualHeight);
}
}
void visual_LayoutUpdated(object sender, EventArgs e)
{
PrepareBitmap((int)visual.ActualWidth, (int)visual.ActualHeight);
}
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>