2016-11-09 3 views
1

Ich erstelle eine WPF-Anwendung, die ein Formular basierend auf einem Modell erstellt, um es zu bearbeiten. Ich verwende Reflektion, um alle Eigenschaften des Modells durchzugehen, um Eingabefelder für die Eigenschaften zu erstellen. Die GenerateForm-Methode durchläuft die Eigenschaften und verwendet die SimpleInputFactory zum Generieren von Eingabefeldern. Ich möchte die Eingabe der generierten Felder validieren, aber für alle Validierungsmethoden müssen Sie wissen, was Sie validieren möchten (entweder mit Generika oder mit der Bindung im XAML). Ich möchte die Eingabe basierend auf Attributen in den Modellen validieren. Gibt es einen bestehenden Weg dies zu tun? Ich könnte es einfach selbst machen, aber wenn es einen bestehenden Weg gibt, würde es helfen.WPF-Validierungslaufzeit generierte Formulare

Vielen Dank im Voraus.

public static Grid GenerateForm(List<object> basisgegevensModels, AddOrEdit addOrEdit) 
    { 
     if (basisgegevensModels.Count <= 0) 
      return null; 

     Grid formGrid = new Grid(); 
     formGrid.Margin = new Thickness(20,20,20,20); 
     formGrid.HorizontalAlignment = HorizontalAlignment.Stretch; 
     AddColumnToGrid(formGrid, GridUnitType.Star, 1); 
     AddColumnToGrid(formGrid, GridUnitType.Star, 3); 
     AddColumnToGrid(formGrid, GridUnitType.Star, 1); 
     AddColumnToGrid(formGrid, GridUnitType.Star, 3); 
     AddRowToGrid(formGrid, GridUnitType.Auto, 0); 


     var propertyInfos = new List<PropertyInfo>(); 
     foreach (var propertyInfo in basisgegevensModels[0].GetType().GetProperties(BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance)) 
     { 
      var visibleAttribute = propertyInfo.GetCustomAttributes(typeof(Visible), false).Cast<Visible>().FirstOrDefault(); 

      if (visibleAttribute == null || visibleAttribute.IsVisible) 
       propertyInfos.Add(propertyInfo); 
     } 

     int column = 0; 
     int row = 0; 
     foreach (var property in propertyInfos) 
     { 
      if (row >= Math.Ceiling((decimal)propertyInfos.Count/2) && row != 0 && column != 2) 
      { 
       column = 2; 
       row = 0; 
      } 

      var displayNameAttribute = basisgegevensModels[0].GetType().GetProperty(property.Name).GetCustomAttributes(typeof(DisplayNameAttribute), false) 
        .Cast<DisplayNameAttribute>().FirstOrDefault(); 
      string displayName; 
      if (displayNameAttribute != null) 
       displayName = displayNameAttribute.DisplayName; 
      else 
       displayName = property.Name; 

      bool isEditAllowed = true; 
      if (addOrEdit == AddOrEdit.Edit) 
      { 
       var editAllowed = 
        basisgegevensModels[0].GetType() 
         .GetProperty(property.Name) 
         .GetCustomAttributes(typeof (EditAllowed), false) 
         .Cast<EditAllowed>() 
         .FirstOrDefault(); 
       if (editAllowed != null) 
        isEditAllowed = editAllowed.IsEditAllowed; 
      } 

      //add label for inputfield 
      TextBlock label = SimpleInputFieldFactory.CreateTextBlock(displayName, column, row); 
      label.VerticalAlignment = VerticalAlignment.Center; 
      formGrid.Children.Add(label); 
      column++; 
      //add input field 
      formGrid.Children.Add(SimpleInputFieldFactory.CreateInputField(basisgegevensModels, property, isEditAllowed, column, row, 300, HorizontalAlignment.Left)); 
      column--; 
      row++; 
      if (column == 0) 
      { 
       AddRowToGrid(formGrid, GridUnitType.Auto, 0); 
      } 
     } 

     return formGrid; 
    } 

SimpleInputFieldFactory Klasse:

public class SimpleInputFieldFactory 
{ 

