Last active
October 13, 2015 20:59
-
-
Save Kinnara/9660212 to your computer and use it in GitHub Desktop.
How to disable bounce effect for ScrollViewer when content is not scrollable
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Diagnostics; | |
using System.Windows; | |
using System.Windows.Controls; | |
using System.Windows.Controls.Primitives; | |
using System.Windows.Media; | |
namespace Kinnara.Phone.Controls | |
{ | |
public sealed class ScrollContent : ContentPresenter | |
{ | |
private ScrollViewer _scrollOwner; | |
private bool _isScrollClient; | |
private ScrollBarVisibility _originalVerticalScrollBarVisibility; | |
private Size _contentDesiredSize; | |
protected override Size MeasureOverride(Size availableSize) | |
{ | |
InitializeScrollOwner(); | |
if (_scrollOwner != null && !_isScrollClient) | |
{ | |
_contentDesiredSize = base.MeasureOverride(new Size(availableSize.Width, double.PositiveInfinity)); | |
} | |
else | |
{ | |
_contentDesiredSize = base.MeasureOverride(availableSize); | |
} | |
UpdateVerticalScrollBarVisibility(); | |
return _contentDesiredSize; | |
} | |
private void InitializeScrollOwner() | |
{ | |
if (_scrollOwner == null) | |
{ | |
_scrollOwner = GetParentByType<ScrollViewer>(this); | |
if (_scrollOwner != null) | |
{ | |
var itemsPresenter = _scrollOwner.Content as ItemsPresenter; | |
if (itemsPresenter != null) | |
{ | |
if (VisualTreeHelper.GetChildrenCount(itemsPresenter) > 0) | |
{ | |
var scrollInfo = VisualTreeHelper.GetChild(itemsPresenter, 0) as IScrollInfo; | |
if (scrollInfo != null) | |
{ | |
_isScrollClient = true; | |
} | |
} | |
} | |
_originalVerticalScrollBarVisibility = _scrollOwner.VerticalScrollBarVisibility; | |
_scrollOwner.SizeChanged += OnScrollOwnerSizeChanged; | |
} | |
} | |
} | |
private void OnScrollOwnerSizeChanged(object sender, SizeChangedEventArgs e) | |
{ | |
UpdateVerticalScrollBarVisibility(); | |
} | |
private void UpdateVerticalScrollBarVisibility() | |
{ | |
if (_isScrollClient) | |
{ | |
if (_scrollOwner.ScrollableHeight > 0) | |
{ | |
SetVerticalScrollBarVisibility(_originalVerticalScrollBarVisibility); | |
} | |
else | |
{ | |
SetVerticalScrollBarVisibility(ScrollBarVisibility.Disabled); | |
} | |
} | |
else if (_scrollOwner != null && _scrollOwner.ActualHeight > 0) | |
{ | |
if (_scrollOwner.ViewportHeight < _contentDesiredSize.Height) | |
{ | |
SetVerticalScrollBarVisibility(_originalVerticalScrollBarVisibility); | |
} | |
else | |
{ | |
SetVerticalScrollBarVisibility(ScrollBarVisibility.Disabled); | |
} | |
} | |
} | |
private void SetVerticalScrollBarVisibility(ScrollBarVisibility value) | |
{ | |
if (_scrollOwner.VerticalScrollBarVisibility != value) | |
{ | |
_scrollOwner.VerticalScrollBarVisibility = value; | |
} | |
} | |
private static T GetParentByType<T>(DependencyObject element) | |
where T : FrameworkElement | |
{ | |
Debug.Assert(element != null, "The element cannot be null."); | |
T result = null; | |
DependencyObject parent = VisualTreeHelper.GetParent(element); | |
while (parent != null) | |
{ | |
result = parent as T; | |
if (result != null) | |
{ | |
return result; | |
} | |
parent = VisualTreeHelper.GetParent(parent); | |
} | |
return null; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<Style x:Key="ScrollViewerVerticalStyle" TargetType="ScrollViewer"> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="ScrollViewer"> | |
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"> | |
<VisualStateManager.VisualStateGroups> | |
<VisualStateGroup x:Name="ScrollStates"> | |
<VisualStateGroup.Transitions> | |
<VisualTransition GeneratedDuration="00:00:00.5"/> | |
</VisualStateGroup.Transitions> | |
<VisualState x:Name="Scrolling"> | |
<Storyboard> | |
<DoubleAnimation Storyboard.TargetName="VerticalScrollBar" Storyboard.TargetProperty="Opacity" To="1" Duration="0"/> | |
</Storyboard> | |
</VisualState> | |
<VisualState x:Name="NotScrolling"> | |
</VisualState> | |
</VisualStateGroup> | |
</VisualStateManager.VisualStateGroups> | |
<Grid Margin="{TemplateBinding Padding}"> | |
<ScrollContentPresenter x:Name="ScrollContentPresenter"> | |
<ScrollContentPresenter.ContentTemplate> | |
<DataTemplate> | |
<kpc:ScrollContent Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}" xmlns:kpc="clr-namespace:Kinnara.Phone.Controls"/> | |
</DataTemplate> | |
</ScrollContentPresenter.ContentTemplate> | |
</ScrollContentPresenter> | |
<ScrollBar x:Name="VerticalScrollBar" IsHitTestVisible="False" Opacity="0" Height="Auto" Width="5" HorizontalAlignment="Right" VerticalAlignment="Stretch" Margin="0,0,1,0" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" IsTabStop="False" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Value="{TemplateBinding VerticalOffset}" Orientation="Vertical" ViewportSize="{TemplateBinding ViewportHeight}" /> | |
</Grid> | |
</Border> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
<Style TargetType="ScrollViewer" BasedOn="{StaticResource ScrollViewerVerticalStyle}"/> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment