开发者

How can one link a DataTrigger to whether a ScrollViewer can scroll up?

I am wanting to show a half opaque arrow at the top and bottom of my ScrollViewer if it can scroll up or down respectively. I'm thinking the best option is a DataTrigger, but I'm not sure what I can tie it too. I'm trying to avoid subclassing S开发者_开发百科crollViewer, but if I absolutely have to, I will. Any ideas?

I'm using the .Net Framework 3.5 (man I wish I could upgrade!).

Thanks. :)


One of possible solutions. It uses two converters to calculate if it is possible to scroll. Template is based on the standard ScrollViewer template, but with two additional text blocks to display information ("arrows").

Window1.xaml

<Window x:Class="WpfApplication1.Window1"
        Title="Window1" Height="300" Width="300"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:WpfApplication1="clr-namespace:WpfApplication1">
    <Window.Resources>
        <ResourceDictionary>
            <WpfApplication1:ScrollViewerCanScrollUpConverter x:Key="ScrollViewerCanScrollUpConverter" />
            <WpfApplication1:ScrollViewerCanScrollDownConverter x:Key="ScrollViewerCanScrollDownConverter" />
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <ScrollViewer Background="Transparent">
            <ScrollViewer.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>
                        <Rectangle x:Name="Corner" Fill="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Grid.Column="1" Grid.Row="1"/>
                        <ScrollContentPresenter Margin="{TemplateBinding Padding}" x:Name="PART_ScrollContentPresenter" Grid.Column="0" Grid.Row="0" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" CanContentScroll="{TemplateBinding CanContentScroll}" CanHorizontallyScroll="False" CanVerticallyScroll="False"/>
                        <ScrollBar Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" Cursor="Arrow" x:Name="PART_VerticalScrollBar" ViewportSize="{TemplateBinding ViewportHeight}" Maximum="{TemplateBinding ScrollableHeight}" Minimum="0" Value="{Binding Path=VerticalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="1" Grid.Row="0" AutomationProperties.AutomationId="VerticalScrollBar"/>
                        <ScrollBar Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" Cursor="Arrow" x:Name="PART_HorizontalScrollBar" Orientation="Horizontal" ViewportSize="{TemplateBinding ViewportWidth}" Maximum="{TemplateBinding ScrollableWidth}" Minimum="0" Value="{Binding Path=HorizontalOffset, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}" Grid.Column="0" Grid.Row="1" AutomationProperties.AutomationId="HorizontalScrollBar"/>
                        <TextBlock x:Name="PART_UpTextBlock" VerticalAlignment="Top" Text="Can scroll up" Visibility="Collapsed" />
                        <TextBlock x:Name="PART_DownTextBlock" VerticalAlignment="Bottom" Text="Can scroll down" Visibility="Collapsed" />
                    </Grid>
                    <ControlTemplate.Triggers>
                        <DataTrigger Value="True" Binding="{Binding Path=VerticalOffset, RelativeSource={RelativeSource Self}, Converter={StaticResource ScrollViewerCanScrollUpConverter}}">
                            <Setter TargetName="PART_UpTextBlock" Property="Visibility" Value="Visible" />
                        </DataTrigger>
                        <DataTrigger Value="True">
                            <DataTrigger.Binding>
                                <MultiBinding Converter="{StaticResource ScrollViewerCanScrollDownConverter}">
                                    <Binding Path="VerticalOffset" RelativeSource="{RelativeSource Self}" />
                                    <Binding Path="ExtentHeight" RelativeSource="{RelativeSource Self}" />
                                    <Binding Path="ViewportHeight" RelativeSource="{RelativeSource Self}" />
                                </MultiBinding>
                            </DataTrigger.Binding>
                            <Setter TargetName="PART_DownTextBlock" Property="Visibility" Value="Visible" />
                        </DataTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </ScrollViewer.Template>
            <Border Margin="10" Height="400" Background="Yellow">
                <TextBlock Text="Content" />
            </Border>
        </ScrollViewer>
    </Grid>
</Window>

Window1.xaml.cs

using System;
using System.Globalization;
using System.Windows.Data;

namespace WpfApplication1
{
    public partial class Window1
    {
        public const double Epsilon = 0.001;

        public Window1()
        {
            InitializeComponent();
        }
    }

    public class ScrollViewerCanScrollUpConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Math.Abs((double)value) > Window1.Epsilon;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }

    public class ScrollViewerCanScrollDownConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            double verticalOffset = (double)values[0];
            double extentHeight = (double)values[1];
            double viewportHeight = (double)values[2];
            double maxOffset = Math.Max(0.0, extentHeight - viewportHeight);
            return verticalOffset < maxOffset - Window1.Epsilon;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotSupportedException();
        }
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