WPF实现滚动条只要在控件外围加上ScrollViewer即可,但是滚动的时候没有动画效果,比较生硬,在滚动的时候添加过渡动画实现平滑滚动能给我们的软件增色不少。
接下来,在上一篇博客(WPF使用FlowDocument加载文本并修改文本样式https://blog.csdn.net/dnazhd/article/details/89307386)的基础上进行修改,这里只展示垂直滚动效果,水平滚动方式同理。为了更加明显的展示效果,先将协议文本内容添加的更多些。
原始滚动效果:
修改后效果:
修改流程:
1.新建SmoothScroll文件夹,并新建SmoothScrollViewer.cs类,继承自ScrollViewer,注册步进长度依赖属性,代码如下:
using System.Windows;
using System.Windows.Controls;
namespace RichTextBoxDemo.SmoothScroll
{
public class SmoothScrollViewer : ScrollViewer
{
///
/// 垂直归一化步进长度
///
public double VerticalScrollRatio
{
get { return (double)GetValue(VerticalScrollRatioProperty); }
set { SetValue(VerticalScrollRatioProperty, value); }
}
//注册VerticalScrollRatio依赖属性
public static readonly DependencyProperty VerticalScrollRatioProperty =
DependencyProperty.Register("VerticalScrollRatio", typeof(double), typeof(SmoothScrollViewer), new PropertyMetadata(0.0, new PropertyChangedCallback(V_ScrollRatioChangedCallBack)));
private static void V_ScrollRatioChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = (ScrollViewer)(d);
if (scrollViewer != null)
{
scrollViewer.ScrollToVerticalOffset((double)(e.NewValue) * scrollViewer.ScrollableHeight);
}
}
///
/// 水平归一化步进长度
///
public double HorizontalScrollRatio
{
get { return (double)GetValue(HorizontalScrollRatioProperty); }
set { SetValue(HorizontalScrollRatioProperty, value); }
}
//注册HorizontalScrollRatio依赖属性
public static readonly DependencyProperty HorizontalScrollRatioProperty =
DependencyProperty.Register("HorizontalScrollRatio", typeof(double), typeof(SmoothScrollViewer), new PropertyMetadata(0.0, new PropertyChangedCallback(H_ScrollRatioChangedCallBack)));
private static void H_ScrollRatioChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var scrollViewer = (ScrollViewer)(d);
if (scrollViewer != null)
{
scrollViewer.ScrollToHorizontalOffset((double)(e.NewValue) * scrollViewer.ScrollableWidth);
}
}
}
}
2、在SmoothScroll文件夹,新建ScrollViewerExtend.cs类,实现平滑滚动功能,代码如下:
using System;
using System.Windows;
using System.Windows.Media.Animation;
namespace RichTextBoxDemo.SmoothScroll
{
public static class ScrollViewerExtend
{
///
/// 实现ScrollViewer的平滑滚动
///
///
/// 归一化步进长度
/// 归一化位置
/// 滚动方向
public static void SmoothScroll(this SmoothScrollViewer scrollViewer, double ScrollStepRatio, double ScrollPositionRatio, ScrollDirection direction)
{
if (double.IsNaN(ScrollStepRatio) || double.IsNaN(ScrollPositionRatio))
return;
DoubleAnimation Animation = new DoubleAnimation();
Animation.From = ScrollPositionRatio;
if (ScrollDirection.Down == direction || ScrollDirection.Right == direction)
{
double To = ScrollPositionRatio + ScrollStepRatio;
Animation.To = To > 0.95 ? 1.0 : To;//向下(右)滚动补偿
}
else if (ScrollDirection.Up == direction || ScrollDirection.Left == direction)
{
double To = ScrollPositionRatio - ScrollStepRatio;
Animation.To = To < 0.05 ? 0.0 : To;//向上(左)滚动补偿
}
Animation.Duration = new Duration(TimeSpan.FromMilliseconds(500));
Storyboard storyboard = new Storyboard();
storyboard.Children.Add(Animation);
Storyboard.SetTarget(Animation, scrollViewer);
if (ScrollDirection.Down == direction || ScrollDirection.Up == direction)
Storyboard.SetTargetProperty(Animation, new PropertyPath(SmoothScrollViewer.VerticalScrollRatioProperty));
else if (ScrollDirection.Right == direction || ScrollDirection.Left == direction)
Storyboard.SetTargetProperty(Animation, new PropertyPath(SmoothScrollViewer.HorizontalScrollRatioProperty));
storyboard.Begin();
}
}
public enum ScrollDirection
{
Up, Down, Left, Right
}
}
3、主界面:
4、交互逻辑:
using RichTextBoxDemo.SmoothScroll;
using System;
using System.IO;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;
namespace RichTextBoxDemo
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
double m_ScrollStepRatio = 0.0; //滚动条的归一化步进长度
double m_ScrollPositionRatio = 0.0; //滚动条的归一化位置
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
LoadDocument();
}
///
/// 加载txt文本
///
private void LoadDocument()
{
string filePath = AppDomain.CurrentDomain.BaseDirectory + @"Disclaimer\Disclaimer.txt";//文件路径
if(File.Exists(filePath))
{
FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);//以只读方式打开源文件
try
{
using (StreamReader sr = new StreamReader(fs))
{
FlowDocument document = new FlowDocument();//承载文件内容
string content = sr.ReadToEnd();
string[] split = content.Split(new char[2] { '\r', '\n' });
foreach (string para in split)
{
if(para != "")
{
Paragraph paragraph = new Paragraph(new Run(para));
paragraph.FontFamily = new FontFamily("微软雅黑");//修改样式
paragraph.Foreground = new SolidColorBrush(Colors.Black);
if (para == "免责声明")
{
paragraph.FontSize = 26;
paragraph.TextAlignment = TextAlignment.Center;
}
else
paragraph.FontSize = 20;
document.Blocks.Add(paragraph);
}
}
this.showInfo.Document = document;
}
}
catch (Exception ex)
{
}
finally
{
fs.Close();
}
}
}
private void scrollviewer_ScrollChanged(object sender, System.Windows.Controls.ScrollChangedEventArgs e)
{
m_ScrollStepRatio = scrollviewer.ViewportHeight / (scrollviewer.ExtentHeight - scrollviewer.ViewportHeight);
m_ScrollPositionRatio = scrollviewer.ContentVerticalOffset / scrollviewer.ScrollableHeight;
if (e.VerticalChange < 0)
scrollviewer.SmoothScroll(m_ScrollStepRatio, m_ScrollPositionRatio, ScrollDirection.Up);
else if (e.VerticalChange > 0)
scrollviewer.SmoothScroll(m_ScrollStepRatio, m_ScrollPositionRatio, ScrollDirection.Down);
}
}
}