当视图模型更新其绑定属性时,需要将插入符号移动到文本框的末尾

问题描述

我正在努力为我们遇到的一个烦人的问题找到一个好的解决方案。我们在 WPF 应用程序中有一个多行文本框,使用 MvvmLight 来实现 MVVM 设计模式。文本框通过双向绑定绑定到视图模型中的属性。最终用户和视图模型都可以更新绑定属性。每当视图模型更新绑定属性时,都会引发 NotifyPropertyChanged 事件(通过 MvvmLight Set() 方法。)发生这种情况时,文本框会正确更新,但插入符号会移动到文本的前面。我们在视图模型中有一个方法调用代码隐藏中具有事件处理程序的事件。事件处理程序将插入符号移动到文本的末尾。问题是,在整个代码中有很多地方我们必须记住才能执行该方法。在我看来,每次引发 NotifyPropertyChanged 事件时,都应该有一种方法让视图自动将插入符号移动到末尾。我找到了一个 12 岁的例子,它可以满足我的要求here。但我遇到了冲突。我们的视图这样定义了 DataContext:

<UserControl x:Class="CaptionNet.Wpf.Captioning.CaptioningView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:CaptionNet.Wpf.Captioning"
         d:DataContext="{Binding Captioningviewmodel,Source={StaticResource Locator}}"
         DataContext="{Binding Captioningviewmodel,Source={StaticResource Locator}}"
         xmlns:dp="clr-namespace:CaptionNet.Wpf.DependencyProperties"
         xmlns:cmd="http://www.galasoft.ch/mvvmlight"
         xmlns:interactivity="http://schemas.microsoft.com/expression/2010/interactivity"
         mc:Ignorable="d" 
         d:DesignHeight="500" d:DesignWidth="500"
         AutomationProperties.AutomationId="CaptioningPane">

示例代码以这种方式定义了 DataContext:

<UserControl.DataContext>
    <local:Captioningviewmodel CaptionsChanged="ScrollToEnd" />
</UserControl.DataContext>

CaptionsChanged 事件在 Captioningviewmodel 中定义。 ScrollToEnd 是后端定义的事件处理程序。

我只能以一种方式定义 DataContext。无论是原始方式还是示例方式,但不能两者兼而有之。如果我使用原始方式,我无法弄清楚如何将 ScrollToEnd 事件处理程序订阅到 CaptionsChanged 事件。如果我使用示例的方式,我无法弄清楚如何将 datacontext 绑定到 Captioningviewmodel。我已经搜索了一整天,一直无法弄清楚这一点。您的帮助将不胜感激。

解决方法

在 TextBox.CaretIndex 上添加绑定。

,

由于我们已经有一种方法可以在用户在文本中间的某处键入内容后强制插入符号到文本的末尾,所以我真正需要的是一种方法来使插入符号移动到文本的末尾视图模型更新绑定属性时的文本。我能够通过在文本框绑定中将 NotifyonTargetUpdated 设置为 true,然后将 TargetUpdatad 事件添加到文本框来完成此操作。在事件处理程序中,我将插入符号位置设置为文本的末尾并在文本框上调用 Keyboard.Focus()。

<TextBox
             Text="{Binding Captions,UpdateSourceTrigger=PropertyChanged,NotifyOnTargetUpdated=true}" 
             Name="CaptionTextBox" 
             AutomationProperties.AutomationId="CaptioningTextBox"
             Margin="20"
             BorderThickness="0"
             SelectionChanged="CaptionTextBox_SelectionChanged"
             PreviewKeyDown="CaptionTextBox_PreviewKeyDown"
             MouseRightButtonUp="CaptionTextBox_MouseRightButtonUp"
             AcceptsReturn="True" 
             TextWrapping="Wrap"
             FontSize="{DynamicResource CaptionFontSize}"
             Background="{DynamicResource FontBackgroundColor}"
             Foreground="{DynamicResource FontForegroundColor}"
             VerticalScrollBarVisibility="Hidden" 
             HorizontalScrollBarVisibility="Disabled"
             IsEnabled="{Binding IsEnabled}"
             AllowDrop="False"
             TextChanged="CaptionTextBox_TextChanged"
             Focusable="True"
            TargetUpdated="CaptionTextBox_TargetUpdated"

然后在代码隐藏中:

    private void CaptionTextBox_TargetUpdated(object sender,System.Windows.Data.DataTransferEventArgs e)
    {
        CaptionTextBox.SelectionLength = 0;
        CaptionTextBox.Select(CaptionTextBox.Text.Length,0);
        Keyboard.Focus(CaptionTextBox);
    }