您的位置:澳门新葡8455最新网站 > 编程教学 > 包含惯性的ScrollViewer

包含惯性的ScrollViewer

发布时间:2019-12-09 15:19编辑:编程教学浏览(59)

    生机勃勃、先看看效果

      寒假过完,在家真心什么都做不了,或许老了,再想以前那么能用尽全力坐下来已经丰富了。回来第少年老成件事就是改了品种的多少个bug,近些日子又新扩展了一个新的效能,为顺序增多了贰个音讯栏。音讯栏有众多花样,供给是三个没有必要历史记录,可以用鼠标选中国国投息内容的音信栏。作者先是想到的正是TextBox,作者个人相比较赏识美貌的,有一些精神分裂症,所以必得把TextBox中的ScrollViewer给改写了,好呢,开头。

    澳门新葡萄京娱乐场 1

      本博文分为多少个部分,第风姿浪漫部分将汇报如何改写TextBox的布局,第二有些则描述怎样改写TextBox中的ScrollViewer样式,首局地则是对自定义样式时发出的不明难题进行缝补。

     

      朝气蓬勃、生成自定义TextBox控件

     

      依然把此番写的音信框做成客商控件的花样,首先,前台轻松的XAML:

    二、原理

    澳门新葡萄京娱乐场 2澳门新葡萄京娱乐场 3新闻框底工XAML

      尽管功效极粗略,可是英特网的有个别资料涉及的代码量非常可观,何况效果亦非很了不起,滚动的时候从不二个顺滑感。作者那边提供的源码风流倜傥共120多行,就可以实现上海体育场面的意义。

     1 <TextBox x:Class="FS.PresentationManagement.Controls.MessageTextBox"
     2          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     3          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="SkyBlue">
     4     <TextBox.Template>
     5         <ControlTemplate TargetType="{x:Type TextBox}">
     6             <Grid Background="{TemplateBinding Background}">
     7                 <Grid.ColumnDefinitions>
     8                     <ColumnDefinition />
     9                     <ColumnDefinition Width="62" />
    10                 </Grid.ColumnDefinitions>
    11                 <!-- 文本框 -->
    12                 <ScrollViewer x:Name="PART_ContentHost">
    13                     <!-- 暂时省略 -->
    14                 </ScrollViewer>
    15                 <!-- 按钮 -->
    16                 <Button Name="BTN_Clear" Margin="5" Grid.Column="1" Click="BTN_Clear_Click">
    17                     <Button.Template>
    18                         <ControlTemplate>
    19                             <Image Name="IMG_Clear" Source="../Pic/clear.png"/>
    20                             <ControlTemplate.Triggers>
    21                                 <Trigger Property="IsMouseOver" Value="True">
    22                                     <Setter TargetName="IMG_Clear" Property="Source" Value="../Pic/clear2.png" />
    23                                 </Trigger>
    24                                 <Trigger Property="Button.IsPressed" Value="True">
    25                                     <Setter TargetName="IMG_Clear" Property="Source" Value="../Pic/clear3.png" />
    26                                 </Trigger>
    27                             </ControlTemplate.Triggers>
    28                         </ControlTemplate>
    29                     </Button.Template>
    30                 </Button>
    31                 <Button Name="BTN_Close" Margin="0,-18,-25,0" VerticalAlignment="Top" Width="32" Height="32" Grid.Column="1" Click="BTN_Close_Click">
    32                     <Button.Template>
    33                         <ControlTemplate>
    34                             <Image Name="IMG_Close" Source="../Pic/close.png" />
    35                             <ControlTemplate.Triggers>
    36                                 <Trigger Property="IsMouseOver" Value="True">
    37                                     <Setter TargetName="IMG_Close" Property="Source" Value="../Pic/close2.png" />
    38                                 </Trigger>
    39                                 <Trigger Property="Button.IsPressed" Value="True">
    40                                     <Setter TargetName="IMG_Close" Property="Source" Value="../Pic/close3.png" />
    41                                 </Trigger>
    42                             </ControlTemplate.Triggers>
    43                         </ControlTemplate>
    44                     </Button.Template>
    45                 </Button>
    46             </Grid>
    47         </ControlTemplate>
    48     </TextBox.Template>
    49 </TextBox>
    

      本质上大家假如接管ScrollViewer的滚动逻辑,并且把那些逻辑替换到带有惯性的就可以,那么如何去接管呢?这里的根本是先屏蔽ScrollViewer的鼠标滚轮事件:

      此时框架大概是,左侧将是三个ScrollViewer,用来体现信息,侧边则是停业和清理,七个开关,至于开关的样式,也早已张开了变动,各类开关使用三张图纸来代表原来、停靠、按下三种境况,必要当心,下边包车型客车XAML中开关的Source路径是像“../Pic/xxx.png”,那是本身把图片放到了近些日子文件的--->上级目录的--->Pic目录下,所以实际上海南大学学家在动用的时候必要把这么些天性改成图片所在路径。

    1 protected override void OnMouseWheel(MouseWheelEventArgs e)
    2 {
    3      e.Handled = true;
    4 }
    

      后台代码那时也极其轻巧,只是简短地三番一次了TextBox控件:

      这样一来,ScrollViewer就不会响应滚轮事件了,大家就在那地做文章。首先大家给那个ScrollViewer增多壹性格质 IsEnableInertia ,用来调整是或不是利用惯性,因为萝卜油麻菜籽各有所好,不要想着强制全体人使用惯性,所以滚轮响应措施成为:

    澳门新葡萄京娱乐场 4澳门新葡萄京娱乐场 5音信框功底C#

    1 protected override void OnMouseWheel(MouseWheelEventArgs e)
    2 {
    3     if (!IsEnableInertia)
    4     {
    5         base.OnMouseWheel(e);
    6         return;
    7     }
    8     e.Handled = true;
    9 }    
    
     1 namespace FS.PresentationManagement.Controls
     2 {
     3     /// <summary>
     4     /// 文本消息框控件
     5     /// </summary>
     6     public partial class MessageTextBox : TextBox
     7     {
     8         public MessageTextBox()
     9         {
    10             InitializeComponent();        
    11         }
    12     }
    13 }
    

      调整ScrollViewer的垂直滚动能够动用 ScrollViewer.ScrollToVerticalOffset ,横向也如出风流浪漫辙。为啥无法用 VerticalOffset ?因为 VerticalOffset 在注册的时候就证明了是只读的:

      当时的功效如图所示:澳门新葡萄京娱乐场 6  看起来勉强接收啊,右上角的闭馆开关由于截图原因不是很清晰,稍后我们得以见到完好版的要好有的。

    1 private static readonly DependencyPropertyKey VerticalOffsetPropertyKey = DependencyProperty.RegisterReadOnly(nameof (VerticalOffset), typeof (double), typeof (ScrollViewer), (PropertyMetadata) new FrameworkPropertyMetadata((object) 0.0));
    2 
    3 public static readonly DependencyProperty VerticalOffsetProperty = ScrollViewer.VerticalOffsetPropertyKey.DependencyProperty;
    

      二、改造ScrollViewer控件

      好了,接下去就是怎么在滚轮响应措施中落到实处惯性运动了,也正是大器晚成种减速运动。想到那儿,熟知动漫的博友相当慢就精晓要用WPF的动漫来贯彻了,暗中同意的卡通片都以三回线性的,要有惯性功用就得用缓动函数,WPF的缓动函数有多数,而 CubicEase 极其切合用来做惯性,它的汇报图如下:

      上边介绍本文的着力,如何自定义ScrollViewer控件,当然,大家的靶子亦不是把它改成怎么着奇葩,只是想把滚动条变得精彩一点而已。假设运用WPF非常多的心上人会明白,超级多控件都以由许多层黄金时代层风华正茂层地叠合产生可视化树的,ScrollViewer也不例外,现在通过Template属性能够完全本身定义其布局。

    澳门新葡萄京娱乐场 7

      要开展改建的ScrollViewer控件就投身第生龙活虎某个XAML代码中的省略部分,小编今天只贴出那风流洒脱部分代码:

      图中,横轴表示时间,纵轴表示运动间隔。很明朗,中间的 EaseOut 格局正是大家想要的。到了那边思路就清楚了,大家得以定义壹脾天性 CurrentVerticalOffset ,大家会在它下面完结动漫,在它的值回调函数中调用 ScrollViewer.ScrollToVerticalOffset 来更新ScrollViewer的轮转地点。当然大家还索要叁个私人商品房字段 _totalVerticalOffset ,这几个是用来寄放在ScrollViewer滚动指标地方的,滚轮向下滚动一个单位大家就给它减去叁遍 e.Delta ,这里的e是滚轮响应措施传进来的参数,每一遍给它赋值之后,就足以在 CurrentVerticalOffset 上进行动漫了: BeginAnimation(CurrentVerticalOffsetProperty, animation卡塔尔(قطر‎ ,须要极其注意的是,当二个正视属性用了动漫片改造后,再对其赋值则不会卓有成效,原因是在一个动漫达到活动期的极点后,时间线私下认可会保持其速度,直到其父级的活动期和保持期甘休停止。假若想在动漫停止后还足以手动改正注重属性的值,则须要把 FillBehavior 设置为Stop。不过尔尔又会冒出二个难题,意气风发旦动画停止,这几个依据属性又会借尸还魂早先值,所以还要给这些动漫订阅一个 Completed 事件,在事件响应措施中为 CurrentVerticalOffset 给定指标值,也正是 _totalVerticalOffset 。

    澳门新葡萄京娱乐场 8澳门新葡萄京娱乐场 9自定义ScrollViewer模版

      最后还大概有叁个冲突难点,当手动拖动滑块或然当用上下文菜单改动滚动条地点时是无法用动漫的,因为那时候未有触发 OnMouseWheel ,没提到,那便是大家想要的,可是假诺重新触发 OnMouseWheel 就有标题了,因为手动触发滚动的时候咱们从没给 CurrentVerticalOffset 和 _totalVerticalOffset 赋值( CurrentVerticalOffset 和 _totalVerticalOffset 只在 OnMouseWheel 中赋值),所以在用动漫实践滚动操作前要先决断一下是不是供给先更新一下它们俩,怎样判别?大家得以用三个个体字段 _isRunning 来维护状态,每当动画起先就给它赋值true,结束则赋值false。那样一来,当 _isRunning = false 时,表达在调用 OnMouseWheel 前,动漫已经收尾,客商可能早就手动改造了滚动条地方(也恐怕没有,但那并不影响),所以就要给前边俩弟兄更新一下值了。

      1 <ScrollViewer x:Name="PART_ContentHost">
      2     <ScrollViewer.Template>
      3         <ControlTemplate TargetType="{x:Type ScrollViewer}">
      4             <Grid Background="{Binding Path=ScrollViewerBackground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}">
      5                 <Grid.ColumnDefinitions>
      6                     <ColumnDefinition />
      7                     <ColumnDefinition Width="Auto"/>
      8                 </Grid.ColumnDefinitions>
      9                 <Grid.RowDefinitions>
     10                     <RowDefinition/>
     11                     <RowDefinition Height="Auto"/>
     12                 </Grid.RowDefinitions>
     13                 <ScrollContentPresenter Margin="5,5,0,5" />
     14                 <ScrollBar Name="PART_VerticalScrollBar" Grid.Column="1" Value="{TemplateBinding VerticalOffset}" Maximum="{TemplateBinding ScrollableHeight}" ViewportSize="{TemplateBinding ViewportHeight}" Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}">
     15                     <ScrollBar.Template>
     16                         <ControlTemplate TargetType="{x:Type ScrollBar}">
     17                             <!-- 竖向滚动条宽度 -->
     18                             <Grid Width="10">
     19                                 <Grid.RowDefinitions>
     20                                     <RowDefinition Height="1" />
     21                                     <RowDefinition />
     22                                     <RowDefinition Height="1" />
     23                                 </Grid.RowDefinitions>
     24                                 <Track x:Name="PART_Track" Grid.Row="1" IsDirectionReversed="True">
     25                                     <Track.DecreaseRepeatButton>
     26                                         <!--上空白-->
     27                                         <RepeatButton Command="ScrollBar.PageUpCommand" Opacity="0.5">
     28                                             <RepeatButton.Template>
     29                                                 <ControlTemplate>
     30                                                     <Border Background="{Binding Path=ScrollBarBackground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" CornerRadius="5,5,0,0" />
     31                                                 </ControlTemplate>
     32                                             </RepeatButton.Template>
     33                                         </RepeatButton>
     34                                     </Track.DecreaseRepeatButton>
     35                                     <Track.Thumb>
     36                                         <!--滑块-->
     37                                         <Thumb>
     38                                             <Thumb.Template>
     39                                                 <ControlTemplate>
     40                                                     <Border Background="{Binding Path=ScrollBarForeground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" CornerRadius="5" />
     41                                                 </ControlTemplate>
     42                                             </Thumb.Template>
     43                                         </Thumb>
     44                                     </Track.Thumb>
     45                                     <Track.IncreaseRepeatButton>
     46                                         <!--下空白-->
     47                                         <RepeatButton Command="ScrollBar.PageDownCommand" Opacity="0.5">
     48                                             <RepeatButton.Template>
     49                                                 <ControlTemplate>
     50                                                     <Border Background="{Binding Path=ScrollBarBackground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" CornerRadius="0,0,5,5" />
     51                                                 </ControlTemplate>
     52                                             </RepeatButton.Template>
     53                                         </RepeatButton>
     54                                     </Track.IncreaseRepeatButton>
     55                                 </Track>
     56                             </Grid>
     57                         </ControlTemplate>
     58                     </ScrollBar.Template>
     59                 </ScrollBar>
     60                 <ScrollBar Name="PART_HorizontalScrollBar" Orientation="Horizontal" Grid.Row="1" Value="{TemplateBinding HorizontalOffset}" Maximum="{TemplateBinding ScrollableWidth}" ViewportSize="{TemplateBinding ViewportWidth}" Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}">
     61                     <ScrollBar.Template>
     62                         <ControlTemplate TargetType="{x:Type ScrollBar}">
     63                             <!-- 横向滚动条高度 -->
     64                             <Grid Height="10">
     65                                 <Grid.ColumnDefinitions>
     66                                     <ColumnDefinition Width="1" />
     67                                     <ColumnDefinition />
     68                                     <ColumnDefinition Width="1" />
     69                                 </Grid.ColumnDefinitions>
     70                                 <Track x:Name="PART_Track" Grid.Column="1" IsDirectionReversed="False">
     71                                     <Track.DecreaseRepeatButton>
     72                                         <!--左空白-->
     73                                         <RepeatButton Command="ScrollBar.PageLeftCommand" Opacity="0.5">
     74                                             <RepeatButton.Template>
     75                                                 <ControlTemplate>
     76                                                     <Border Background="{Binding Path=ScrollBarBackground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" CornerRadius="5,0,0,5" />
     77                                                 </ControlTemplate>
     78                                             </RepeatButton.Template>
     79                                         </RepeatButton>
     80                                     </Track.DecreaseRepeatButton>
     81                                     <Track.Thumb>
     82                                         <!--滑块-->
     83                                         <Thumb>
     84                                             <Thumb.Template>
     85                                                 <ControlTemplate>
     86                                                     <Border Background="{Binding Path=ScrollBarForeground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" CornerRadius="5" />
     87                                                 </ControlTemplate>
     88                                             </Thumb.Template>
     89                                         </Thumb>
     90                                     </Track.Thumb>
     91                                     <Track.IncreaseRepeatButton>
     92                                         <!--右空白-->
     93                                         <RepeatButton Command="ScrollBar.PageRightCommand" Opacity="0.5">
     94                                             <RepeatButton.Template>
     95                                                 <ControlTemplate>
     96                                                     <Border Background="{Binding Path=ScrollBarBackground,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type TextBox}}}" CornerRadius="0,5,5,0" />
     97                                                 </ControlTemplate>
     98                                             </RepeatButton.Template>
     99                                         </RepeatButton>
    100                                     </Track.IncreaseRepeatButton>
    101                                 </Track>
    102                             </Grid>
    103                         </ControlTemplate>
    104                     </ScrollBar.Template>
    105                 </ScrollBar>
    106             </Grid>
    107         </ControlTemplate>
    108     </ScrollViewer.Template>
    109 </ScrollViewer>
    

      因为周围的惯性滚动以垂直方向居多,所以作者从未写水平方向的逻辑,但也十分轻松扩充,有意思味的博友能够下载源代码自身商讨。

      对应的后台重视属性:

     

    澳门新葡萄京娱乐场 10澳门新葡萄京娱乐场 11ScrollViewer的后台重视属性

    三、源码

     1         /// <summary>
     2         /// 滚动框背景
     3         /// </summary>
     4         public Brush ScrollViewerBackground
     5         {
     6             get { return (Brush)GetValue(ScrollViewerBackgroundProperty); }
     7             set { SetValue(ScrollViewerBackgroundProperty, value); }
     8         }
     9         public static readonly DependencyProperty ScrollViewerBackgroundProperty =
    10             DependencyProperty.Register("ScrollViewerBackground", typeof(Brush), typeof(MessageTextBox), new PropertyMetadata(Brushes.LightBlue));
    11 
    12         /// <summary>
    13         /// 滚动条前景
    14         /// </summary>
    15         public Brush ScrollBarForeground
    16         {
    17             get { return (Brush)GetValue(ScrollBarForegroundProperty); }
    18             set { SetValue(ScrollBarForegroundProperty, value); }
    19         }
    20         public static readonly DependencyProperty ScrollBarForegroundProperty =
    21             DependencyProperty.Register("ScrollBarForeground", typeof(Brush), typeof(MessageTextBox), new PropertyMetadata(Brushes.RoyalBlue));
    22 
    23         /// <summary>
    24         /// 滚动条背景
    25         /// </summary>
    26         public Brush ScrollBarBackground
    27         {
    28             get { return (Brush)GetValue(ScrollBarBackgroundProperty); }
    29             set { SetValue(ScrollBarBackgroundProperty, value); }
    30         }
    31         public static readonly DependencyProperty ScrollBarBackgroundProperty =
    32             DependencyProperty.Register("ScrollBarBackground", typeof(Brush), typeof(MessageTextBox), new PropertyMetadata(Brushes.WhiteSmoke));
    

      本文所评论的控件源码已经在github开源:

      在布局前台分界面时,首先,定义了三个Grid做为容器,并把它分成了四份,分别是内容、竖向滚动条、横向滚动条、空白。个中,内容位于0行、0列,使用ScrollContentPresenter来表示将在展现的源委;竖向滚动条坐落于0行1列,使用ScrollBar来代表;横向滚动条坐落于1行0列,使用横向(Orientation="Horizontal")的ScrollBar来表示。

     

      然后,分别自定义ScrollBar的体裁。以竖向滚动条为例,自定义ControlTemplate,使用Grid作为容器,把滚动条分为三行,第一表现提升按键、第二行为滚动条、第三行为向下开关。小编那边由于雅观寻思,把多少个按键全省略了(实际上大家超级少使用按键来上下滚动,超过十分之五时候用的鼠标中轮和拖动滑块)。

      滚动条是选拔的Track控件,它又包罗三个区域,分别是空中白、滑块、下空白,我们来看个示例图:

    澳门新葡萄京娱乐场 12

     

      Track的DecreaseRepeatButton正是空间白、Thumb则是滑块、IncreaseRepeatButton是下空白,分别对那八个控件实行体制自定义就能够改换其外观。供给表明的是竖向滚动条须要把Track的IsDirectionReversed属性设置为True,横向则设置为False,否则会产出卓殊奇异的场馆(原因嘛,大家看属性名的意思就知道了)。

      最后,还会有一点要解释一下,我们开掘众多控件有雷同于“PART_***”的名号,这一个名称请不要随意变动,那是WPF内置的奇怪名称,举个例子ScrollViewer的“PART_ContentHost”名称,就是代表这几个控件是用于装载Text博克斯的文件内容的,何况通过测量试验,这么些名称只可以用来ScrollViewer可能Adorner、Decorator控件。若无动用那个新鲜名称,大概就无法像您想像中那样自动达成专门的学问了。

    澳门新葡萄京娱乐场,  三、改进一些主题素材

      为何把那做为单独的生龙活虎环来谈谈吗?因为后边的代码已经能够达成主题的专门的学业了,并且现身的标题事关也并非超级大。不过总会不爽,因为它就不那么完美,所以,Fix It!

      标题1:鼠标中轮无法使ScrollViewer上下滚动

       发生那几个主题素材的由来极其古怪,借使不是改良ScrollViewer的Template来完全改变它,而是使用ScrollViewer.Resources来定义ScrollBar的Style则完全不会生出这种难点,可是那无法使的更改各控件的轻重和结构。

      其它,倘若不是把ScrollViewer的Name设置为“PART_ContentHost”,而是利用<TextBlock Text="{TemplateBinding Text}" TextWrapping="{TemplateBinding TextWrapping}" />放置到ScrollViewer体中,就能够正常滚动。但是那时会诱致力不能支选普通话本了,因为TextBlock中的文本是不帮助选中的,极其注意到,这个时候的轮转效能非常低,滚动时画面有无人不知的木讷现象。相似假诺不把ScrollViewer的Name设置为“PART_ContentHost”,而用<Decorator Name="PART_ContentHost" />放置到ScrollViewer体中,纵然选中也能支撑,可是依然不可能滚动。

      解决措施:

      首先,为ScrollViewer添加Initialized="PART_ContentHost_Initialized"事件,后台扩张新的性质ScrollViewer以便使用:

    澳门新葡萄京娱乐场 13澳门新葡萄京娱乐场 14初始化滚动条

     1     /// <summary>
     2         /// 消息体滚动框
     3         /// </summary>
     4         public ScrollViewer ScrollViewer { get; set; }
     5     
     6     // 初始化滚动条
     7         private void PART_ContentHost_Initialized(object sender, EventArgs e)
     8         {
     9             this.ScrollViewer = sender as ScrollViewer;
    10         }
    

      然后,本身达成中轮滚动方法,为ScrollViewer增多MouseWheel="PART_ContentHost_MouseWheel"事件,增多后台响应代码:

      private void PART_ContentHost_MouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
      {
        ScrollViewer.ScrollToVerticalOffset(ScrollViewer.VerticalOffset

    • (e.Delta >> 2));
        }

      便得以完备消弭鼠标中轮滚动难题。

      标题2:鼠标左键按住拖动无法使ScrollViewer滚动

       日常的话,大家在其余文字相关软件上,举例记事本、网页等,只要鼠标左键按下拖动选中文本,借使鼠标超过文本框可体现范围,便会自行向鼠标所在方向滚动文本内容,以落到实处跨页选中的功效。可是与难题1同等,由于改动了ScrollViewer的Template,招致那么些通用功能也急需和煦完成了。

      解决办法:

      首先,给前台的最上层成分TextBox增多SelectionChanged="TextBox_SelectionChanged"事件,以跟踪选中时鼠标所在地方:

     1         private void TextBox_SelectionChanged(object sender, RoutedEventArgs e)
     2         {
     3             if (ScrollViewer != null && this.SelectedText != "")
     4             {
     5                 var point = System.Windows.Input.Mouse.GetPosition(ScrollViewer);
     6                 // 纵向位移
     7                 double y = point.Y;
     8                 if (y > 0)
     9                 {
    10                     y = y - ScrollViewer.ActualHeight;
    11                     if (y < 0) y = 0;
    12                 }
    13                 _ScrollY = y;
    14                 // 横向位移
    15                 double x = point.X;
    16                 if (x > 0)
    17                 {
    18                     x = x - ScrollViewer.ActualWidth;
    19                     if (x < 0) x = 0;
    20                 }
    21                 _ScrollX = x;
    22             }
    23         }
    

      说喜宝(Hipp卡塔尔(英语:State of Qatar)(Nutrilon卡塔尔(英语:State of Qatar)下,_ScrollX和_ScrollY是多个分子属性,它们分别用来记录横向、竖向的鼠标位移,以用来决定是还是不是滚动。唯有在超过ScrollViewer的限制时,它们的值才会不为0,当小于0时意味着要发展/左滚动,大于0时表示向下/右滚动,它们的相对值越大,则滚动速度越快。

      现在,滚动量已经能立异了,但滚动触发条件还索要思索。首先,横向和竖向滚动相对于前台分界面确定是异步举办的;其次,已经在滚动时要实时依据滚动量来决定滚动速度;还会有,滚动终止条件应该是滚动量为0可能曾经滚动到了界限。好了,目的显然,必要增添三个委托来分别管理横向、竖向滚动,还需求八个异步操作情形来代表滚动是或不是终止,那么,代码扩展为:

    澳门新葡萄京娱乐场 15澳门新葡萄京娱乐场 16滚动委托

     1     // 坚向位移
     2         private double _ScrollY
     3         {
     4             get { return _scrollY; }
     5             set
     6             {
     7                 _scrollY = value;
     8                 // 开启滚动
     9                 if (_scrollY != 0 && (_ScrollYResult == null || _ScrollYResult.IsCompleted))
    10                     _ScrollYResult = _ScrollYAction.BeginInvoke(null, null);
    11             }
    12         }
    13         private double _scrollY;
    14 
    15         // 横向位移
    16         private double _ScrollX
    17         {
    18             get { return _scrollX; }
    19             set
    20             {
    21                 _scrollX = value;
    22                 // 开启滚动
    23                 if (_scrollX != 0 && (_ScrollXResult == null || _ScrollXResult.IsCompleted))
    24                     _ScrollXResult = _ScrollXAction.BeginInvoke(null, null);
    25             }
    26         }
    27         private double _scrollX;
    28 
    29     // 竖向滚动
    30         private Action _ScrollYAction;
    31         private IAsyncResult _ScrollYResult;
    32     
    33         // 横向滚动
    34         private Action _ScrollXAction;
    35         private IAsyncResult _ScrollXResult;
    

      也正是说,在_ScrollX和_ScrollY更新的时候,程序会开展一回推断,假设滚动量不为0,并且信托调用未有开首依然已经实现的时候,就调用委托,伊始开展滚动。

      最后,就是编辑滚动委托调用的函数了,分别有几个函数,在函数内以100ms为风流倜傥巡回,不停地开展滚动,当滚动到截至恐怕滚动量已经为0时跳出循环,退出函数实践。

    澳门新葡萄京娱乐场 17澳门新葡萄京娱乐场 18滚动函数体

     1     // 竖向
     2     private void ScrollYMethod()
     3         {
     4             double endOffset = 0;
     5             if (_ScrollY < 0)       // 向上滚动
     6                 endOffset = 0;
     7             else                    // 向下滚动
     8                 ScrollViewer.Dispatcher.Invoke((Action)(() => endOffset = ScrollViewer.ScrollableHeight), null);
     9             // 初始位置
    10             double offset = 0;
    11             ScrollViewer.Dispatcher.Invoke((Action)(() => offset = ScrollViewer.VerticalOffset), null);
    12             // 开始滚动
    13             while (offset != endOffset && _ScrollY != 0)
    14             {
    15                 ScrollViewer.Dispatcher.Invoke((Action)(() =>
    16                 {
    17                     offset = ScrollViewer.VerticalOffset;
    18                     ScrollViewer.ScrollToVerticalOffset(ScrollViewer.VerticalOffset + _ScrollY);
    19                 }), null);
    20                 Thread.Sleep(100);
    21             }
    22         }
    23 
    24     // 横向
    25     private void ScrollXMethod()
    26         {
    27             double endOffset = 0;
    28             if (_ScrollX < 0)       // 向左滚动
    29                 endOffset = 0;
    30             else                    // 向右滚动
    31                 ScrollViewer.Dispatcher.Invoke((Action)(() => endOffset = ScrollViewer.ScrollableWidth), null);
    32             // 初始位置
    33             double offset = 0;
    34             ScrollViewer.Dispatcher.Invoke((Action)(() => offset = ScrollViewer.HorizontalOffset), null);
    35             // 开始滚动
    36             while (offset != endOffset && _ScrollX != 0)
    37             {
    38                 ScrollViewer.Dispatcher.Invoke((Action)(() =>
    39                 {
    40                     offset = ScrollViewer.HorizontalOffset;
    41                     ScrollViewer.ScrollToHorizontalOffset(ScrollViewer.HorizontalOffset + _ScrollX);
    42                 }), null);
    43                 Thread.Sleep(100);
    44             }
    45         }
    

      当然绝不要忘,把“_ScrollYAction = ScrollYMethod;”,“_ScrollXAction

    ScrollXMethod;”这两条委托先河化语句放到PART_ContentHost_Initialized事件管理函数中去,不然就白写了。

      至此,难题2也改进完成。

      标题3:自动滚动到底层

      实则这不是主题材料,而是二个修正,因为平日的滚动条都并未有这些效用。在实用中,借使音信是不停地填写到音信框中,理想中应有是当拖动滚动条时,不会自行把滚动条更新到近来的一条新闻,而是锁定到拖动的职位(因为自己想看的是拖动到的音讯)。其余,要是想实时看新新闻,就须求活动滚动到最尾部。

      消除方式:

      当滚动条拖动到最底部时,就打开自动滚动,每来一条新音信都滚动一次到最尾部。要是滚动条不在最底部就毫无自动滚动。达成情势正是为Text博克斯增多TextChanged="TextBox_TextChanged"事件,以判别是或不是须求滚动:

    1         private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
    2         {
    3             if (this.Text != "" && ScrollViewer != null)
    4             {
    5                 // 如果已经拖到最底端,则固定住
    6                 if (ScrollViewer.ScrollableHeight == ScrollViewer.VerticalOffset)
    7                     ScrollViewer.ScrollToBottom();
    8             }
    9         }
    

      终于码完字了,多想只贴代码啊。放个图,大家看看啊:

    澳门新葡萄京娱乐场 19

      请无视上边的特别赫色横条,这是本身此外一个顺序中的GridSplitter。那么些自定义控件除了援助TextBox的装有属性外,仍能更正配色(使用公开的性质),此外还应该有一点击清空、关闭开关的操作完成都轻便,不贴了,感兴趣的下载源代码看看吧。

      源代码:ScrollTest.rar

      转发请注解原址:http://www.cnblogs.com/lekko/archive/2013/02/27/2935022.html 

    本文由澳门新葡8455最新网站发布于编程教学,转载请注明出处:包含惯性的ScrollViewer

    关键词: