ScrollViewer边缘模糊效果,不透明效应无法正常工作

发布于 2024-08-15 04:53:06 字数 1717 浏览 5 评论 0原文

我想为触摸屏应用程序创建一个自定义滚动查看器控件,而不使用滚动条。为了让用户知道他们可以滚动内容,我使用不透明蒙版通过线性渐变淡化滚动查看器的底部和顶部部分。这一切都工作正常,除了除了滚动查看器之外还应用于文本块的不透明蒙版的问题!

我的意思是,我希望将淡入淡出效果应用于滚动查看器的顶部 1% 和底部 1%,然后滚动查看器的中间将可见。然而问题是,即使我在文本块上设置了 OpacityMask="{x:Null}",这种效果也会发生在滚动查看器内的控件上。

我也尝试将不透明度蒙版应用到滚动查看器的外部,但发生了同样的问题。 Opacitymask 属性也适用于儿童吗?有没有更好的方法来实现这种褪色效果?

这是我正在使用的代码:

<Grid Width="200" Height="130">
    <ScrollViewer BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"
                           HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" >
        <ScrollViewer.OpacityMask>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientStop Color="Transparent" Offset="0" />
                <GradientStop Color="Black" Offset="0.1" />
                <GradientStop Color="Black" Offset="0.9" />
                <GradientStop Color="Transparent" Offset="1" />
            </LinearGradientBrush>
        </ScrollViewer.OpacityMask>
        <TextBlock Margin="0,10" Style="{StaticResource textSmall}" TextWrapping="Wrap">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
        </TextBlock>
    </ScrollViewer>
</Grid>

I want to create a custom scrollviewer control for a touch screen application without using scrollbars. To accomplish letting the users know that they can scroll the content, I am fading the bottom and top part of the scrollviewer with a linear gradient using an opacitymask. This all works fine, except for a problem with the opacitymask applying to the textblock in addition to the scrollviewer!

What I mean is, I would like the fading effect to apply to the top 1% and bottom 1% of the scrollviewer, and then the middle of the scrollviewer will be visible. The problem, however, is that this effect is also happening on the control within the scrollviewer as well, even if i set OpacityMask="{x:Null}" on the textblock.

I have tried applying the opacitymask to the outside of the scrollviewer as well but the same problem happens. Does the Opacitymask property apply to the children as well? Is there a better way to doing this fading effect?

Here is the code I am using:

<Grid Width="200" Height="130">
    <ScrollViewer BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"
                           HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" >
        <ScrollViewer.OpacityMask>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientStop Color="Transparent" Offset="0" />
                <GradientStop Color="Black" Offset="0.1" />
                <GradientStop Color="Black" Offset="0.9" />
                <GradientStop Color="Transparent" Offset="1" />
            </LinearGradientBrush>
        </ScrollViewer.OpacityMask>
        <TextBlock Margin="0,10" Style="{StaticResource textSmall}" TextWrapping="Wrap">
        Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
        </TextBlock>
    </ScrollViewer>
</Grid>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

染墨丶若流云 2024-08-22 04:53:06

我知道这是一个较旧的问题,但我遇到这个问题是因为我试图做类似的事情;所以我想我应该为下一个人发布我的解决方案。对我的解决方案的任何反馈都将受到赞赏。

在我们的应用程序中,大多数 ScrollViewer 控件都位于非滚动纹理的顶部,因此我们希望可滚动内容淡入 ScrollViewer 边缘的背景中,但前提是该方向上有更多内容。此外,我们至少有一个 2 轴可滚动区域,用户可以在其中向各个方向平移。它也必须在这种情况下发挥作用。我们的应用程序实际上也没有滚动条,但我已将其排除在我在此介绍的解决方案之外(它不会影响解决方案)。

此解决方案的特点:

  1. 如果 ScrollViewer 一侧存在当前不可见的内容,则淡化 ScrollViewer 内内容的边缘。

  2. 当您滚动靠近内容边缘时,降低淡入淡出效果的强度。

  3. 对褪色边缘的外观进行一定程度的控制。具体来说,您可以控制:

    1. 褪色边缘的厚度
    2. 最外边缘内容的不透明程度(或淡入淡出的“强度”程度)
    3. 滚动到边缘附近时淡入淡出效果消失的速度

基本思想是控制不透明度遮盖 ScrollViewer 模板中的可滚动内容。不透明蒙版包含一个透明的外边框和一个应用了 BlurEffect 的内部不透明边框,以获得边缘的渐变效果。然后,当您滚动时,可以操纵内边框的边距,以控制沿特定边缘出现的淡入淡出的“深度”。

此解决方案对 ScrollViewer 进行子类化,并要求您指定对 ScrollViewer 模板的更改。 ScrollContentPresenter 需要包装在名为“PART_ScrollContentPresenterContainer”的边框内。

FadingScrollViewer 类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;

namespace ScrollViewerTest
{
  public class FadingScrollViewer : ScrollViewer
  {
    private const string PART_SCROLL_PRESENTER_CONTAINER_NAME = "PART_ScrollContentPresenterContainer";

    public double FadedEdgeThickness { get; set; }
    public double FadedEdgeFalloffSpeed { get; set; }
    public double FadedEdgeOpacity { get; set; }

    private BlurEffect InnerFadedBorderEffect { get; set; }
    private Border InnerFadedBorder { get; set; }
    private Border OuterFadedBorder { get; set; }



