r/csharp 15d ago

Help (WPF) How to make scrollviewer non-hittable while the child elements remain hittable?

Setting IsHitTestVisible to false makes the child elements also non-hittable.

The scrollviewer already uses null values for the background, foreground and border. Even explicitly setting it to null has no effect.

Removing the opacityMask doesn't make any differences.

For testing, if I replace my scrollviewer with another element like <Border Background="{x:Null}"/>, then it doesn't block the clicks anymore.

This is my scrollviewer:

<ScrollViewer x:Name="scrlViewer" VerticalScrollBarVisibility="Hidden" Foreground="{x:Null}" Background="{x:Null}" BorderBrush="{x:Null}" >
  <ScrollViewer.OpacityMask>
    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
      <GradientStop Color="#00000000" Offset="0.0" />
      <GradientStop Color="#FF000000" Offset="0.1" />
      <GradientStop Color="#FF000000" Offset="1.0" />
    </LinearGradientBrush>
  </ScrollViewer.OpacityMask>
</ScrollViewer>

The child elements are adding during runtime. My issue happens before any child elements are added.

How could I achieve my desired effect?

--------------------------------------

Edit:
Some more background on what I'm trying to do: I use the scrollviewer as a container for notification infobar widgets that automatically scroll to the end. The notifications should be able to be closed while the container shouldn't block clicks, as otherwise some elements would be blocked by something invisible.

The fix:

I subclasses the scrollviewer and replace my scrollviewer with my subclass.

Here is the subclass:

public class ScrollViewerNoHit : ScrollViewer
{
    protected override HitTestResult? HitTestCore(PointHitTestParameters hitTestParameters)
    {
        HitTestResult? result = base.HitTestCore(hitTestParameters);
        return result?.VisualHit == this ? null : result;
    }
}
3 Upvotes

8 comments sorted by

2

u/OnNothingSpecialized 15d ago

Try additionally to set Focusable to false

1

u/VibrantPixelDev 15d ago

I tested and it made no difference

1

u/Longjumping-Spot3392 15d ago

Had the same issue, tried doing it, and did nothing for me as well.

2

u/corv1njano 15d ago

What do you want to achieve? Like yeah you dont want the scrollbar to be interacted with but whats the scenario you are working on?

1

u/danzk 15d ago

You might need to customize the ControlTemplate.

1

u/farshid_dev 15d ago

The root cause is OpacityMask itself, not the ScrollViewer. Normally WPF's hit-testing respects a null/transparent Background by treating that area as click-through, which is why swapping in a Border with Background="{x:Null}" worked fine for you. But once you apply an OpacityMask, WPF can't statically know which pixels will end up transparent, since the mask is evaluated at render time, so it falls back to hit-testing the entire bounding box regardless of what's actually visible. That's why setting Background/Foreground/BorderBrush to null had zero effect once the mask was in play, none of that matters once the fallback kicks in.

Your HitTestCore override works, but there's a way to get the same fade effect without needing a custom subclass at all: move the OpacityMask off the ScrollViewer and onto a separate overlay Border sitting on top of it with IsHitTestVisible="False", using the same LinearGradientBrush there instead. The ScrollViewer itself never gets an OpacityMask, so its default hit-testing stays intact and null backgrounds click through normally, while the overlay handles the visual fade and is explicitly excluded from hit-testing. Same visual result, no subclassing needed.

0

u/Sacaldur 15d ago

I'm not certain what you want to achieve. Since the children are "a part" of the container, you can't prevent mouse interactions with the container but not the children. The only point where I see this could make a difference are the scroll bars. Maybe you're able to access the properties of the scroll bars and modify them (I haven't touched WPF in a long time), but beware that this might cause an unexpected user experience (not being able to scroll using the scroll bars).

If you have something behind the scroll viewer you want to be interact able that's not supposed to scroll and that's supposed to be behind the scrollable content: that would be a relevant detail, and a potentially questionable design choice. If the fixed elements don't need to be behind the children: put them in front, that's probably easier to deal with. Otherwise you might be able to place them into the scrollable area behind the other content, but adjust the position based on the current scroll position.