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

运行结果

相关推荐
软泡芙17 小时前
【WPF 】MVVM 设计模式在 WPF 中的实战应用
设计模式·wpf
张小俊_18 小时前
WPF 跨线程 UI 更新与硬编码赋值引发的 Bug 排查
c#·bug·wpf
七夜zippoe2 天前
DolphinDB在工业物联网中的优势
物联网·wpf·工业物联网·优势·dolphindb
heimeiyingwang2 天前
【架构实战】观察者模式在分布式系统中的应用
观察者模式·架构·wpf
bugcome_com2 天前
WPF + Microsoft.ToolKit.Mvvm 技术指南与实战项目
microsoft·wpf
武藤一雄3 天前
WPF中逻辑树(Logical Tree)与可视化树(Visual Tree)到底是什么
microsoft·c#·.net·wpf·.netcore
炸炸鱼.3 天前
ELK 企业级日志分析系统完整部署手册
elk·wpf
Mr_pyx4 天前
微服务可观测性实战:分布式链路追踪从入门到精通
wpf
c#上位机5 天前
wpf附加事件
wpf
玖笙&5 天前
✨WPF编程进阶【9.1】:WPF资源完全指南(附源码)
c++·c#·wpf·visual studio