    public FadingScrollViewer()
    {
      this.FadedEdgeThickness = 20;
      this.FadedEdgeFalloffSpeed = 4.0;
      this.FadedEdgeOpacity = 0.0;

      this.ScrollChanged += FadingScrollViewer_ScrollChanged;
      this.SizeChanged += FadingScrollViewer_SizeChanged;
    }



    private void FadingScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
      if (this.InnerFadedBorder == null)
        return;

      var topOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.VerticalOffset); ;
      var bottomOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.ScrollableHeight - this.VerticalOffset);
      var leftOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.HorizontalOffset);
      var rightOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.ScrollableWidth - this.HorizontalOffset);

      this.InnerFadedBorder.Margin = new Thickness(leftOffset, topOffset, rightOffset, bottomOffset);
    }



    private double CalculateNewMarginBasedOnOffsetFromEdge(double edgeOffset)
    {
      var innerFadedBorderBaseMarginThickness = this.FadedEdgeThickness / 2.0;
      var calculatedOffset = (innerFadedBorderBaseMarginThickness) - (1.5 * (this.FadedEdgeThickness - (edgeOffset / this.FadedEdgeFalloffSpeed)));

      return Math.Min(innerFadedBorderBaseMarginThickness, calculatedOffset);
    }



    private void FadingScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
      if (this.OuterFadedBorder == null || this.InnerFadedBorder == null || this.InnerFadedBorderEffect == null)
        return;

      this.OuterFadedBorder.Width = e.NewSize.Width;
      this.OuterFadedBorder.Height = e.NewSize.Height;

      double innerFadedBorderBaseMarginThickness = this.FadedEdgeThickness / 2.0;
      this.InnerFadedBorder.Margin = new Thickness(innerFadedBorderBaseMarginThickness);
      this.InnerFadedBorderEffect.Radius = this.FadedEdgeThickness;
    }



    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      BuildInnerFadedBorderEffectForOpacityMask();
      BuildInnerFadedBorderForOpacityMask();
      BuildOuterFadedBorderForOpacityMask();
      SetOpacityMaskOfScrollContainer();
    }



    private void BuildInnerFadedBorderEffectForOpacityMask()
    {
      this.InnerFadedBorderEffect = new BlurEffect()
        {
          RenderingBias = RenderingBias.Performance,
        };
    }



    private void BuildInnerFadedBorderForOpacityMask()
    {
      this.InnerFadedBorder = new Border()
        {
          Background = Brushes.Black,
          HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
          VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
          Effect = this.InnerFadedBorderEffect,
        };
    }



    private void BuildOuterFadedBorderForOpacityMask()
    {
      byte fadedEdgeByteOpacity = (byte)(this.FadedEdgeOpacity * 255);

      this.OuterFadedBorder = new Border()
        {
          Background = new SolidColorBrush(Color.FromArgb(fadedEdgeByteOpacity, 0, 0, 0)),
          ClipToBounds = true,
          Child = this.InnerFadedBorder,
        };
    }



    private void SetOpacityMaskOfScrollContainer()
    {
      var opacityMaskBrush = new VisualBrush()
        {
          Visual = this.OuterFadedBorder
        };

      var scrollContentPresentationContainer = this.Template.FindName(PART_SCROLL_PRESENTER_CONTAINER_NAME, this) as UIElement;

      if (scrollContentPresentationContainer == null)
        return;

      scrollContentPresentationContainer.OpacityMask = opacityMaskBrush;
    }
  }
}

下面是使用该控件的 XAML,需要对默认 ScrollViewer 模板进行最少的更改(它是 ScrollContentPresenter 周围的边框)。

<local:FadingScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Margin="10" FadedEdgeThickness="20" FadedEdgeOpacity="0" FadedEdgeFalloffSpeed="4">
  <local:FadingScrollViewer.Template>
    <ControlTemplate TargetType="{x:Type ScrollViewer}">
      <Grid x:Name="Grid" Background="{TemplateBinding Background}">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="*"/>
          <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Border x:Name="PART_ScrollContentPresenterContainer">
          <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
        </Border>

        <ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
        <ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
      </Grid>
    </ControlTemplate>
  </local:FadingScrollViewer.Template>


  <!-- Your content here -->

</local:FadingScrollViewer>

请注意 FadedScrollViewer 上的这些附加属性:FadedEdgeThickness、FadedEdgeOpacity 和 FadedEdgeFalloffSpeed

  • FadedEdgeThickness:您希望淡入淡出的厚度(以像素为单位)
  • FadedEdgeOpacity:您希望淡入淡出最外边缘的不透明程度。 0 = 边缘完全透明,1 = 边缘完全不褪色
  • FadedEdgeFalloffSpeed:控制当您靠近褪色边缘时消失的速度。值越高,淡出越慢。

I know this is an older question, but I came across this question because I was trying to do something similar; so I figured I'd post my solution for the next person. Any feedback on my solution is appreciated.

