停止 WPF ScrollViewer 自动滚动到感知的内容 [英] Stop WPF ScrollViewer automatically scrolling to perceived content

查看:87
本文介绍了停止 WPF ScrollViewer 自动滚动到感知的内容的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

应用程序

我正在构建一个包含范围选择器的应用程序.这由包含在一个 UserControl 派生类中的两个自定义绘制的 Slider 控件组成.然后,范围选择器控件包含在 ScrollViewer 中,该控件在大多数情况下都可以看到 Horizo​​nalScrollBar.

I am building an application which includes a range selector. This consists of two custom drawn Slider controls contained within one UserControl derived class. The range selector control is then contained inside a ScrollViewer which has the HorizonalScrollBar visible most of the time.

示例应用程序代码:(文字墙的应用程序)

Window.xaml(窗口文件):

Window.xaml ( the Window file ):

<Grid>
    <ScrollViewer x:Name="ScrollViewer" HorizontalScrollBarVisibility="Visible"  VerticalScrollBarVisibility="Disabled">
            <local:SliderTest x:Name="slider"                                                                         
                           LowerValue="0"
                           UpperValue="10"
                           Minimum="0"
                           Maximum="100" Width="900" Height="165" Padding="15,0,15,0" HorizontalAlignment="Left">
            </local:SliderTest>
    </ScrollViewer>
</Grid>

SliderTest.xaml:

SliderTest.xaml:

<UserControl x:Class="scrollviewerDemoProblem.SliderTest"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             x:Name="root"
             xmlns:local="clr-namespace:scrollviewerDemoProblem"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <ControlTemplate x:Key="simpleSlider" TargetType="{x:Type Slider}">
            <Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Track x:Name="PART_Track" Grid.Row="1">
                        <Track.Thumb>
                            <Thumb x:Name="Thumb" FlowDirection="LeftToRight" Width="15">
                                <Thumb.Template>
                                    <ControlTemplate TargetType="Thumb">
                                        <Canvas>
                                            <Path x:Name="test1" StrokeThickness="0" Fill="DarkGreen">
                                                <Path.Data>
                                                    <GeometryGroup FillRule="NonZero">
                                                        <PathGeometry>
                                                            <PathGeometry.Figures>
                                                                <PathFigure IsClosed="True" StartPoint="0,150" IsFilled="True">
                                                                    <PathFigure.Segments>
                                                                        <PathSegmentCollection>
                                                                            <LineSegment Point="-15,150" />
                                                                            <LineSegment Point="-15,0" />
                                                                            <LineSegment Point="0,0" />
                                                                        </PathSegmentCollection>
                                                                    </PathFigure.Segments>
                                                                </PathFigure>
                                                            </PathGeometry.Figures>
                                                        </PathGeometry>
                                                    </GeometryGroup>
                                                </Path.Data>
                                            </Path>
                                        </Canvas>
                                    </ControlTemplate>
                                </Thumb.Template>
                            </Thumb>
                        </Track.Thumb>
                    </Track>
                </Grid>
            </Border>
        </ControlTemplate>

        <ControlTemplate x:Key="simpleSliderRight" TargetType="{x:Type Slider}">
            <Border SnapsToDevicePixels="true" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="Auto" MinHeight="{TemplateBinding MinHeight}"/>
                        <RowDefinition Height="Auto"/>
                    </Grid.RowDefinitions>
                    <Track x:Name="PART_Track" Grid.Row="1">
                        <Track.Thumb>
                            <Thumb x:Name="Thumb" HorizontalAlignment="Center" HorizontalContentAlignment="Center" Width="15">
                                <Thumb.Template>
                                    <ControlTemplate TargetType="Thumb">
                                        <Canvas>
                                            <Path Stroke="Black" StrokeThickness="0" Fill="DarkCyan">
                                                <Path.Data>
                                                    <GeometryGroup FillRule="NonZero">
                                                        <PathGeometry>
                                                            <PathGeometry.Figures>
                                                                <PathFigure IsClosed="True" StartPoint="0,150">
                                                                    <PathFigure.Segments>
                                                                        <PathSegmentCollection>
                                                                            <LineSegment Point="15,150" />
                                                                            <LineSegment Point="15,0" />
                                                                            <LineSegment Point="0,0" />
                                                                        </PathSegmentCollection>
                                                                    </PathFigure.Segments>
                                                                </PathFigure>
                                                            </PathGeometry.Figures>
                                                        </PathGeometry>
                                                    </GeometryGroup>
                                                </Path.Data>
                                            </Path>
                                        </Canvas>
                                    </ControlTemplate>
                                </Thumb.Template>
                            </Thumb>
                        </Track.Thumb>
                    </Track>
                </Grid>
            </Border>
        </ControlTemplate>
    </UserControl.Resources>

    <Grid x:Name="Gridd" VerticalAlignment="Top" Height="165" >
        <Border x:Name="timeScaleBorder" Width="auto" Height="15" VerticalAlignment="Top" Background="Black">
            <Canvas x:Name="timeCanvas" Width="auto" Height="15">
            </Canvas>
        </Border>
        <Border x:Name="background" BorderThickness="1,1,1,1" BorderBrush="Black" VerticalAlignment="Center" Height="150"
                Margin="0,15,0,0" Background="White" />
        <Slider  x:Name="LowerSlider"
                Minimum="{Binding ElementName=root, Path=Minimum}"
                Maximum="{Binding ElementName=root, Path=Maximum}"
                Value="{Binding ElementName=root, Path=LowerValue, Mode=TwoWay}"
                Template="{StaticResource simpleSlider}"
                Margin="0,15,0,0" />
        <Slider  x:Name="UpperSlider"
                Minimum="{Binding ElementName=root, Path=Minimum}"
                Maximum="{Binding ElementName=root, Path=Maximum}"
                Value="{Binding ElementName=root, Path=UpperValue, Mode=TwoWay}"
                Template="{StaticResource simpleSliderRight}"
                Margin="0,15,0,0" />
    </Grid>
