我在WPF中有一个TextBox
。我想限制TextBox
中文本的长度。通过属性MaxLength
可以轻松限制字符数。
在我的用例中,我需要限制文本而不是字符数,而是限制给定编码中文本的二进制表示的长度。由于德国人使用该程序,因此有一些变音,消耗两个字节。
我已经有了一个方法,检查给定的字符串是否适合给定的长度:
public bool IsInLength(string text, int maxLength, Encoding encoding)
{
return encoding.GetByteCount(text) < maxLength;
}
是否有人知道如何以某种方式将此功能绑定到文本框,用户无法输入太多字符以超过最大字节长度。
没有EventHandler的解决方案是首选,因为TextBox位于DataTemplate。
中答案 0 :(得分:4)
ValidationRule
可能适合这里的账单。这是一个示例实现:
public sealed class ByteCountValidationRule : ValidationRule
{
// For this example I test using an emoji () which will take 2 bytes and fail this rule.
static readonly int MaxByteCount = 1;
static readonly ValidationResult ByteCountExceededResult = new ValidationResult(false, $"Byte count exceeds the maximum allowed limit of {MaxByteCount}");
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
var val = value as string;
return val != null && Encoding.UTF8.GetByteCount(val) > MaxByteCount
? ByteCountExceededResult
: ValidationResult.ValidResult;
}
}
XAML使用:
<TextBox.Text>
<Binding Path="Text" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:ByteCountValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
现在你可以输入1个表情符号或2个ascii字符来触发失败(因为它们将超过1个字节的限制)。
答案 1 :(得分:-1)
我扩展了Alex Klaus的解决方案,以防止输入太长的文本。
public class TextBoxMaxLengthBehavior : Behavior<TextBox>
{
public static readonly DependencyProperty MaxLengthProperty =
DependencyProperty.Register(
nameof(MaxLength),
typeof(int),
typeof(TextBoxMaxLengthBehavior),
new FrameworkPropertyMetadata(0));
public int MaxLength
{
get { return (int) GetValue(MaxLengthProperty); }
set { SetValue(MaxLengthProperty, value); }
}
public static readonly DependencyProperty LengthEncodingProperty =
DependencyProperty.Register(
nameof(LengthEncoding),
typeof(Encoding),
typeof(TextBoxMaxLengthBehavior),
new FrameworkPropertyMetadata(Encoding.Default));
public Encoding LengthEncoding
{
get { return (Encoding) GetValue(LengthEncodingProperty); }
set { SetValue(LengthEncodingProperty, value); }
}
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewTextInput += PreviewTextInputHandler;
DataObject.AddPastingHandler(AssociatedObject, PastingHandler);
}
protected override void OnDetaching()
{
base.OnDetaching();
AssociatedObject.PreviewTextInput -= PreviewTextInputHandler;
DataObject.RemovePastingHandler(AssociatedObject, PastingHandler);
}
private void PreviewTextInputHandler(object sender, TextCompositionEventArgs e)
{
string text;
if (AssociatedObject.Text.Length < AssociatedObject.CaretIndex)
text = AssociatedObject.Text;
else
{
// Remaining text after removing selected text.
string remainingTextAfterRemoveSelection;
text = TreatSelectedText(out remainingTextAfterRemoveSelection)
? remainingTextAfterRemoveSelection.Insert(AssociatedObject.SelectionStart, e.Text)
: AssociatedObject.Text.Insert(AssociatedObject.CaretIndex, e.Text);
}
e.Handled = !ValidateText(text);
}
private bool TreatSelectedText(out string text)
{
text = null;
if (AssociatedObject.SelectionLength <= 0)
return false;
var length = AssociatedObject.Text.Length;
if (AssociatedObject.SelectionStart >= length)
return true;
if (AssociatedObject.SelectionStart + AssociatedObject.SelectionLength >= length)
AssociatedObject.SelectionLength = length - AssociatedObject.SelectionStart;
text = AssociatedObject.Text.Remove(AssociatedObject.SelectionStart, AssociatedObject.SelectionLength);
return true;
}
private void PastingHandler(object sender, DataObjectPastingEventArgs e)
{
if (e.DataObject.GetDataPresent(DataFormats.Text))
{
var pastedText = Convert.ToString(e.DataObject.GetData(DataFormats.Text));
var text = ModifyTextToFit(pastedText);
if (!ValidateText(text))
e.CancelCommand();
else if (text != pastedText)
e.DataObject.SetData(DataFormats.Text, text);
}
else
e.CancelCommand();
}
private string ModifyTextToFit(string text)
{
var result = text.Remove(MaxLength);
while (!string.IsNullOrEmpty(result) && !ValidateText(result))
result = result.Remove(result.Length - 1);
return result;
}
private bool ValidateText(string text)
{
return LengthEncoding.GetByteCount(text) <= MaxLength;
}
}
在XAML中,我可以像这样使用它:
<DataTemplate DataType="{x:Type vm:StringViewModel}">
<TextBox Text="{Binding Path=Value, UpdateSourceTrigger=PropertyChanged, ValidatesOnNotifyDataErrors=True}">
<i:Interaction.Behaviors>
<b:TextBoxMaxLengthBehavior MaxLength="{Binding MaxLength}" LengthEncoding="{Binding LengthEncoding}" />
</i:Interaction.Behaviors>
</TextBox>
</DataTemplate>
其中xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
。我希望这会对其他人有所帮助。