In our application, most of our ScrollViewer controls sit on top of non-scrolling textures, so we wanted the scrollable content to fade into that background at the edges of the ScrollViewer, but only when there was more content in that direction. In addition, we have at least one 2-axis scrollable area where the user can pan around in every direction. It had to work in that scenario as well. Our application also doesn't really have scrollbars, but I've left that out of the solution I present here (it doesn't impact the solution).

Features of this solution:

  1. Fades the edges of the content within the ScrollViewer if there is content along that side of the ScrollViewer that is not currently visible.

  2. Decreases the intensity of the fade effect as you scroll closer to the edge of the content.

  3. Gives some control over how the faded edges look. Specifically, you can control:

    1. Thickness of the faded edge
    2. How opaque the content is at the outermost edge (or how "intense" the fade is)
    3. How fast the fade effect disappears as you scroll near the edge

The basic idea is to control an opacity mask over the scrollable content in the ScrollViewer's template. The opacity mask contains a transparent outer border, and an inner opaque border with the BlurEffect applied to it to get the gradient effect at the edges. Then, the margin of the inner border is manipulated as you scroll around to control how "deep" the fade appears along a particular edge.

This solution subclasses the ScrollViewer, and requires you to specify a change to the ScrollViewer's template. The ScrollContentPresenter needs to be wrapped inside a Border named "PART_ScrollContentPresenterContainer".

The FadingScrollViewer class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;

namespace ScrollViewerTest
{
  public class FadingScrollViewer : ScrollViewer
  {
    private const string PART_SCROLL_PRESENTER_CONTAINER_NAME = "PART_ScrollContentPresenterContainer";

    public double FadedEdgeThickness { get; set; }
    public double FadedEdgeFalloffSpeed { get; set; }
    public double FadedEdgeOpacity { get; set; }

    private BlurEffect InnerFadedBorderEffect { get; set; }
    private Border InnerFadedBorder { get; set; }
    private Border OuterFadedBorder { get; set; }



    public FadingScrollViewer()
    {
      this.FadedEdgeThickness = 20;
      this.FadedEdgeFalloffSpeed = 4.0;
      this.FadedEdgeOpacity = 0.0;

      this.ScrollChanged += FadingScrollViewer_ScrollChanged;
      this.SizeChanged += FadingScrollViewer_SizeChanged;
    }



    private void FadingScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
      if (this.InnerFadedBorder == null)
        return;

      var topOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.VerticalOffset); ;
      var bottomOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.ScrollableHeight - this.VerticalOffset);
      var leftOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.HorizontalOffset);
      var rightOffset = CalculateNewMarginBasedOnOffsetFromEdge(this.ScrollableWidth - this.HorizontalOffset);

      this.InnerFadedBorder.Margin = new Thickness(leftOffset, topOffset, rightOffset, bottomOffset);
    }



    private double CalculateNewMarginBasedOnOffsetFromEdge(double edgeOffset)
    {
      var innerFadedBorderBaseMarginThickness = this.FadedEdgeThickness / 2.0;
      var calculatedOffset = (innerFadedBorderBaseMarginThickness) - (1.5 * (this.FadedEdgeThickness - (edgeOffset / this.FadedEdgeFalloffSpeed)));

      return Math.Min(innerFadedBorderBaseMarginThickness, calculatedOffset);
    }



    private void FadingScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
      if (this.OuterFadedBorder == null || this.InnerFadedBorder == null || this.InnerFadedBorderEffect == null)
        return;

      this.OuterFadedBorder.Width = e.NewSize.Width;
      this.OuterFadedBorder.Height = e.NewSize.Height;

      double innerFadedBorderBaseMarginThickness = this.FadedEdgeThickness / 2.0;
      this.InnerFadedBorder.Margin = new Thickness(innerFadedBorderBaseMarginThickness);
      this.InnerFadedBorderEffect.Radius = this.FadedEdgeThickness;
    }



    public override void OnApplyTemplate()
    {
      base.OnApplyTemplate();

      BuildInnerFadedBorderEffectForOpacityMask();
      BuildInnerFadedBorderForOpacityMask();
      BuildOuterFadedBorderForOpacityMask();
      SetOpacityMaskOfScrollContainer();
    }



    private void BuildInnerFadedBorderEffectForOpacityMask()
    {
      this.InnerFadedBorderEffect = new BlurEffect()
        {
          RenderingBias = RenderingBias.Performance,
        };
    }



    private void BuildInnerFadedBorderForOpacityMask()
    {
      this.InnerFadedBorder = new Border()
        {
          Background = Brushes.Black,
          HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
          VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
          Effect = this.InnerFadedBorderEffect,
        };
    }



    private void BuildOuterFadedBorderForOpacityMask()
    {
      byte fadedEdgeByteOpacity = (byte)(this.FadedEdgeOpacity * 255);

      this.OuterFadedBorder = new Border()
        {
          Background = new SolidColorBrush(Color.FromArgb(fadedEdgeByteOpacity, 0, 0, 0)),
          ClipToBounds = true,
          Child = this.InnerFadedBorder,
        };
    }



    private void SetOpacityMaskOfScrollContainer()
    {
      var opacityMaskBrush = new VisualBrush()
        {
          Visual = this.OuterFadedBorder
        };

      var scrollContentPresentationContainer = this.Template.FindName(PART_SCROLL_PRESENTER_CONTAINER_NAME, this) as UIElement;

      if (scrollContentPresentationContainer == null)
        return;

      scrollContentPresentationContainer.OpacityMask = opacityMaskBrush;
    }
  }
}

Here's the XAML to use the control, with the most minimal changes to the default ScrollViewer template required (it's the Border around the ScrollContentPresenter).

