带有惯性的ScrollViewer

2019-11-14 17:06 来源:未知

大器晚成、先看看效果

  寒假过完,在家真心什么都做不了,可能老了,再想早先那样能全力以赴坐下来已经极度了。回来第意气风发件事就是改了品种的一个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"卡塔 尔(英语:State of Qatar)的ScrollBar来表示。

 

  然后,分别自定义ScrollBar的样式。以竖向滚动条为例,自定义ControlTemplate,使用Grid作为容器,把滚动条分为三行,第风流倜傥作为升高开关、第二作为滚动条、第三行事向下按键。小编这里由于雅观思量,把四个按键全省略了(实际上大家超级少使用按键来上下滚动,超越50%时候用的鼠标中轮和拖动滑块卡塔 尔(阿拉伯语:قطر‎。

  滚动条是应用的Track控件,它又富含多少个区域,分别是空中白、滑块、下空白,大家来看个示例图:

金沙澳门登陆网站 12

 

  Track的DecreaseRepeatButton正是空间白、Thumb则是滑块、IncreaseRepeatButton是下空白,分别对那三个控件举行体制自定义就可以改造其外观。要求证实的是竖向滚动条须求把Track的IsDirectionReversed属性设置为True,横向则设置为False,不然会身不由己格外奇怪的情景(原因嘛,我们看属性名的乐趣就领会了卡塔 尔(英语:State of Qatar)。

  最后,还应该有一点要解释一下,我们开采许多控件有接近于“PART_***”的名称,这么些名称请不要随便变动,那是WPF内置的非正规名称,比方ScrollViewer的“PART_ContentHost”名称,便是象征那几个控件是用来装载TextBox的文书内容的,並且通过测验,这一个称谓只可以用来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,引致这些通用成效也亟需团结达成了。

  消除办法:

  首先,给前台的最上层成分Text博克斯增多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         }

  说惠氏(WYETH卡塔尔国下,_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:自动滚动到底层

  骨子里那小难题,而是八个更上大器晚成层楼,因为相同的滚动条都未有这几个职能。在实用中,假设消息是不停地填写到消息框中,理想中应有是当拖动滚动条时,不会自动把滚动条更新到近日的一条音讯,而是锁定到拖动的职位(因为本人想看的是拖动到的音信卡塔 尔(阿拉伯语:قطر‎。其它,如果想实时看新新闻,就供给活动滚动到最尾巴部分。

  化解方式:

  当滚动条拖动到最头部时,就张开自动滚动,每来一条新新闻都滚动贰回到最底部。借使滚动条不在最底部就毫无自动滚动。达成方式便是为TextBox增多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 

TAG标签:
版权声明:本文由金沙澳门唯一官网发布于编程教学,转载请注明出处:带有惯性的ScrollViewer