2012-01-05 19 views
8

ViewModel:Maksymalna długość ramki TextFox WPF - czy istnieje sposób powiązania tej wartości z maksymalną wartością sprawdzania poprawności danych w powiązanym polu?

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

XAML:

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

Czy istnieje jakiś sposób, aby uniknąć ustawiania MaxLength pola tekstowego, aby dopasować się mój ViewModel (która może zmienić, ponieważ jest w innym zespole) i czy automatycznie ustawi maksymalną długość na podstawie wymogu StringLength?

Odpowiedz

0

Jednym ze sposobów na zrobienie tego byłoby utworzenie właściwości w tym samym modelu widoku o nazwie SomePropertyMaxLength, a następnie powiązanie właściwości MaxLength z tą właściwością.

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

Tak, myślałem o tym, ale naprawdę chciałem uniknąć przechodzenia przez dodatkowe właściwości, które odzwierciedlają moje metadane, a następnie przechodzenie przez wszystkie moje xaml i wiązanie z tymi właściwościami ... Miałem nadzieję na "pod obejmuje "rodzaj drogi ... może przez przywiązane zachowania? – michael

+1

Możesz zmienić "SomeProperty" na obiekt, który zawiera wartość ciągu i wartość maksymalnej długości, a następnie powiąż odpowiednio te właściwości. W ten sposób nie będziesz musiał tworzyć nowych właściwości, ale nadal będziesz musiał przejść przez zmiany xaml. – evasilchenko

1

A ja nie zamierzam napisać kod całkowicie sam, jeden pomysł jest stworzenie własnego MarkupExtension że weźmie nazwę właściwości i refleksji nad szuka StringLengthAttribute.

Jeśli atrybut istnieje, spróbuj powiązać cel z tą wartością (używając odbicia). Jeśli nie, należy powiązać 0 z wartością docelową (domyślnie 0, to znaczy bez wartości maksymalnej).

+0

Sporo czasu spędziłem próbując wymyślić, jak napisać to rozszerzenie, żeby zrobił to, co mówisz. – michael

14

Użyłem Behavior do połączenia TextBox z atrybutem weryfikacji właściwości powiązanej (jeśli jest). Zachowanie wygląda następująco:

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

Można zobaczyć, zachowanie po prostu pobiera kontekst danych w polu tekstowym, a jego ekspresja wiążący dla „Tekst”. Następnie używa odbicia, aby uzyskać atrybut "StringLength". Wykorzystanie jest tak:

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

Można też dodać tę funkcjonalność poprzez rozszerzenie TextBox, ale lubię za pomocą zachowań, ponieważ mają budowę modułową.

0

Rozszerzenie oznaczenia to zdecydowanie droga. Tworzę podklasę BindingDecoratorBase o nazwie Binding, która ma właściwość zależności ModelType. Ponieważ MarkupExtensions są tworzone podczas InitializeComponent(), nie ma możliwości określenia DataContext, ponieważ nie został on jeszcze ustawiony.

Podanie typu modelu umożliwia dostęp odblaskowy do atrybutów zdefiniowanych w modelu. Umożliwia to:

  • Ustawianie maksymalnej długości dla pól tekstowych.
  • Ustawienie StringFormat dla TextBlocks.
  • Ustawianie domyślnego konwertera w zależności od typu danych członka.
  • Dodanie wymaganego sprawdzania poprawności. Korzystając z ValidationRules powiązania lub ustawiając ValidatesOnDataErrors.

Znacznik wygląda następująco: Text = "{PO: Wiązanie DataType = model: modAccount, Path = subkoncie}"

Formatowanie MaxLength i konwersji zwinięte w jednym pakiecie, bez potrzeby zmiany czegokolwiek jak zmieniają się klasy modelu.

+0

Czy masz próbkę kodu tej podklasy? – TaterJuice

Powiązane problemy