<local:FadingScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Margin="10" FadedEdgeThickness="20" FadedEdgeOpacity="0" FadedEdgeFalloffSpeed="4">
  <local:FadingScrollViewer.Template>
    <ControlTemplate TargetType="{x:Type ScrollViewer}">
      <Grid x:Name="Grid" Background="{TemplateBinding Background}">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="*"/>
          <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Border x:Name="PART_ScrollContentPresenterContainer">
          <ScrollContentPresenter x:Name="PART_ScrollContentPresenter" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Grid.Column="0" Margin="{TemplateBinding Padding}" Grid.Row="0"/>
        </Border>

        <ScrollBar x:Name="PART_VerticalScrollBar" AutomationProperties.AutomationId="VerticalScrollBar" Cursor="Arrow" Grid.Column="1" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Grid.Row="0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Value="{Binding VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportHeight}"/>
        <ScrollBar x:Name="PART_HorizontalScrollBar" AutomationProperties.AutomationId="HorizontalScrollBar" Cursor="Arrow" Grid.Column="0" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Orientation="Horizontal" Grid.Row="1" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Value="{Binding HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" ViewportSize="{TemplateBinding ViewportWidth}"/>
      </Grid>
    </ControlTemplate>
  </local:FadingScrollViewer.Template>


  <!-- Your content here -->

</local:FadingScrollViewer>

Note these additional properties on the FadedScrollViewer: FadedEdgeThickness, FadedEdgeOpacity, and FadedEdgeFalloffSpeed

  • FadedEdgeThickness: How thick do you want the fade to be (in pixels)
  • FadedEdgeOpacity: How opaque do you want the outer-most edge of the fade to be. 0 = completely transparent at the edge, 1 = do not fade at all at the edge
  • FadedEdgeFalloffSpeed: Controls how fast the faded edge appears to disappear as you get close to it. The higher the value, the slower the fade out.
想挽留 2024-08-22 04:53:06

我更改了 Grandpapy 的代码,使其可以在不使用自定义控件的情况下工作。
像这样,您只需添加附加属性即可将所有 ScrollViewers“升级”为淡入淡出滚动查看器。
您还需要为滚动查看器指定一种样式,无论如何我都这样做了。它必须定义名称 PART_ScrollContentPresenterContainer。您无需修改​​即可使用 Grandpapys 风格。

该类的代码(称为ScrollViewErxensions)是:

/// <summary>
/// Attached property that makes the scrollbar fade on it's edges
/// 
/// derived class at from http://stackoverflow.com/questions/1901709/scrollviewer-edge-blur-effect-opacitymask-not-working-properly
/// </summary>
public class ScrollViewerExtensions : DependencyObject
{
    /// <summary>
    /// MAIN property: this activates the whole fading effect
    /// </summary>
    public static readonly DependencyProperty FadedEdgeThicknessProperty =
        DependencyProperty.RegisterAttached("FadedEdgeThickness", typeof(double), typeof(ScrollViewerExtensions), new PropertyMetadata(20.0d, OnFadedEdgeThicknessChanged));

    public static void SetFadedEdgeThickness(ScrollViewer s, double value)
    {
        s.SetValue(FadedEdgeThicknessProperty, value);
    }

    public static double GetFadedEdgeThickness(ScrollViewer s, double value)
    {
        return (double)s.GetValue(FadedEdgeThicknessProperty);
    }

    /// <summary>
    /// optional property. changes how fast the fade appears/diappears when scrolling near an edge
    /// </summary>
    public static readonly DependencyProperty FadedEdgeFalloffSpeedProperty =
        DependencyProperty.RegisterAttached("FadedEdgeFalloffSpeed", typeof(double), typeof(ScrollViewerExtensions), new PropertyMetadata(4.0d, OnFadedEdgeFalloffSpeedChanged));

    public static void SetFadedEdgeFalloffSpeed(ScrollViewer s, double value)
    {
        s.SetValue(FadedEdgeFalloffSpeedProperty, value);
    }

    public static double GetFadedEdgeFalloffSpeed(ScrollViewer s, double value)
    {
        return (double)s.GetValue(FadedEdgeFalloffSpeedProperty);
    }

    /// <summary>
    /// optional property. changes how opaque the outermost edge should be
    /// </summary>
    public static readonly DependencyProperty FadedEdgeOpacityProperty =
        DependencyProperty.RegisterAttached("FadedEdgeOpacity", typeof(double), typeof(ScrollViewerExtensions), new PropertyMetadata(0.0d, OnFadedEdgeOpacityChanged));

    public static void SetFadedEdgeOpacity(ScrollViewer s, double value)
    {
        s.SetValue(FadedEdgeOpacityProperty, value);
    }

    public static double GetFadedEdgeOpacity(ScrollViewer s, double value)
    {
        return (double)s.GetValue(FadedEdgeOpacityProperty);
    }




    private const string PART_SCROLL_PRESENTER_CONTAINER_NAME = "PART_ScrollContentPresenterContainer";

    private static Dictionary<ScrollViewer, FadeSettings> Settings = new Dictionary<ScrollViewer, FadeSettings>();



    /// <summary>
    /// this is kindof the constructor for the properties. If you don't specify this, nothing will fade!
    /// </summary>
    /// <param name="d"></param>
    /// <param name="e"></param>
    public static void OnFadedEdgeThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;

        if (scrollViewer == null)
            return;

        double edgeThickness = (double)e.NewValue;

        scrollViewer.ScrollChanged += FadingScrollViewer_ScrollChanged;
        scrollViewer.SizeChanged += FadingScrollViewer_SizeChanged;

        if (!Settings.ContainsKey(scrollViewer))
            Settings.Add(scrollViewer, new FadeSettings());

