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

运行结果

相关推荐
光辉岁月~7 小时前
使用CalcBinding实现复杂逻辑绑定
wpf
SunflowerCoder17 小时前
WPF迁移avalonia之触发器
c#·wpf·avalonia
主宰者17 小时前
【WPF+Prism】日常开发问题总结
wpf
~空中楼阁1 天前
WPF WriteableBitmap 高性能双缓冲图片显示方案
wpf
I'mSQL2 天前
WPF资源字典合并报错
wpf
one9962 天前
WPF应用程序中的异常处理
c#·.net·wpf
somethingGoWay3 天前
wpf .netcore 导出docx文件
wpf·.netcore
somethingGoWay3 天前
wpf .netcore 导出pdf文件
pdf·wpf·.netcore
self_myth4 天前
[特殊字符] 深入理解操作系统核心特性:从并发到分布式,从单核到多核的全面解析
windows·macos·wpf·harmonyos
c#上位机4 天前
wpf之TextBlock
c#·wpf