【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;
        }
    }
}

运行结果

相关推荐
无心水6 小时前
分布式定时任务与SELECT FOR UPDATE:从致命陷阱到优雅解决方案(实战案例+架构演进)
服务器·人工智能·分布式·后端·spring·架构·wpf
LZL_SQ8 小时前
HCCL测试框架中AllReduce边界条件测试设计深度剖析
wpf·cann
User_芊芊君子1 天前
【分布式训练】CANN SHMEM跨设备内存通信库:构建高效多机多卡训练的关键组件
分布式·深度学习·神经网络·wpf
就是有点傻2 天前
WPF按钮走马灯效果
wpf
zuozewei2 天前
虚拟电厂聚合商平台安全技术体系深度解读
安全·wpf
极客智造2 天前
WPF 自定义控件:AutoGrid 实现灵活自动布局的网格控件
wpf
极客智造2 天前
WPF Grid 布局高效扩展:GridHelpers 附加属性工具类全解析
wpf
张人玉2 天前
WPF 多语言实现完整笔记(.NET 4.7.2)
笔记·.net·wpf·多语言实现·多语言适配
暖馒2 天前
深度剖析串口通讯(232/485)
开发语言·c#·wpf·智能硬件
我要打打代码3 天前
WPF控件(2)
wpf