        Settings[scrollViewer].FadedEdgeThickness = edgeThickness;
    }


    public static void OnFadedEdgeFalloffSpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;

        if (scrollViewer == null)
            return;

        double edgeFalloffSpeed = (double)e.NewValue;

        if (!Settings.ContainsKey(scrollViewer))
            Settings.Add(scrollViewer, new FadeSettings());

        Settings[scrollViewer].FadedEdgeFalloffSpeed = edgeFalloffSpeed;
    }


    public static void OnFadedEdgeOpacityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;

        if (scrollViewer == null)
            return;

        double edgeOpacity = (double)e.NewValue;

        if (!Settings.ContainsKey(scrollViewer))
            Settings.Add(scrollViewer, new FadeSettings());

        Settings[scrollViewer].FadedEdgeOpacity = edgeOpacity;
    }


    private static void FadingScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        ScrollViewer scrollViewer = sender as ScrollViewer;
        FadeSettings settings = Settings[scrollViewer];

        if (settings.InnerFadedBorder == null)
            return;

        var topOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.VerticalOffset); ;
        var bottomOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.ScrollableHeight - scrollViewer.VerticalOffset);
        var leftOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.HorizontalOffset);
        var rightOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.ScrollableWidth - scrollViewer.HorizontalOffset);

        settings.InnerFadedBorder.Margin = new Thickness(leftOffset, topOffset, rightOffset, bottomOffset);
    }

    private static void FadingScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        ScrollViewer scrollViewer = sender as ScrollViewer;
        FadeSettings settings = Settings[scrollViewer];

        if (!settings.Initialized) // abuse the SizeChanged event to call the OnApplyTemplate method. We can't override it, so we need something, that fires after it would normally be called. see http://msdn.microsoft.com/en-us/library/dd351483%28v=vs.95%29.aspx
        {
            OnApplyTemplate(scrollViewer);
            settings.Initialized = true;
        }

        if (settings.OuterFadedBorder == null || settings.InnerFadedBorder == null || settings.InnerFadedBorderEffect == null)
            return;

        settings.OuterFadedBorder.Width = e.NewSize.Width;
        settings.OuterFadedBorder.Height = e.NewSize.Height;

        double innerFadedBorderBaseMarginThickness = settings.FadedEdgeThickness / 2.0;
        settings.InnerFadedBorder.Margin = new Thickness(innerFadedBorderBaseMarginThickness);
        settings.InnerFadedBorderEffect.Radius = settings.FadedEdgeThickness;
    }

    private static double CalculateNewMarginBasedOnOffsetFromEdge(ScrollViewer scrollViewer, double edgeOffset)
    {
        FadeSettings settings = Settings[scrollViewer];

        var innerFadedBorderBaseMarginThickness = settings.FadedEdgeThickness / 2.0;
        //var calculatedOffset = (innerFadedBorderBaseMarginThickness) - (1.0 * (this.FadedEdgeThickness - (edgeOffset / this.FadedEdgeFalloffSpeed)));

        double calculatedOffset;
        if (edgeOffset == 0)
            calculatedOffset = -innerFadedBorderBaseMarginThickness;
        else
            calculatedOffset = (edgeOffset * settings.FadedEdgeFalloffSpeed) - innerFadedBorderBaseMarginThickness;

        return Math.Min(innerFadedBorderBaseMarginThickness, calculatedOffset);
    }

    public static void OnApplyTemplate(ScrollViewer scrollViewer)
    {
        BuildInnerFadedBorderEffectForOpacityMask(scrollViewer);
        BuildInnerFadedBorderForOpacityMask(scrollViewer);
        BuildOuterFadedBorderForOpacityMask(scrollViewer);
        SetOpacityMaskOfScrollContainer(scrollViewer);
    }

    private static void BuildInnerFadedBorderEffectForOpacityMask(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        settings.InnerFadedBorderEffect = new BlurEffect()
        {
            RenderingBias = RenderingBias.Performance,
        };
    }

    private static void BuildInnerFadedBorderForOpacityMask(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        settings.InnerFadedBorder = new Border()
        {
            Background = Brushes.Black,
            HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
            VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
            Effect = settings.InnerFadedBorderEffect,
        };
    }

    private static void BuildOuterFadedBorderForOpacityMask(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        byte fadedEdgeByteOpacity = (byte)(settings.FadedEdgeOpacity * 255);

        settings.OuterFadedBorder = new Border()
        {
            Background = new SolidColorBrush(Color.FromArgb(fadedEdgeByteOpacity, 0, 0, 0)),
            ClipToBounds = true,
            Child = settings.InnerFadedBorder,
        };
    }

    private static void SetOpacityMaskOfScrollContainer(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        var opacityMaskBrush = new VisualBrush()
        {
            Visual = settings.OuterFadedBorder
        };

        var scrollContentPresentationContainer = scrollViewer.Template.FindName(PART_SCROLL_PRESENTER_CONTAINER_NAME, scrollViewer) as UIElement;

        if (scrollContentPresentationContainer == null)
            return;

        scrollContentPresentationContainer.OpacityMask = opacityMaskBrush;

        // test
        /*var container = scrollContentPresentationContainer as Border;
        var scroller = container.Child as UIElement;
        container.Child = null;

        Grid g = new Grid();
        container.Child = g;

        g.Children.Add(scroller);
        this.OuterFadedBorder.IsHitTestVisible = false;
        g.Children.Add(this.OuterFadedBorder);*/
    }


    protected class FadeSettings
    {
        public BlurEffect InnerFadedBorderEffect { get; set; }
        public Border InnerFadedBorder { get; set; }
        public Border OuterFadedBorder { get; set; }

        public double FadedEdgeThickness { get; set; }
        public double FadedEdgeFalloffSpeed { get; set; }
        public double FadedEdgeOpacity { get; set; }

        public bool Initialized { get; set; }

        public FadeSettings()
        {
            FadedEdgeThickness = 20.0d;
            FadedEdgeFalloffSpeed = 4.0d;
            FadedEdgeOpacity = 0.0d;
        }
    }
}

