.net - 如何将 DataTrigger 与 ScrollViewer 是否可以向上滚动联系起来?

标签 .net wpf scrollviewer datatrigger

我想在 ScrollViewer 的顶部和底部显示一个半不透明的箭头(如果它可以分别向上或向下滚动)。我认为最好的选择是 DataTrigger,但我不确定我也可以将它绑定(bind)在一起。我试图避免子类化 ScrollViewer,但如果我绝对必须这样做,我会的。有什么想法吗?

我正在使用 .Net Framework 3.5(我希望我可以升级!)。

谢谢。 :)

最佳答案

可能的解决方案之一。它使用两个转换器来计算是否可以滚动。模板基于标准 ScrollViewer 模板,但带有两个附加文本 block 来显示信息(“箭头”)。

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();
        }
    }
}

关于.net - 如何将 DataTrigger 与 ScrollViewer 是否可以向上滚动联系起来?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4035462/

相关文章:

asp.net - 让 ASP.NET MVC Web 应用程序加载域中性

c# - 调试IIS随机疯狂内存使用情况

wpf - 如何在 WPF 中设置/重置三态复选框值

c# - 只读自动实现的属性是否可能?

c# - C# 是否优化了字符串文字的连接?

c# - WPF DataGrid - 如何在验证错误后取消编辑行?

wpf - 删除列表框周围的多余空间

c# - 在自定义样式的按钮中获取 ScrollViewer

c# - ScrollViewer:当 ComputedHorizo​​ntalScrollBarVisibility 改变时通知

silverlight - 增长的ScrollView(高度="Auto"MaxHeight ="Stretch")