问题描述
在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();
}
}
你期待的结果是什么?实际看到的错误信息又是什么?
我希望:
- MainWindowVM()中代码能够有效。结果:有效。
- 我希望Button控件的 ClarReceData() 函数能够在TextBox有文本数据时实现执行有效,即清除TextBox控件的数据。结果:数据依然存在(无效)
修正Append的接口实现即可。
问题是由跨线程操作引起的,交由线程委托操作即可。