MVVM模型下如何在TextBox控件中实现追加文本及清除数据?

问题描述

在WPF架构使用MVVM模型进行开发,在使用TextBox控件中无法实现数据的追加,数据的清除。

问题出现的环境背景及自己尝试过哪些方法

Stack Overflow 中的问题 MVVM: How to make a function call on a control? 找到了部分解决方法,实现了文本的追加和清除。但通过Button按钮却无法清除数据(详细内容请看相关代码与期待的结果)。

相关代码

  • 定义接口
public interface ITextBoxAppend
{
    void Delete();
    void Delete(int startIndex, int length);

    void Append(string value);
    void Append(string value, int index);

    string GetCurrentValue();

    event EventHandler<string> BufferAppendedHandler;
}
  • 实现接口
    class IClassTextBoxAppend : ITextBoxAppend
    {
        private readonly StringBuilder _buffer = new StringBuilder();

        public void Delete()
        {
            _buffer.Clear();
        }

        public void Delete(int startIndex, int length)
        {
            _buffer.Remove(startIndex, length);
        }

        public void Append(string value)
        {
            _buffer.Append(value);

            BufferAppendedHandler?.Invoke(this, value);
        }

        public void Append(string value, int index)
        {
            if (index== _buffer.Length)
            {
                _buffer.Append(value);
            }
            else
            {
                _buffer.Insert(index, value);
            }
        }

        public string GetCurrentValue()
        {
            return _buffer.ToString();
        }

        public event EventHandler<string> BufferAppendedHandler;
    }
  • 封装附加属性
    public class MvvmTextBox
    {
        public static readonly DependencyProperty BufferProperty =
            DependencyProperty.RegisterAttached(
                "Buffer",
                typeof(ITextBoxAppend),
                typeof(MvvmTextBox),
                new UIPropertyMetadata(null, PropertyChangedCallback)
            );

        private static void PropertyChangedCallback(
            DependencyObject dependencyObject,
            DependencyPropertyChangedEventArgs depPropChangedEvArgs)
        {
            // todo: unrelease old buffer.
            var textBox = (TextBox)dependencyObject;
            var textBuffer = (ITextBoxAppend)depPropChangedEvArgs.NewValue;

            var detectChanges = true;

            textBox.Text = textBuffer.GetCurrentValue();
            textBuffer.BufferAppendedHandler += (sender, appendedText) =>
            {
                detectChanges = false;
                textBox.AppendText(appendedText);
                detectChanges = true;
            };

            // todo: unrelease event handlers.
            textBox.TextChanged += (sender, args) =>
            {
                if (!detectChanges)
                    return;

                foreach (var change in args.Changes)
                {
                    if (change.AddedLength > 0)
                    {
                        var addedContent = textBox.Text.Substring(
                            change.Offset, change.AddedLength);

                        textBuffer.Append(addedContent, change.Offset);
                    }
                    else
                    {
                        textBuffer.Delete(change.Offset, change.RemovedLength);
                    }
                }

                Debug.WriteLine(textBuffer.GetCurrentValue());
            };
        }

        public static void SetBuffer(UIElement element, bool value)
        {
            element.SetValue(BufferProperty, value);
        }
        public static ITextBoxAppend GetBuffer(UIElement element)
        {
            return (ITextBoxAppend)element.GetValue(BufferProperty);
        }
    }
  • TextBox控件

在View中的代码:

<TextBox x:Name="ReceTextBox" local:MvvmTextBox.Buffer="{Binding ReceData}"/>

在ViewModel中的代码:

class MainWindowVM
{
    public ITextBoxAppend ReceData { get; set; }

    public MainWindowVM()
    {
        ReceData = new IClassTextBoxAppend();
        ReceData.Append("Test");
        ReceData.Delete();
    }
}
  • Button控件

在View中的代码:

<Button x:Name="ClearReceButton" Content="清空" Click="ClarReceData"/>

在ViewModel中的代码:

class MainWindowVM
{
    public void ClarReceData()
    {
        ReceData.Delete();
    }
}

你期待的结果是什么?实际看到的错误信息又是什么?

我希望:

  1. MainWindowVM()中代码能够有效。结果:有效。
  2. 我希望Button控件的 ClarReceData() 函数能够在TextBox有文本数据时实现执行有效,即清除TextBox控件的数据。结果:数据依然存在(无效)
阅读 5.9k
2 个回答

修正Append的接口实现即可。

public void Append(string value)
{
    _buffer.Append(value);

     App.Current.Dispatcher.Invoke((Action)(() =>
     {
           BufferAppendedHandler(this, value);
     }));
}

问题是由跨线程操作引起的,交由线程委托操作即可。

新手上路,请多包涵

解决如下

1.在接口处增加清空
public interface ITextBoxAppend
{
    void Delete();
    void Delete(int startIndex, int length);
    void Append(string value);
    void Append(string value, int index);

    string GetCurrentValue();

    /// <summary>
    /// Appended 事件
    /// </summary>
    event EventHandler<string> BufferAppendedHandler;

    /// <summary>
    /// 清空事件
    /// </summary>
    event EventHandler<string> BufferDeleteHandler;
}

2.在PropertyChangedCallback回调里注册事件并清空textBox
textBuffer.BufferDeleteHandler += (sender, args) =>
        {
            detectChanges = false;
            textBox.Clear();
            detectChanges = true;
        };
        
 3.在清空函数里触发事件
 public void Delete()
   {
        _buffer.Clear();
        System.Windows.Application.Current.Dispatcher?.Invoke(new Action(() =>
        {
            BufferDeleteHandler?.Invoke(this, null);
        }));
    }
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
logo
Microsoft
子站问答
访问
宣传栏