2016-11-09 55 views
1

我正在創建一個WPF應用程序,該應用程序根據模型生成一個表單來編輯它。我使用反射通過模型的所有屬性爲屬性創建輸入域。 GenerateForm方法遍歷屬性並使用SimpleInputFactory生成輸入字段。我想驗證生成的字段的輸入,但所有驗證方法都要求您知道要驗證的內容(無論是使用泛型還是必須在XAML中的綁定中指定它)。我想根據模型中的屬性驗證輸入。有沒有現有的方法來做到這一點?我可以自己做,但如果有一些現有的方式,它會有所幫助。WPF驗證運行時生成表格

在此先感謝。

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

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

回答

2

是的,你可以使用System.ComponentModel.DataAnnotations進行驗證。

文檔用於基名稱空間:MSDN: System.ComponentModel.DataAnnotations

實例包括RequiredAttributeRangeAttribute

微軟還提供瞭如何給用戶使用WPF的ErrorTemplateBinding在下面的例子中提供實時反饋的驗證一個很好的例子:MSDN: Validation in MVVM using Data Annotations

我也開發了自己的目的的小框架其中包含這些技術 - 基本上是一個基類,您需要用ValidationAttribute派生屬性修飾虛擬機,並使用相應的Binding,而WPF負責其餘部分。 GitHub: ValidatingBaseViewModel

+0

謝謝,這工作!應該已經注意到了一個。 –