2012-01-05 10 views
8

のViewModel:WPF TextBox MaxLength - これをバインドされたフィールドのデータ検証最大長にバインドする方法はありますか?

public class MyViewModel 
{ 
    [Required, StringLength(50)] 
    public String SomeProperty { ... } 
} 

XAML:

<TextBox Text="{Binding SomeProperty}" MaxLength="50" /> 

が私のViewModelを一致させるのTextBoxののMaxLengthを設定しないようにするためにどのような方法があります(それは別のアセンブリであるため、変更する可能性がある)と、 StringLength要件に基づいて自動的に最大長を設定しますか?

答えて

0

これを実行する1つの方法は、SomePropertyMaxLengthという同じビューモデルでプロパティを作成し、そのプロパティにMaxLengthプロパティをバインドすることです。

<TextBox Text="{Binding SomeProperty}" MaxLength="{Binding SomePropertyMaxLength}"/> 
+0

はい、私はそれについて考えましたが、私は本当に自分のメタデータを反映した追加のプロパティを追加し、すべてのxamlを通過し、それらのプロパティにバインドすることを避けたいと思っていました。 「カバーする」方法のタイプ...おそらく付随する行動によって? – michael

+1

"SomeProperty"を文字列値とmaxlength値を含むオブジェクトに変更して、それぞれのプロパティにバインドすることができます。この方法では、新しいプロパティを作成する必要はありませんが、xamlの変更を行う必要があります。 – evasilchenko

1

私は完全に自分自身をコードを記述するつもりはないが、1つのアイデアは、プロパティ名を取り、StringLengthAttribute探しの上に反映されますことMarkupExtension独自に作成することです。

属性が存在する場合は、ターゲットをその値にバインドしてください(リフレクションを使用)。そうでない場合は、0を目標値にバインドします(デフォルトは0です。つまり、最大値はありません)。

+0

私はあなたが言うことをするようにこのエクステンションを書く方法を理解しようとしています。 – michael

14

私はBehaviorを使用して、TextBoxをそのバウンドプロパティの検証属性(存在する場合)に接続しました。動作は次のようになります。

/// <summary> 
/// Set the maximum length of a TextBox based on any StringLength attribute of the bound property 
/// </summary> 
public class RestrictStringInputBehavior : Behavior<TextBox> 
{ 
    protected override void OnAttached() 
    { 
     AssociatedObject.Loaded += (sender, args) => setMaxLength(); 
     base.OnAttached(); 
    } 

    private void setMaxLength() 
    { 
     object context = AssociatedObject.DataContext; 
     BindingExpression binding = AssociatedObject.GetBindingExpression(TextBox.TextProperty); 

     if (context != null && binding != null) 
     { 
      PropertyInfo prop = context.GetType().GetProperty(binding.ParentBinding.Path.Path); 
      if (prop != null) 
      { 
       var att = prop.GetCustomAttributes(typeof(StringLengthAttribute), true).FirstOrDefault() as StringLengthAttribute; 
       if (att != null) 
       { 
        AssociatedObject.MaxLength = att.MaximumLength; 
       } 
      } 
     } 
    } 
} 

あなたが見ることができ、動作は単純にテキストボックスのデータコンテキストを取得し、「テキスト」のためのそのバインディング式。次に、リフレクションを使用して "StringLength"属性を取得します。使用法は、このようなものです:

<UserControl 
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

    <TextBox Text="{Binding SomeProperty}"> 
     <i:Interaction.Behaviors> 
      <local:RestrictStringInputBehavior /> 
     </i:Interaction.Behaviors> 
    </TextBox> 

</UserControl> 

またTextBoxを拡張することによって、この機能を追加することもできますが、彼らはモジュール化されたので、私は行動を使って好きです。

0

マークアップ拡張機能は間違いなく使い道です。 モデルDataType依存プロパティを持つBindingというBindingDecoratorBaseのサブクラスを作成しています。 MarkupExtensionsはInitializeComponent()中に作成されるため、まだ設定されていないDataContextを判別する方法はありません。

モデルタイプを指定すると、モデルに定義された属性への反映アクセスが可能になります。

  • テキストボックスのMaxLengthを設定します。
  • TextBlocksのStringFormatの設定。
  • メンバーのデータ型に応じてデフォルトのコンバータを設定します。
  • 必要な検証を追加しています。バインディングのValidationRulesを使用するか、ValidatesOnDataErrorsを設定します。

マークアップは次のようになります。 テキスト= "{PO:バインディングのデータ型=モデル:modAccount、パス=サブアカウント}"

の書式、のMaxLength、および変換は何も変更しなくて一つのパッケージにロールバックモデルクラスが変更されると、

+0

このサブクラスのコードサンプルがありますか? – TaterJuice

関連する問題