</UserControl>

SliderText.xaml.cs:

SliderText.xaml.cs:

public partial class SliderTest : UserControl
{
    public SliderTest()
    {
        InitializeComponent();
    }

    #region Dependency properties, values etc.

    public static readonly DependencyProperty MinimumProperty =
        DependencyProperty.Register("Minimum", typeof(double), typeof(SliderTest), new UIPropertyMetadata(0d));

    public double LowerValue
    {
        get { return (double)GetValue(LowerValueProperty); }
        set { SetValue(LowerValueProperty, value); }
    }

    public static readonly DependencyProperty LowerValueProperty =
        DependencyProperty.Register("LowerValue", typeof(double), typeof(SliderTest), new UIPropertyMetadata(0d));

    public double UpperValue
    {
        get { return (double)GetValue(UpperValueProperty); }
        set { SetValue(UpperValueProperty, value); }
    }

    public static readonly DependencyProperty UpperValueProperty =
        DependencyProperty.Register("UpperValue", typeof(double), typeof(SliderTest), new UIPropertyMetadata(0d));

    public double Maximum
    {
        get { return (double)GetValue(MaximumProperty); }
        set { SetValue(MaximumProperty, value); }
    }

    public static readonly DependencyProperty MaximumProperty =
        DependencyProperty.Register("Maximum", typeof(double), typeof(SliderTest), new UIPropertyMetadata(1d));

    public double Minimum
    {
        get { return (double)GetValue(MinimumProperty); }
        set { SetValue(MinimumProperty, value); }
    }
    #endregion        
}

问题提供的大多数示例代码都很乏味,而且它的机制非常好.我遇到的问题是一个视觉问题,特别是我在主窗口中的 ScrollViewer 控件.ScrollViewer 似乎会在 Slider 中的任何一个获得焦点时自动调整 ScrollViewer 的水平偏移(例如通过鼠标点击)).

The Problem Most of the sample code provided is boring and the mechanics of it works pretty good. The problem I am having is a visual problem specifically with the ScrollViewer control that I have in the main Window. The ScrollViewer seems to be automatically adjusting the horizontal offset of the ScrollViewer when either of the Slider's gains focus ( from a mouse click for example ).

再现行为

  1. 运行应用程序,您将看到 ScrollViewer 的水平滚动条可见.
  2. 单击绿色(最左侧)Slider,您会注意到 ScrollViewer 会自动调整以将水平偏移移动到感知内容"开始的位置.
  1. Run the application, you will see that the horizontal scroll bar of the ScrollViewer is visible.
  2. Click on the Green ( far left ) Slider, you will notice that the ScrollViewer automatically adjusts to shift the horizontal offset to where the perceived 'content' starts.

