0

在我开始解释我的问题之前,请注意我的目标框架是 .NET 3.5。

我有一个文本框,其文本绑定到 viewmodel 属性。我的要求是,当用户在文本框中输入内容(通过键盘和鼠标粘贴)时,应清除其中的任何垃圾字符,并应使用替换的字符串更新文本框[在下面的示例中,“s”将被替换'h']。

XAML代码:

 <Style x:Key="longTextField" TargetType="{x:Type TextBoxBase}">
            <Setter Property="SnapsToDevicePixels" Value="True"/>
            <Setter Property="OverridesDefaultStyle" Value="True"/>
            <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
            <Setter Property="AcceptsReturn" Value="True"/>
            <Setter Property="AllowDrop" Value="true"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TextBoxBase}">
                        <Border      
                      Name="Border"    
                      Padding="2"    
                      Background="Transparent"    
                      BorderBrush="LightGray"    
                      BorderThickness="1">
                            <ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsEnabled" Value="False">
                                <Setter Property="Foreground" Value="Black"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
 <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding Value, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True}"  MinLines="3"       TextWrapping="Wrap"
                 SpellCheck.IsEnabled="True" Style="{StaticResource longTextField}"></TextBox>

视图模型属性:

     private string _value;
            public string Value
            {
                get
                {
                    return _value;
                }
                set
                {
                    if (_value == value) 
                        return;

                    _value = value;
//replaces 's' with 'h' and should update the textbox.
                    _value = _value.Replace('s','h');
                    RaisePropertyChanged(() => Value);
                }
            }

以上内容根本不适合我。视图模型属性设置器正在触发......该值正在被替换......但是文本框没有得到更新。令人困惑的是,这在 .Net4.0 上完美运行。

您知道为什么这不起作用吗?除了升级到 .NET 4.0 之外,还有什么潜在的解决方案可以解决这个问题?

我的要求:

  • 用户可以键入以及将任何内容粘贴到多行文本框中。

  • 文本可以包含垃圾,应该在它进入文本框之前进行更改。

在此先感谢,-迈克

4

1 回答 1

6

我遇到了一个非常相似的问题,我想要双向绑定,我正在修改 ViewModel 中的值并希望在 TextBox 中看到更新。我能够解决它。虽然我使用的是 .NET 4.0,但我基本上遇到了同样的问题,因此对于 3.5 的情况,这可能也值得尝试。

简短的回答:

我遇到的是一个错误,TextBox's显示的文本与该属性的值不TextBox's同步TextMeleak 对类似问题的回答使我了解了这一点,我能够使用 Visual Studio 2010 中的调试器以及使用 Meleak 的TextBlock技术来验证这一点。

我能够通过使用显式绑定来解决它。这需要自己在后面的代码中处理UpdateSource()UpdateTarget()问题(或者在自定义控制代码中,因为我最终这样做以使其更容易重用)。

进一步说明:

以下是我处理显式绑定任务的方式。首先,我有一个用于更新绑定源的 TextChanged 事件的事件处理程序:

// Push the text in the textbox to the bound property in the ViewModel
textBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();

其次,我有一个 TextBox 的 Loaded 事件的事件处理程序。在那个处理程序中,我为我的 ViewModel 的 PropertyChanged 事件注册了一个处理程序(这里的 ViewModel 是“DataContext”):

private void ExplicitBindingTextBox_Loaded(object sender, RoutedEventArgs e)
{
    TextBox textBox = sender as TextBox;

    if (textBox.DataContext as INotifyPropertyChanged == null)
        throw new InvalidOperationException("...");

    (textBox.DataContext as INotifyPropertyChanged).PropertyChanged +=
                  new PropertyChangedEventHandler(ViewModel_PropertyChanged);
}

最后,在 PropertyChanged 处理程序中,我使 TextBox 从 ViewModel 中获取值(通过启动 UpdateTarget())。 这使得 TextBox 从 ViewModel 中获取修改后的字符串(在您的情况下,是带有替换字符的字符串)。在我的情况下,我还必须在刷新文本后(来自 UpdateTarget())处理恢复用户的插入符号位置。不过,该部分可能适用于您的情况,也可能不适用于您的情况。

    /// <summary>
    /// Update the textbox text with the value that is in the VM.
    /// </summary>
    void ViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        // This textbox only cares about the property it is bound to
        if (e.PropertyName != MyViewModel.ValueStrPropertyName)
            return;

        // "this" here refers to the actual textbox since I'm in a custom control
        //  that derives from TextBox
        BindingExpression bindingExp = this.GetBindingExpression(TextBox.TextProperty);
        // the version that the ViewModel has (a potentially modified version of the user's string)
        String viewModelValueStr;

        viewModelValueStr = (bindingExp.DataItem as MyViewModel).ValueStr;


        if (viewModelValueStr != this.Text)
        {
            // Store the user's old caret position (relative to the end of the str) so we can restore it
            //  after updating the text from the ViewModel's corresponding property.
            int oldCaretFromEnd = this.Text.Length - this.CaretIndex;

            // Make the TextBox's Text get the updated value from the ViewModel
            this.GetBindingExpression(TextBox.TextProperty).UpdateTarget();

            // Restore the user's caret index (relative to the end of the str)
            this.CaretIndex = this.Text.Length - oldCaretFromEnd;
        }

    }
于 2013-01-31T15:51:18.097 回答