如何将命令绑定到RichTextBox嵌套ScrollBar的Scroll事件?
问题分析
你当前的代码无效的核心原因是:你在FlowDocument的Paragraph中手动添加的ScrollBar和RichTextBox自带的滚动条完全无关。RichTextBox的滚动条是内置在它的ControlTemplate里的(对应模板中的PART_ContentHost,一个ScrollViewer控件),你手动添加的这个ScrollBar只是一个独立的UI元素,不会响应RichTextBox的滚动操作,所以绑定的命令自然不会触发。
RichTextBox 解决方案(MVVM+Interactivity)
要绑定RichTextBox内部滚动条的滚动事件到命令,最可靠的方式是自定义一个Behavior,通过它找到RichTextBox模板中的ScrollViewer,并订阅其ScrollChanged事件来触发命令:
1. 自定义 Behavior 类
using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; using System.Windows.Input; namespace YourNamespace { public class RichTextBoxScrollBehavior : Behavior<RichTextBox> { public static readonly DependencyProperty ScrollCommandProperty = DependencyProperty.Register( nameof(ScrollCommand), typeof(ICommand), typeof(RichTextBoxScrollBehavior)); public ICommand ScrollCommand { get => (ICommand)GetValue(ScrollCommandProperty); set => SetValue(ScrollCommandProperty, value); } protected override void OnAttached() { base.OnAttached(); AssociatedObject.TemplateApplied += OnTemplateApplied; if (AssociatedObject.Template != null) HookScrollViewer(); } private void OnTemplateApplied(object sender, RoutedEventArgs e) { HookScrollViewer(); } private void HookScrollViewer() { if (AssociatedObject.Template.FindName("PART_ContentHost", AssociatedObject) is ScrollViewer scrollViewer) { scrollViewer.ScrollChanged += OnScrollChanged; } } private void OnScrollChanged(object sender, ScrollChangedEventArgs e) { ScrollCommand?.Execute(e); } protected override void OnDetaching() { base.OnDetaching(); if (AssociatedObject.Template.FindName("PART_ContentHost", AssociatedObject) is ScrollViewer scrollViewer) { scrollViewer.ScrollChanged -= OnScrollChanged; } AssociatedObject.TemplateApplied -= OnTemplateApplied; } } }
2. XAML 中使用 Behavior
确保已引入Interactivity命名空间和自定义Behavior的命名空间:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:local="clr-namespace:YourNamespace"
然后修改RichTextBox的XAML:
<RichTextBox> <i:Interaction.Behaviors> <local:RichTextBoxScrollBehavior ScrollCommand="{Binding UpdateText}" /> </i:Interaction.Behaviors> <RichTextBox.Document> <FlowDocument> <Paragraph> <Run Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=LostFocus}" /> </Paragraph> </FlowDocument> </RichTextBox.Document> </RichTextBox>
普通 TextBox 解决方案
普通TextBox的模板中同样包含名为PART_ContentHost的ScrollViewer,所以可以复用类似的思路,只需要将Behavior的泛型类型改为TextBox:
自定义 TextBoxScrollBehavior
using System.Windows; using System.Windows.Controls; using System.Windows.Interactivity; using System.Windows.Input; namespace YourNamespace { public class TextBoxScrollBehavior : Behavior<TextBox> { public static readonly DependencyProperty ScrollCommandProperty = DependencyProperty.Register( nameof(ScrollCommand), typeof(ICommand), typeof(TextBoxScrollBehavior)); public ICommand ScrollCommand { get => (ICommand)GetValue(ScrollCommandProperty); set => SetValue(ScrollCommandProperty, value); } protected override void OnAttached() { base.OnAttached(); AssociatedObject.TemplateApplied += OnTemplateApplied; if (AssociatedObject.Template != null) HookScrollViewer(); } private void OnTemplateApplied(object sender, RoutedEventArgs e) { HookScrollViewer(); } private void HookScrollViewer() { if (AssociatedObject.Template.FindName("PART_ContentHost", AssociatedObject) is ScrollViewer scrollViewer) { scrollViewer.ScrollChanged += OnScrollChanged; } } private void OnScrollChanged(object sender, ScrollChangedEventArgs e) { ScrollCommand?.Execute(e); } protected override void OnDetaching() { base.OnDetaching(); if (AssociatedObject.Template.FindName("PART_ContentHost", AssociatedObject) is ScrollViewer scrollViewer) { scrollViewer.ScrollChanged -= OnScrollChanged; } AssociatedObject.TemplateApplied -= OnTemplateApplied; } } }
XAML 使用
<TextBox> <i:Interaction.Behaviors> <local:TextBoxScrollBehavior ScrollCommand="{Binding UpdateText}" /> </i:Interaction.Behaviors> <TextBox.Text> <Binding Path="Text" Mode="TwoWay" UpdateSourceTrigger="LostFocus" /> </TextBox.Text> </TextBox>
内容的提问来源于stack exchange,提问作者JoJo
相关产品推荐
相关产品推荐