您可以在代码中设置附件的属性:

scroller.SetValue(ScrollViewerExtensions.FadedEdgeThicknessProperty, 70.0d);

或者您直接在XAML中定义它:

<ScrollViewer Name="scrollViewer" controls:ScrollViewerExtensions.FadedEdgeThickness="40">
    some content
</ScrollViewer>

希望大家可以对此做些事情!

I changed Grandpappy's code to work without using a custom control.
Like this you can "upgrade" all your ScrollViewers to fading scrollviewers just by adding an attached Property to them.
You also need to specify a style for the scrollviewer, which i did anyway. It has to define the name PART_ScrollContentPresenterContainer. You can use Grandpappys Style without modifications.

The Code for the class (called it ScrollViewerExtensions) is:

/// <summary>
/// Attached property that makes the scrollbar fade on it's edges
/// 
/// derived class at from http://stackoverflow.com/questions/1901709/scrollviewer-edge-blur-effect-opacitymask-not-working-properly
/// </summary>
public class ScrollViewerExtensions : DependencyObject
{
    /// <summary>
    /// MAIN property: this activates the whole fading effect
    /// </summary>
    public static readonly DependencyProperty FadedEdgeThicknessProperty =
        DependencyProperty.RegisterAttached("FadedEdgeThickness", typeof(double), typeof(ScrollViewerExtensions), new PropertyMetadata(20.0d, OnFadedEdgeThicknessChanged));

    public static void SetFadedEdgeThickness(ScrollViewer s, double value)
    {
        s.SetValue(FadedEdgeThicknessProperty, value);
    }

    public static double GetFadedEdgeThickness(ScrollViewer s, double value)
    {
        return (double)s.GetValue(FadedEdgeThicknessProperty);
    }

    /// <summary>
    /// optional property. changes how fast the fade appears/diappears when scrolling near an edge
    /// </summary>
    public static readonly DependencyProperty FadedEdgeFalloffSpeedProperty =
        DependencyProperty.RegisterAttached("FadedEdgeFalloffSpeed", typeof(double), typeof(ScrollViewerExtensions), new PropertyMetadata(4.0d, OnFadedEdgeFalloffSpeedChanged));

    public static void SetFadedEdgeFalloffSpeed(ScrollViewer s, double value)
    {
        s.SetValue(FadedEdgeFalloffSpeedProperty, value);
    }

    public static double GetFadedEdgeFalloffSpeed(ScrollViewer s, double value)
    {
        return (double)s.GetValue(FadedEdgeFalloffSpeedProperty);
    }

    /// <summary>
    /// optional property. changes how opaque the outermost edge should be
    /// </summary>
    public static readonly DependencyProperty FadedEdgeOpacityProperty =
        DependencyProperty.RegisterAttached("FadedEdgeOpacity", typeof(double), typeof(ScrollViewerExtensions), new PropertyMetadata(0.0d, OnFadedEdgeOpacityChanged));

    public static void SetFadedEdgeOpacity(ScrollViewer s, double value)
    {
        s.SetValue(FadedEdgeOpacityProperty, value);
    }

    public static double GetFadedEdgeOpacity(ScrollViewer s, double value)
    {
        return (double)s.GetValue(FadedEdgeOpacityProperty);
    }




    private const string PART_SCROLL_PRESENTER_CONTAINER_NAME = "PART_ScrollContentPresenterContainer";

    private static Dictionary<ScrollViewer, FadeSettings> Settings = new Dictionary<ScrollViewer, FadeSettings>();



    /// <summary>
    /// this is kindof the constructor for the properties. If you don't specify this, nothing will fade!
    /// </summary>
    /// <param name="d"></param>
    /// <param name="e"></param>
    public static void OnFadedEdgeThicknessChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;

        if (scrollViewer == null)
            return;

        double edgeThickness = (double)e.NewValue;

        scrollViewer.ScrollChanged += FadingScrollViewer_ScrollChanged;
        scrollViewer.SizeChanged += FadingScrollViewer_SizeChanged;

        if (!Settings.ContainsKey(scrollViewer))
            Settings.Add(scrollViewer, new FadeSettings());

