我试图限制用户可以在文本框中输入的行数.
我一直在研究 – 我能找到的最接近的是:
Limit the max number of chars per line in a textbox
而Limit the max number of chars per line in a textbox原来是winforms.
这不是我所追求的……还值得一提的是有一个误导性的maxlines属性我发现只限制了文本框中显示的内容.
我的要求:
>不要求使用单倍间距字体
>将文本框限制为最多包含5行
>接受回车
>不允许额外的回车
>达到最大长度时停止文本输入
>包装文字(不要特别小心,如果它在两个单词之间做这个或分解整个单词)
>处理粘贴到控件中的文本,并仅粘贴适合的内容.
>没有滚动条
>另外 – 这很好 – 可以选择限制每行的字符数
这些要求用于创建WYSIWYG文本框,该文本框将用于捕获最终将被打印的数据,并且字体需要更改 – 如果文本被切断或对于固定大小的行太大 – 那么它将会出现印刷方式(即使它看起来不正确).
我通过处理事件自己做了这件事 – 但是我很难做到这一点.到目前为止,这是我的代码.
XAML
<TextBox TextWrapping="Wrap" AcceptsReturn="True"
PreviewTextInput="UIElement_OnPreviewTextInput"
TextChanged="TextBoxBase_OnTextChanged" />
代码背后
public int TextBoxMaxAllowedLines { get; set; }
public int TextBoxMaxAllowedCharactersPerLine { get; set; }
public MainWindow()
{
InitializeComponent();
TextBoxMaxAllowedLines = 5;
TextBoxMaxAllowedCharactersPerLine = 50;
}
private void TextBoxBase_OnTextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = (TextBox)sender;
int textLineCount = textBox.LineCount;
if (textLineCount > TextBoxMaxAllowedLines)
{
StringBuilder text = new StringBuilder();
for (int i = 0; i < TextBoxMaxAllowedLines; i++)
text.Append(textBox.GetLineText(i));
textBox.Text = text.ToString();
}
}
private void UIElement_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
{
TextBox textBox = (TextBox)sender;
int textLineCount = textBox.LineCount;
for (int i = 0; i < textLineCount; i++)
{
var line = textBox.GetLineText(i);
if (i == TextBoxMaxAllowedLines-1)
{
int selectStart = textBox.SelectionStart;
textBox.Text = textBox.Text.TrimEnd('\r', '\n');
textBox.SelectionStart = selectStart;
//Last line
if (line.Length > TextBoxMaxAllowedCharactersPerLine)
e.Handled = true;
}
else
{
if (line.Length > TextBoxMaxAllowedCharactersPerLine-1 && !line.EndsWith("\r\n"))
e.Handled = true;
}
}
}
这不太正常 – 我在最后一行得到了奇怪的行为,文本框中的选定位置不断跳跃.
顺便说一句,也许我走错了轨道…我也想知道是否可以通过使用这样的东西使用正则表达式来实现:https://*.com/a/1103822/685341
我对任何想法持开放态度,因为我一直在努力解决这个问题.上面列出的要求是不可变的 – 我无法更改它们.
解决方法:
这是我的最终解决方案 – 我仍然想听听是否有人能想出更好的方法来做到这一点……
这只是处理最大行数 – 我还没有用最大字符做任何事情 – 但它在逻辑上是我已经完成的一个简单的扩展.
当我正在处理文本框的textChanged事件时 – 这也包括对控件的调整 – 我没有找到一种简洁的方法来截断此事件中的文本(除非我单独处理key_preview) – 所以我只是没有通过撤消允许无效输入.
XAML
<TextBox TextWrapping="Wrap" AcceptsReturn="True"
HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Disabled">
<i:Interaction.Behaviors>
<lineLimitingTextBoxWpfTest:LineLimitingBehavior TextBoxMaxAllowedLines="5" />
</i:Interaction.Behaviors>
</TextBox>
代码(行为)
/// <summary> limits the number of lines the textbox will accept </summary>
public class LineLimitingBehavior : Behavior<TextBox>
{
/// <summary> The maximum number of lines the textbox will allow </summary>
public int? TextBoxMaxAllowedLines { get; set; }
/// <summary>
/// Called after the behavior is attached to an AssociatedObject.
/// </summary>
/// <remarks>
/// Override this to hook up functionality to the AssociatedObject.
/// </remarks>
protected override void OnAttached()
{
if (TextBoxMaxAllowedLines != null && TextBoxMaxAllowedLines > 0)
AssociatedObject.TextChanged += OnTextBoxTextChanged;
}
/// <summary>
/// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
/// </summary>
/// <remarks>
/// Override this to unhook functionality from the AssociatedObject.
/// </remarks>
protected override void OnDetaching()
{
AssociatedObject.TextChanged -= OnTextBoxTextChanged;
}
private void OnTextBoxTextChanged(object sender, TextChangedEventArgs e)
{
TextBox textBox = (TextBox)sender;
int textLineCount = textBox.LineCount;
//Use Dispatcher to undo - https://*.com/a/25453051/685341
if (textLineCount > TextBoxMaxAllowedLines.Value)
Dispatcher.BeginInvoke(DispatcherPriority.Input, (Action) (() => textBox.Undo()));
}
}
这需要将System.Windows.InterActivity添加到项目中并在XAML中引用:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"