【问题标题】:Is it possible to only highlight certain part of image (opacity)?是否可以只突出图像的某些部分(不透明度)?
【发布时间】:2011-01-06 08:35:46
【问题描述】:

我已对图像应用不透明度。这是代码:-

<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>

我希望只有 Grid 内的图像区域应该设置为 1 的不透明度,否则它应该保持 0.8。有什么想法我该怎么做?这对我的应用程序非常重要,但不知何故我找不到解决方案。

提前致谢:)

【问题讨论】:

  • 图像在画布而不是网格中...?
  • @Aaron :- 是的!它在画布上。就像你看到的那样。如果您有任何其他布局更改但外观和感觉相同的其他解决方案,请告诉我。
  • 您需要 Silverlight 中的这项工作吗?
  • @AnthonyWJones :是的,我在 Silverlight 中需要它。

标签: wpf silverlight


【解决方案1】:

以通用且可重复使用的方式执行此操作的一种方法是将 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>

【讨论】:

  • - 很好的解决方案。但是代码太多了。我不知道要达到那么简单的效果会这么难。我对 Multibindgs 不是很熟悉。我将不得不逐段剖析代码以获得更好的理解。但解决方案正是我想要的。
  • @Ankit Rathod:我同意,为此编写了很多代码,但我想不出更简单的解决方案。如果有什么想法我会更新。
【解决方案2】:

您可以使用另一个Image 并将OpacityMask 设置为VisualBrush,从而生成如下所示的剪切矩形:

<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>

这是使用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】:

    这是一个横向的解决方案:-

        <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>
    

    这在褪色的图像中提供了与充满活力的矩形相同的视觉外观。可以通过修改BorderThickness 属性来操作明显的矩形。来自这个矩形的事件可以被困在Border 上,因为已经添加了透明背景,因此可以拖动它。其他内容可以添加到Border 的内部,例如透明矩形网格可以提供一些大小调整功能。

    相比之下,这里接受的答案要复杂得多,尽管它是对您的实际问题的更直接的答案。

    【讨论】:

      猜你喜欢
      • 2011-07-04
      • 1970-01-01
      • 2012-04-17
      • 2012-02-24
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 2019-11-12
      • 1970-01-01
      相关资源
      最近更新 更多