【WPF实现RichTextBox添加文本、自动滚动】

前言

使用WPF 中的RichTextBox控件实现添加文本后自动滚动末尾。因为RichTextBox无法直接绑定数据,所以通过引用System.Windows.Interactivity实现(System.Windows.Interactivity.WPF)

代码

MainWindow.xaml

csharp 复制代码
<Window x:Class="WPF_MvvmDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:behavior="clr-namespace:WPF_MvvmDemo" 
        xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="50"/>
        </Grid.RowDefinitions>
        <RichTextBox Name="OutputListBox" Grid.Row="0"  
                     Margin="5" Background="#FFFFFF" Focusable="True" 
                     VerticalScrollBarVisibility="Auto">
            <!--数据绑定-->
            <i:Interaction.Behaviors>
                <behavior:RichTextBoxBehavior Document="{Binding RichTextContent, Mode=TwoWay}" />
            </i:Interaction.Behaviors>
            <!--自动滚动-->
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="TextChanged">
                    <ei:CallMethodAction MethodName="ScrollToEnd" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </RichTextBox>
       
        <Button  Grid.Row="2" Width="150" Margin="5" HorizontalAlignment="Right"
                 Command="{Binding AppendTextCommand}">AddText</Button>
    </Grid>
</Window>

MainWindow

csharp 复制代码
public partial class MainWindow : Window
{
    MainViewModel viewModel;
    public MainWindow()
    {
        InitializeComponent();
        viewModel=new MainViewModel();
        this.DataContext = viewModel;
    }
}

RelayCommand

csharp 复制代码
public class RelayCommand : ICommand
{
    public Action<string> execute;

    public RelayCommand(Action<string> execute)
    {
        this.execute = execute;
    }

    public event EventHandler? CanExecuteChanged;

    public bool CanExecute(object? parameter)
    {
        return CanExecuteChanged!=null;
    }

    public void Execute(object? parameter)
    {
        execute?.Invoke(parameter?.ToString());
    }
}

RichTextBoxBehavior

csharp 复制代码
/// <summary>
///RichTextBox 的 Document 属性不是一个依赖属性(DependencyProperty),因此不能直接进行双向数据绑定。
///我们需要使用一种间接的方式来实现数据绑定。
///解决方案:
///使用 Behavior 来实现 RichTextBox 的数据绑定。Behavior 是一个附加行为,可以在 XAML 中使用,
///通过代码来实现复杂的行为逻辑。
/// </summary>
public class RichTextBoxBehavior : Behavior<RichTextBox>
{
    public static readonly DependencyProperty DocumentProperty =
        DependencyProperty.Register("Document", typeof(FlowDocument), typeof(RichTextBoxBehavior),
            new FrameworkPropertyMetadata(null, OnDocumentChanged));

    public FlowDocument Document
    {
        get { return (FlowDocument)GetValue(DocumentProperty); }
        set { SetValue(DocumentProperty, value); }
    }

    private static void OnDocumentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var behavior = d as RichTextBoxBehavior;
        if (behavior != null)
        {
            behavior.UpdateRichTextBox((FlowDocument)e.NewValue);
        }
    }

    protected override void OnAttached()
    {
        base.OnAttached();
        AssociatedObject.Loaded += OnLoaded;
        AssociatedObject.TextChanged += OnTextChanged;
    }

    protected override void OnDetaching()
    {
        base.OnDetaching();
        AssociatedObject.Loaded -= OnLoaded;
        AssociatedObject.TextChanged -= OnTextChanged;
    }

    private void OnLoaded(object sender, RoutedEventArgs e)
    {
        UpdateRichTextBox(Document);
    }

    private void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        Document = AssociatedObject.Document;
    }

    private void UpdateRichTextBox(FlowDocument document)
    {
        if (document != null && AssociatedObject.Document != document)
        {
            AssociatedObject.Document = document;
        }
    }
}

运行结果

相关推荐
绿龙术士1 天前
构建现代化WPF应用:数据驱动开发与高级特性解析
c#·wpf
wangnaisheng3 天前
【WPF】Opacity 属性的使用
wpf
姬激薄3 天前
配置Hadoop集群-集群配置
wpf
python算法(魔法师版)3 天前
.NET 在鸿蒙系统上的适配现状
华为od·华为·华为云·.net·wpf·harmonyos
大道随心3 天前
【wpf】11 在WPF中实现父窗口蒙版效果:原理详解与进阶优化
wpf
zizisuo4 天前
9.1.领域驱动设计
wpf
大道随心4 天前
【wpf】10 C#树形控件高效实现:递归构建与路径查找优化详解
开发语言·c#·wpf
离歌漠4 天前
WPF内嵌其他进程的窗口
c#·wpf
沉到海底去吧Go5 天前
【身份证识别表格】批量识别身份证扫描件或照片保存为Excel表格,怎么大批量将身份证图片转为excel表格?基于WPF和腾讯OCR的识别方案
ocr·wpf·excel·身份证识别表格·批量扫描件身份证转表格·图片识别表格·图片识别excel表格
csdn_aspnet5 天前
WPF 性能 UI 虚拟化 软件开发人员的思考
ui·wpf