    public static Control CreateInputField(List<object> basisgegevensModels,  PropertyInfo property, bool editAllowed, int column, int row, double  inputFieldWidth, HorizontalAlignment inputFieldHorAlignment) 
    { 
     Control inputField = null; 
     var triggers = new List<System.Windows.Interactivity.EventTrigger>(); 
     var multiBinding = new MultiBinding(); 
     multiBinding.NotifyOnSourceUpdated = true; 
     multiBinding.Mode = BindingMode.TwoWay; 
     multiBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged; 

     foreach (var basisgegevensModel in basisgegevensModels) 
     { 
      Binding binding = new Binding(property.Name) 
      { 
       UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, 
       Source = basisgegevensModel, 
       Mode = BindingMode.TwoWay 
      }; 
      multiBinding.Bindings.Add(binding); 
     } 

     //add inputfield 
     if (property.PropertyType == typeof(string) || property.PropertyType == typeof(int)) 
     { 
      string valueAsString = ""; 
      if (property.GetValue(basisgegevensModels[0]) != null) 
       valueAsString = property.GetValue(basisgegevensModels[0]).ToString(); 

      inputField = CreateTextBox(valueAsString, column, row); 
      triggers.Add(new System.Windows.Interactivity.EventTrigger("EditValueChanged")); 
     } 
     else if (property.PropertyType == typeof(bool)) 
     { 
      bool valueAsBool = false; 
      if (property.GetValue(basisgegevensModels[0]) != null) 
       valueAsBool = (bool)property.GetValue(basisgegevensModels[0]); 

      inputField = CreateCheckBox(valueAsBool, column, row); 
      triggers.Add(new System.Windows.Interactivity.EventTrigger("EditValueChanged")); 
     } 
     else if (property.PropertyType.BaseType == typeof(Enum)) 
     { 
      int valueAsInt = 0; 
      if (property.GetValue(basisgegevensModels[0]) != null) 
       valueAsInt = (int)property.GetValue(basisgegevensModels[0]); 

      inputField = CreateDropDown(property.PropertyType, valueAsInt, column, row); 
      triggers.Add(new System.Windows.Interactivity.EventTrigger("EditValueChanged")); 

      ((ComboBoxEdit)inputField).SelectedIndex = valueAsInt; 
      ((ComboBoxEdit)inputField).IsTextEditable = false; 
     } 

     //add general settings, bindings and triggers 
     if (inputField != null) 
     { 
      inputField.Width = inputFieldWidth; 
      inputField.HorizontalAlignment = inputFieldHorAlignment; 
      inputField.Margin = new Thickness(5); 
      inputField.IsEnabled = editAllowed; 
      var multiEditAllowedAttribute = property.GetCustomAttributes(typeof(MultiEditAllowed), false) 
       .Cast<MultiEditAllowed>().FirstOrDefault(); 

      //only add binding and trigger if 1 entity is selected OR multiedit is allowed 
      if (basisgegevensModels.Count == 1 || multiEditAllowedAttribute == null || multiEditAllowedAttribute.IsMultiEditAllowed) 
      { 
       multiBinding.Converter = new MultiEditValueConverter(); 
       inputField.SetBinding(BaseEdit.EditValueProperty, multiBinding); 

       foreach (var trigger in triggers) 
       { 
        var action = new ActionMessage(); 
        action.MethodName = "InputChanged"; 

        trigger.Actions.Add(action); 
        Interaction.GetTriggers(inputField).Add(trigger); 
       } 
      } 
      else 
      { 
       inputField.IsEnabled = false; 
      } 

      return inputField; 
     } 

     return null; 
    } 

    public static List<string> GetEnumList(Type enumType) 
    { 
     if (!enumType.IsEnum) 
     { 
      return new List<string>(); 
     } 

     return Enum.GetNames(enumType).ToList(); 
    } 

    public static TextBlock CreateTextBlock(string text, int column, int row) 
    { 
     TextBlock textBlock = new TextBlock(); 
     textBlock.Text = text; 
     Grid.SetColumn(textBlock, column); 
     Grid.SetRow(textBlock, row); 

     return textBlock; 
    } 

    private static TextEditBase CreateTextBox(string text, int column, int row) 
    { 
     TextEdit textBox = new TextEdit(); 
     textBox.Text = text; 
     Grid.SetColumn(textBox, column); 
     Grid.SetRow(textBox, row); 

     return textBox; 
    } 

    private static CheckEdit CreateCheckBox(bool isChecked, int column, int row) 
    { 
     CheckEdit checkBox = new CheckEdit(); 
     checkBox.IsChecked = isChecked; 
     Grid.SetColumn(checkBox, column); 
     Grid.SetRow(checkBox, row); 

     return checkBox; 
    } 

    private static ComboBoxEdit CreateDropDown(Type enumType, int value, int column, int row) 
    { 
     ComboBoxEdit dropDown = new ComboBoxEdit(); 
     foreach (var enumValue in GetEnumList(enumType)) 
     { 
      dropDown.Items.Add(enumValue); 
     } 
     dropDown.SelectedIndex = value; 
     Grid.SetColumn(dropDown, column); 
     Grid.SetRow(dropDown, row); 

     return dropDown; 
    } 
} 

Antwort

2

Ja, können Sie die System.ComponentModel.DataAnnotations für die Validierung verwenden.

Dokumentation für die Basis-Namensraum: MSDN: System.ComponentModel.DataAnnotations

Beispiele hierfür sind RequiredAttribute und RangeAttribute.

Microsoft auch ein hervorragendes Beispiel dafür, wie die Validierung Feedback in Echtzeit an den Benutzer in WPF, um die ErrorTemplate und Binding im folgende Beispiel verwenden: MSDN: Validation in MVVM using Data Annotations

ich auch einen kleinen Rahmen für meine eigenen Zwecke entwickelt habe die diese Techniken enthält - im Grunde eine Basisklasse, wo Sie Ihre VM mit ValidationAttribute abgeleiteten Attributen dekorieren müssen und die entsprechenden Binding verwenden und WPF kümmert sich um den Rest. GitHub: ValidatingBaseViewModel

+0

Danke, das hat funktioniert! Sollte das bemerkt haben. –