I have a small Person Domain Model as follows:
public class Person
{
    public Person()
    {
        FirstName = "John";
        LastName = "Doe";
        BirthDate = DateTime.Now.AddYears(-18);
    }
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public Guid PersonId { get; set; }
    [MaxLength(25, ErrorMessage = "The First Name cannot be more than 25 characters in length.")]
    [MinLength(3, ErrorMessage = "The First Name must be at least three characters.")]
    [Required(ErrorMessage = "The First Name is required.", AllowEmptyStrings = false)]
    [DisplayName("First Name")]
    public string FirstName { get; set; }
    [MaxLength(25, ErrorMessage = "The Last Name cannot be more than 25 characters in length.")]
    [MinLength(3, ErrorMessage = "The Last Name must be at least three characters  in length.")]
    [Required(ErrorMessage = "The Last Name is required.", AllowEmptyStrings = false)]
    [DisplayName("Last Name")]
    public string LastName { get; set; }
    [DisplayName("Full Name")]
    public string FullName => string.Format("{0} {1}", FirstName, LastName);
    [Date(ErrorMessage = "Age must be between 18 and 65 years of age")]
    [DisplayName("Birth Date")]
    [DataType(DataType.Date,ErrorMessage = "This is not a valid date.")]
    [Required(ErrorMessage = "The Birth Date is Required")]
    public DateTime BirthDate { get; set; }
    [RegularExpression(@"^((?!000)(?!666)(?:[0-6]\d{2}|7[0-2][0-9]|73[0-3]|7[5-6][0-9]|77[0-2]))-((?!00)\d{2})-((?!0000)\d{4})$",
        ErrorMessage = "The Social Security Number must be in the pattern xxx-xx-xxx and be a valid US SSN.")]
    [DisplayName("Social Security #")]
    [Required(ErrorMessage = "The Social Security Number is Required.",AllowEmptyStrings = false)]
    public string SocialSecurityNumber { get; set; }
    public override string ToString()
    {
        return FullName;
    }
}
If I create a new MVC web site and scaffold my controller, all my validating attributes just work on the create new and edit screens.
However, if I needed a WinForm to do the same thing, I would need to "roll my own". I did just that.
My WinForm code-behind in all its glory:
public partial class AddPersonForm : Form
{
    private readonly DemoContext _context;
    public AddPersonForm()
    {
        _context = new DemoContext();
        InitializeComponent();
    }
    protected override void OnLoad(EventArgs e)
    {
        _context.People.Load();
        personBindingSource.DataSource = _context.People.Local.ToBindingList();
        personBindingSource.RaiseListChangedEvents = true;
        FirstNameTextBox.Validating += Input_Validating;
        LastNameTextBox.Validating += Input_Validating;
        BirthDateDateTimePicker.Validating += Input_Validating;
        SocialSecurityNumberTextBox.Validating += Input_Validating;
        personBindingSource.AddNew();
        base.OnLoad(e);
    }
    private void personBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        personBindingSource.EndEdit();
        int changes = _context.SaveChanges();
        Debug.WriteLine("# of changes: " + changes);
    }
    private void Input_Validating(object sender, CancelEventArgs e)
    {
        // GetValidationErrors cannot see any errors unless the following line is present
        personBindingSource.EndEdit();
        IEnumerable<DbEntityValidationResult> results = _context.GetValidationErrors();
        foreach (DbEntityValidationResult result in results)
        {
            // Stops at the first error and also cancels the endedit.
            foreach (DbValidationError error in result.ValidationErrors)
            {
                Debug.WriteLine("Property: " + error.PropertyName);
                if (error.PropertyName == "FirstName")
                {
                    errorProvider1.SetError(FirstNameTextBox, error.ErrorMessage);
                    //e.Cancel = true;
                    return;
                }
                if (error.PropertyName == "LastName")
                {
                    errorProvider1.SetError(LastNameTextBox, error.ErrorMessage);
                    //e.Cancel = true;
                    return;
                }
                if (error.PropertyName == "BirthDate")
                {
                    errorProvider1.SetError(BirthDateDateTimePicker, error.ErrorMessage);
                    //e.Cancel = true;
                    return;
                }
                if (error.PropertyName == "SocialSecurityNumber")
                {
                    errorProvider1.SetError(SocialSecurityNumberTextBox, error.ErrorMessage);
                    //e.Cancel = true;
                    return;
                }
            }
        }
        errorProvider1.Clear();
    }
}
It may look bad, but it does work. How do I make my method Input_Validating() more efficient so I don't have to write a new block for every input control on the form?

