问题
I have applied opacity to the image. Here is the code :-
<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="DelSilverlightApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<Canvas x:Name="LayoutRoot" Background="White">
<Image Source="Vista.jpg" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200" Opacity="0.8"/>
<Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143" Opacity="0.6" Canvas.Left="223" Canvas.Top="272" />
</Canvas>
</UserControl>
I want that only the area of the image inside of Grid should be set to opacity of 1 else it should remain 0.8. Any ideas how can i do that? This is very vital to my application but somehow i can't find a solution to it.
Thanks in advance :)
回答1:
One way to do this in a Generic and re-usable way is to use an OpacityMask with a VisualBrush and bind the values within the VisualBrush to the Image and the Grid. This way, it will work when the Image and Grid move around and change in Size etc. The VisualBrush can contain a Canvas and a Rectangle to achieve the 0.8 and 1.0 Opacity. Opacity can't be used on the Canvas however since it will effect the Opacity of the Rectangle so Background will do instead. 0.8 is equal to #CC000000. I used #50000000 to show the effect more clearly.

Update
Some workarounds were needed for the Silverlight version of this so I uploaded my sample app 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 you wanted this to work in Silverlight as well. Silverlight doesn't have MultiBinding but fortuanetely Colin E. has a very nice solution for this.
VisualBrush is also missing, but Chris C. has a nice solution to that. 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 RenderSize to 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>
回答2:
You can use another Image
with an OpacityMask
set to a VisualBrush
that results in a clipping rectangle like this:
<Canvas x:Name="LayoutRoot" Background="White">
<Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200" Opacity="0.5"/>
<Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
<Image.OpacityMask>
<VisualBrush Stretch="None">
<VisualBrush.Visual>
<Rectangle Width="254" Height="143" Fill="Black"/>
</VisualBrush.Visual>
</VisualBrush>
</Image.OpacityMask>
</Image>
<Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143" Opacity="0.6" Canvas.Left="223" Canvas.Top="272" />
</Canvas>
and here's another method using Image.Clip
:
<Canvas x:Name="LayoutRoot" Background="White">
<Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200" Opacity="0.5"/>
<Image Source="http://thecybershadow.net/misc/hax.png" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
<Image.Clip>
<RectangleGeometry Rect="23,72,254,143"/>
</Image.Clip>
</Image>
<Grid x:Name="rectToGetXAndY" Canvas.ZIndex="3" Width="254" Height="143" Opacity="0.6" Canvas.Left="223" Canvas.Top="272" />
</Canvas>
回答3:
Here is a lateral solution:-
<Canvas x:Name="LayoutRoot" Background="White">
<Grid x:Name="ImageContainer" Height="300" Width="310" Canvas.Left="200" Canvas.Top="200">
<Image Source="Vista.jpg" />
<Border x:Name="rectToGetXAndY" Background="Transparent" BorderThickness="23, 72, 85, 33" BorderBrush="#99FFFFFF" />
</Grid>
</Canvas>
This provides the same visual appearance of a vibrant rectangle in a washed out image. The apparent rectangle can be manipulated by modifying the BorderThickness
property. Events from this rectangle can be trapped on the Border
because a Transparent background has been added so it can be dragged about for example. Other content could be added to internals of the Border
, for example a Grid of transparent rectangles could provide some sizing features.
The accepted answer here is significantly more complex by comparison albeit a more direct answer to your actual question.
来源:https://stackoverflow.com/questions/4571059/is-it-possible-to-only-highlight-certain-part-of-image-opacity