2017-08-01 27 views
5

私はWPFでTextBoxを持っています。私はTextBoxのテキストの長さを制限したい。プロパティーの数を制限する簡単な方法は、MaxLengthです。TextBoxのテキストの制約された表現による長さ

私の使用では、文字の数ではなく、指定されたエンコーディングのテキストのバイナリ表現の長さでテキストを制限する必要があります。プログラムはドイツ語で使用されるので、2バイトを消費するいくつかのウムラウトがあります。

チェックすることを指定した文字列が与えられた長さに収まる場合、私はすでに、メソッドを持っています。

public bool IsInLength(string text, int maxLength, Encoding encoding) 
{ 
    return encoding.GetByteCount(text) < maxLength; 
} 

は誰がユーザーという、方法で、テキストボックスに、この機能を結びつけるための方法のアイデアを持ってい最大バイト長を超える文字を入力する可能性はほとんどありません。

TextBoxがDataTemplateの内部にあるため、EventHandlerを使用しないソリューションが優先されます。

+0

入力を検証するために、データアノテーションと検証インタフェース(Inotfiy ...)を使用していますか? – Jehof

+0

はい、あります。それから道はありますか? – scher

+0

Aテキストボックスにバインドされているプロパティのカスタム検証属性 – Jehof

答えて

3

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つのバイトの制限を超えてしまうので)今、あなたは失敗をトリガするために1個の絵文字または2つのASCII文字を入れることができます。

+0

あなたの応答に感謝します。これは素晴らしい解決策です。 ValidationRuleを使用することは私にとっては新しいものであり、今後のアプリケーションで役立ちます。しかし、ユーザーがあまりにも多くの文字を入力することができないソリューションを探していました。 ValidationRuleを使用すると、ユーザーは余りにも多くの文字を入力できますが、エラーが発生します。 – scher

+0

ネイティブのテキストボックスを使用して達成できるかどうかは疑いの余地はありません。ユーザーは文字を視覚的に入力できますが、無効な情報でビューモデルが更新されることはありません。それがシステムの仕組みです。この問題を回避するには、ユーザタイプとして入力できる文字数を動的に減らすMaxLengthにバインディングを追加することが考えられますが、混乱するユーザエクスペリエンスの他に、望みの結果を100%達成できない場合もあります。私は、コントロールのデフォルトの予想される動作を変更するこのルートを下回らないことを強くお勧めします。 – Maverik

+0

私は['Behavior'](https://msdn.microsoft.com/en-us/library/system.windows.interactivity.behavior(v = expression.40))のソリューションに取り組んでいます。aspx)。可能であれば投稿します。 – scher

-2

長すぎるテキストの入力を防ぐために、Alex Klausのソリューションを拡張しました。 XAMLで

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; 
    } 
} 

私はこのようにそれを使用することができます: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

<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> 

を。これが他の人に役立つことを願っています。

+1

なぜValidationRuleアプローチを使用しないのですか?それは小さく、読みやすく、簡単です...そして、それは行動と同じように再利用可能です。 –

+0

ValidationRuleを使用すると、ユーザーは許可されている以上に多くの文字をテキストボックスに入力できます。彼または彼女はこれが有効ではないことを見ているが、それは私の期待された行動ではなかった。私は本当にユーザーがあまりにも多くの文字を入力しないようにしたい。 – scher

関連する問題