这些症状出现在滚动窗格的任一端.

These symptoms occur at either end of the scroll pane.

应用程序运行时的屏幕截图(应用程序放大 200% 以确保细节清晰):

Screenshot of application when it is run ( Application is Zoomed in 200% for detail clarity ):

点击左侧滑块时的行为截图:

Screenshot of the behavior when the left slider is clicked:

我想要发生的事情:

当我单击任一滑块项目(在任一端)时,当滑块看起来超出滑块的末端(滑块范围由顶部的黑条表示)时,我希望 ScrollViewer 自动调整它的水平偏移.

When I click on either slider item ( at either end ) when a slider looks to be beyond end of the slider ( slider range is denoted by the black bar at the top ) I don't want the ScrollViewer to automatically adjust it's horizontal offset.

疑似问题:

我怀疑问题在于 ScrollViewer 从实际绘制的内容开始的 15 像素(我的两个滑块的绘制宽度)开始感知其子项的实际内容".画布仅绘制,因为我在主窗口的 SliderTest 控件内包含了 15 像素的填充,如果删除此填充,ScrollViewer 不会显示任何滑块的画布.

I suspect that the problem is that the ScrollViewer perceives the actual 'content' of it's childen starts 15 pixels ( the drawn width of both of my sliders ) in from where the actual drawn content does start. The Canvas only draws because I included a padding of 15 pixels inside of the SliderTest control on the main window, if this padding is removed the ScrollViewer does not show any of the Slider's Canvas.

EDIT :看起来填充不是问题,请阅读评论以了解原因.

EDIT : it appears the padding is not the problem, read the comments as to why.

我尝试过的事情

我尝试过覆盖主窗口的 OnPreviewMouseDown 事件.这里的问题是我仍然希望两个 Slider 都能正常运行,将事件设置为 Handled 会导致 Slider 完全停止工作.

I have tried looking into overriding the OnPreviewMouseDown event of the main Window. The problem here is that I still want both Slider's to behave normally, setting the event to Handled causes the Slider to stop working completely.

注意事项:

范围选择器控件中的滑块(在本例中称为 SliderTest)必须都具有 1 像素的宽度.滑块必须能够超出时间选择范围的末端 15 个像素(请参阅顶部的黑条以获取参考).

The Slider's within the range selector control ( Called SliderTest in this example ) must both have a width of 1 pixel. The slider's must be able to extend 15 pixels past the end of the time selection range ( see the black bar at the top for a reference ).

感谢您阅读这个长篇小说.

Thank you for reading this novel-lengthed problem.

推荐答案

默认情况下,当控件收到逻辑焦点时,FrameworkElement 调用自己的 BringIntoView 方法(从它的 OnGotFocus 方法中,如果它有键盘焦点).这会导致生成一个 RequestBringIntoView 事件,该事件在元素树中冒泡允许祖先元素将元素的该部分带入视野.ScrollViewer 侦听此事件并最终将在关联的 IScrollInfo/ScrollContentPresenter 上调用 MakeVisible,这将它留给面板以将该部分显示在视图中(因为面板将知道它如何安排其子项).然后它接收它接收的返回的 rect 并要求将其自身的那部分显示在视图中(以防您有嵌套元素需要采取一些操作来确保原始元素显示在视图中).因此,抑制这种行为的一种方法是处理滑块上的 RequestBringIntoView 事件并标记该事件已处理.

By default when a control receives the logical focus, FrameworkElement calls its own BringIntoView method (from within its OnGotFocus method if it has keyboard focus). That results in a RequestBringIntoView event being generated that bubbles up the element tree to allow ancestor elements to bring that portion of the element into view. The ScrollViewer listens for this event and eventually will call MakeVisible on the associated IScrollInfo/ScrollContentPresenter which leaves it up to the panel to bring that portion into view (since the panel would know how it arranges its children). It then takes that returned rect it receives back and asks for that portion of itself to be brought into view (in case you had nested elements that would require some action to ensure the original element was brought into view). So one way to suppress this behavior would be to handle the RequestBringIntoView event on the sliders and mark the event handled.

这篇关于停止 WPF ScrollViewer 自动滚动到感知的内容的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