WPF验证运行时生成的表单

时间:2016-11-09 10:21:16

标签: c# wpf validation mvvm

我正在创建一个WPF应用程序,它根据模型生成一个表单来编辑它。我使用反射来遍历模型的所有属性,以创建属性的输入字段。 GenerateForm方法遍历属性并使用SimpleInputFactory生成输入字段。我想验证生成的字段的输入,但是所有验证方法都要求您知道要验证的内容(要么使用泛型,要么必须在XAML中的绑定上指定它)。我想根据模型中的属性验证输入。有没有现成的方法呢?我可以自己做,但如果有一些现有的方式,它会有所帮助。

提前致谢。

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

1 个答案:

答案 0 :(得分:2)

是的,您可以使用toggle()进行验证。

基本命名空间的文档:MSDN: System.ComponentModel.DataAnnotations

示例包括RequiredAttributeRangeAttribute

Microsoft还提供了一个很好的示例,说明如何使用以下示例中的$(document).ready(function() { $('#check').change(function() { $('p').toggle(!this.checked); }).change(); });<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <input type="checkbox" id="check" /> <p>If you click on the checkbox, I will disappear.</p>在WPF中实时向用户提供验证反馈:MSDN: Validation in MVVM using Data Annotations

我还为自己的目的开发了一个小框架,它结合了这些技术 - 基本上是一个基类,你需要用System.ComponentModel.DataAnnotations派生属性来装饰你的VM并使用适当的ErrorTemplate和WPF照顾其余的。 GitHub: ValidatingBaseViewModel