        Settings[scrollViewer].FadedEdgeThickness = edgeThickness;
    }


    public static void OnFadedEdgeFalloffSpeedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;

        if (scrollViewer == null)
            return;

        double edgeFalloffSpeed = (double)e.NewValue;

        if (!Settings.ContainsKey(scrollViewer))
            Settings.Add(scrollViewer, new FadeSettings());

        Settings[scrollViewer].FadedEdgeFalloffSpeed = edgeFalloffSpeed;
    }


    public static void OnFadedEdgeOpacityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var scrollViewer = d as ScrollViewer;

        if (scrollViewer == null)
            return;

        double edgeOpacity = (double)e.NewValue;

        if (!Settings.ContainsKey(scrollViewer))
            Settings.Add(scrollViewer, new FadeSettings());

        Settings[scrollViewer].FadedEdgeOpacity = edgeOpacity;
    }


    private static void FadingScrollViewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        ScrollViewer scrollViewer = sender as ScrollViewer;
        FadeSettings settings = Settings[scrollViewer];

        if (settings.InnerFadedBorder == null)
            return;

        var topOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.VerticalOffset); ;
        var bottomOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.ScrollableHeight - scrollViewer.VerticalOffset);
        var leftOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.HorizontalOffset);
        var rightOffset = CalculateNewMarginBasedOnOffsetFromEdge(scrollViewer, scrollViewer.ScrollableWidth - scrollViewer.HorizontalOffset);

        settings.InnerFadedBorder.Margin = new Thickness(leftOffset, topOffset, rightOffset, bottomOffset);
    }

    private static void FadingScrollViewer_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        ScrollViewer scrollViewer = sender as ScrollViewer;
        FadeSettings settings = Settings[scrollViewer];

        if (!settings.Initialized) // abuse the SizeChanged event to call the OnApplyTemplate method. We can't override it, so we need something, that fires after it would normally be called. see http://msdn.microsoft.com/en-us/library/dd351483%28v=vs.95%29.aspx
        {
            OnApplyTemplate(scrollViewer);
            settings.Initialized = true;
        }

        if (settings.OuterFadedBorder == null || settings.InnerFadedBorder == null || settings.InnerFadedBorderEffect == null)
            return;

        settings.OuterFadedBorder.Width = e.NewSize.Width;
        settings.OuterFadedBorder.Height = e.NewSize.Height;

        double innerFadedBorderBaseMarginThickness = settings.FadedEdgeThickness / 2.0;
        settings.InnerFadedBorder.Margin = new Thickness(innerFadedBorderBaseMarginThickness);
        settings.InnerFadedBorderEffect.Radius = settings.FadedEdgeThickness;
    }

    private static double CalculateNewMarginBasedOnOffsetFromEdge(ScrollViewer scrollViewer, double edgeOffset)
    {
        FadeSettings settings = Settings[scrollViewer];

        var innerFadedBorderBaseMarginThickness = settings.FadedEdgeThickness / 2.0;
        //var calculatedOffset = (innerFadedBorderBaseMarginThickness) - (1.0 * (this.FadedEdgeThickness - (edgeOffset / this.FadedEdgeFalloffSpeed)));

        double calculatedOffset;
        if (edgeOffset == 0)
            calculatedOffset = -innerFadedBorderBaseMarginThickness;
        else
            calculatedOffset = (edgeOffset * settings.FadedEdgeFalloffSpeed) - innerFadedBorderBaseMarginThickness;

        return Math.Min(innerFadedBorderBaseMarginThickness, calculatedOffset);
    }

    public static void OnApplyTemplate(ScrollViewer scrollViewer)
    {
        BuildInnerFadedBorderEffectForOpacityMask(scrollViewer);
        BuildInnerFadedBorderForOpacityMask(scrollViewer);
        BuildOuterFadedBorderForOpacityMask(scrollViewer);
        SetOpacityMaskOfScrollContainer(scrollViewer);
    }

    private static void BuildInnerFadedBorderEffectForOpacityMask(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        settings.InnerFadedBorderEffect = new BlurEffect()
        {
            RenderingBias = RenderingBias.Performance,
        };
    }

    private static void BuildInnerFadedBorderForOpacityMask(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        settings.InnerFadedBorder = new Border()
        {
            Background = Brushes.Black,
            HorizontalAlignment = System.Windows.HorizontalAlignment.Stretch,
            VerticalAlignment = System.Windows.VerticalAlignment.Stretch,
            Effect = settings.InnerFadedBorderEffect,
        };
    }

    private static void BuildOuterFadedBorderForOpacityMask(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        byte fadedEdgeByteOpacity = (byte)(settings.FadedEdgeOpacity * 255);

        settings.OuterFadedBorder = new Border()
        {
            Background = new SolidColorBrush(Color.FromArgb(fadedEdgeByteOpacity, 0, 0, 0)),
            ClipToBounds = true,
            Child = settings.InnerFadedBorder,
        };
    }

    private static void SetOpacityMaskOfScrollContainer(ScrollViewer scrollViewer)
    {
        FadeSettings settings = Settings[scrollViewer];

        var opacityMaskBrush = new VisualBrush()
        {
            Visual = settings.OuterFadedBorder
        };

        var scrollContentPresentationContainer = scrollViewer.Template.FindName(PART_SCROLL_PRESENTER_CONTAINER_NAME, scrollViewer) as UIElement;

        if (scrollContentPresentationContainer == null)
            return;

        scrollContentPresentationContainer.OpacityMask = opacityMaskBrush;

        // test
        /*var container = scrollContentPresentationContainer as Border;
        var scroller = container.Child as UIElement;
        container.Child = null;

        Grid g = new Grid();
        container.Child = g;

        g.Children.Add(scroller);
        this.OuterFadedBorder.IsHitTestVisible = false;
        g.Children.Add(this.OuterFadedBorder);*/
    }


    protected class FadeSettings
    {
        public BlurEffect InnerFadedBorderEffect { get; set; }
        public Border InnerFadedBorder { get; set; }
        public Border OuterFadedBorder { get; set; }

        public double FadedEdgeThickness { get; set; }
        public double FadedEdgeFalloffSpeed { get; set; }
        public double FadedEdgeOpacity { get; set; }

        public bool Initialized { get; set; }

        public FadeSettings()
        {
            FadedEdgeThickness = 20.0d;
            FadedEdgeFalloffSpeed = 4.0d;
            FadedEdgeOpacity = 0.0d;
        }
    }
}

You can either set the attached property in code:

scroller.SetValue(ScrollViewerExtensions.FadedEdgeThicknessProperty, 70.0d);

or you define it directly in XAML:

<ScrollViewer Name="scrollViewer" controls:ScrollViewerExtensions.FadedEdgeThickness="40">
    some content
</ScrollViewer>

Hope you guys can do something with it!

风透绣罗衣 2024-08-22 04:53:06

安托万是对的,只是他把它搞反了。您需要将文本块的背景颜色设置为白色或透明或任何您想要的颜色。

 <Grid Background="LightGray">
    <ScrollViewer BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"
                       HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" >
        <ScrollViewer.OpacityMask>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientStop Color="Transparent" Offset="0" />
                <GradientStop Color="Black" Offset="0.1" />
                <GradientStop Color="Black" Offset="0.9" />
                <GradientStop Color="Transparent" Offset="1" />
            </LinearGradientBrush>
        </ScrollViewer.OpacityMask>
        <TextBlock Margin="0,10"  TextWrapping="Wrap" Width="200" Background="White">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
        </TextBlock>
    </ScrollViewer>
</Grid>

如果删除 TextBlock 背景,您会注意到文本块中的文本将淡出,但定义背景后,它仅将其应用于滚动查看器。

Antoine is right except he has it backward. You need to set the background color on the textblock to white or transparent or whatever you are wanting.

 <Grid Background="LightGray">
    <ScrollViewer BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"
                       HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden" >
        <ScrollViewer.OpacityMask>
            <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                <GradientStop Color="Transparent" Offset="0" />
                <GradientStop Color="Black" Offset="0.1" />
                <GradientStop Color="Black" Offset="0.9" />
                <GradientStop Color="Transparent" Offset="1" />
            </LinearGradientBrush>
        </ScrollViewer.OpacityMask>
        <TextBlock Margin="0,10"  TextWrapping="Wrap" Width="200" Background="White">
    Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
        </TextBlock>
    </ScrollViewer>
</Grid>

If you remove the TextBlock background you will notice the text in the textblock will fade out but with the background defined it is only applying it to the scrollviewer.

硬不硬你别怂 2024-08-22 04:53:06

您可以在同一网格内的 ScrollViewer 顶部添加一个具有透明渐变的控件,并将其“IsHitTestVisible”设置为 false 以实现此效果。下面是在 ScrollViewer 顶部使用 Canvas 控件的示例的修改版本:

<Grid Width="200" Height="130">
            <ScrollViewer BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"
                           HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden"  Background="LightBlue">
                <TextBlock Margin="10,30,10,30" TextWrapping="Wrap" OpacityMask="Black" VerticalAlignment="Center">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
                </TextBlock>
            </ScrollViewer>
            <Canvas Width="200" Height="130" Focusable="False" IsEnabled="False" IsHitTestVisible="False">
                <Canvas.Background>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                        <GradientStop Color="#FFFFFFFF" Offset="0" />
                        <GradientStop Color="#00FFFFFF" Offset="0.1" />
                        <GradientStop Color="#00FFFFFF" Offset="0.9" />
                        <GradientStop Color="#FFFFFFFF" Offset="1" />
                    </LinearGradientBrush>
                </Canvas.Background>
            </Canvas>
        </Grid>

我向 ScrollViewer 添加了背景颜色,并向 TextBlock 添加了较大的上边距,以便可以轻松确认所需的效果。输出如下:
替代文本

You could add a control with a transparent gradient on top of the ScrollViewer within the same Grid and set its 'IsHitTestVisible' to false to achieve this effect. Here is a modified version of your example using a Canvas control on top of the ScrollViewer:

<Grid Width="200" Height="130">
            <ScrollViewer BorderThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Padding="2"
                           HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Hidden"  Background="LightBlue">
                <TextBlock Margin="10,30,10,30" TextWrapping="Wrap" OpacityMask="Black" VerticalAlignment="Center">
                Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum
                </TextBlock>
            </ScrollViewer>
            <Canvas Width="200" Height="130" Focusable="False" IsEnabled="False" IsHitTestVisible="False">
                <Canvas.Background>
                    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
                        <GradientStop Color="#FFFFFFFF" Offset="0" />
                        <GradientStop Color="#00FFFFFF" Offset="0.1" />
                        <GradientStop Color="#00FFFFFF" Offset="0.9" />
                        <GradientStop Color="#FFFFFFFF" Offset="1" />
                    </LinearGradientBrush>
                </Canvas.Background>
            </Canvas>
        </Grid>

I added a background color to the ScrollViewer and a large top margin to the TextBlock so that it would be easy to confirm the desired effect. Here is what the output looked like:
alt text

梦冥 2024-08-22 04:53:06

我今天遇到了同样的问题,解决方案实际上非常简单:将 ScrollViewer.Background 属性设置为除 null 以外的任何值(在您的情况下您需要透明),并且它有效。

我在这里发布答案,因为这是我发现的关于这个问题的唯一问题。

I faced the same problem today, and the solution is actually very simple: set the ScrollViewer.Background property to anything but null (in your case you'd want Transparent), and it works.

I'm posting the answer here as it's the only question I found regarding this problem.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文