[quoted text, click to view] > I would like to keep it in the business object so code doesn't
> have to be duplicated in multiple forms.
Absolutely; this is good practice - it separates the model from the
UI.
If you want the validation to *prevent* invalid entry, then put it in
the setter and raise an exception. If you want it to /notify/ the user
about data errors without interrupting the flow, then implement
IDataErrorInfo. Some UI controls (most notably DataGridView) support
this automatically, but for others you might need to cobble some
things together, perhaps involving an ErrorProvider. For a hasty, not
very pretty example - see below.
using System;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
public class OrderHeader : INotifyPropertyChanged, IDataErrorInfo
{
public event PropertyChangedEventHandler PropertyChanged;
private string mOrderNumber;
private void UpdateField<T>(ref T field, T value, string
propertyName)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
}
}
}
public string OrderNumber
{
get { return mOrderNumber; }
set
{
string fmt = value.Trim().ToUpper().PadLeft(8, '0');
UpdateField(ref mOrderNumber, fmt, "OrderNumber");
}
}
#region IDataErrorInfo Members
static string GetAllErrors(IDataErrorInfo component)
{
StringBuilder sb = new StringBuilder();
foreach (PropertyDescriptor property in
TypeDescriptor.GetProperties(component))
{
string propErr = component[property.Name];
if (!string.IsNullOrEmpty(propErr))
{
sb.AppendLine(propErr);
}
}
return sb.ToString();
}
string IDataErrorInfo.this[string columnName]
{
get {
switch (columnName)
{
case "OrderNumber":
int len = mOrderNumber == null ? 0 :
mOrderNumber.Length;
if (len < 2 || len > 8){
return "Order number must be between 2 and 8
characters";
}
break;
}
return "";
}
}
string IDataErrorInfo.Error
{
get { return GetAllErrors(this); }
}
#endregion
}
static class Program
{
static void Main()
{
Application.EnableVisualStyles();
OrderHeader order = new OrderHeader();
order.OrderNumber = "0001";
BindingList<OrderHeader> orders = new
BindingList<OrderHeader>();
orders.Add(order);
orders.AllowNew = orders.AllowRemove = false;
using (Form f = new Form())
using (TextBox tb1 = new TextBox())
using (TextBox tb2 = new TextBox())
using (DataGridView dgv = new DataGridView())
using (ErrorProvider err = new ErrorProvider())
{
err.Icon = SystemIcons.Error;
tb1.Top = 20;
tb2.Top = 60;
tb1.DataBindings.Add("Text", orders, "OrderNumber");
tb2.DataBindings.Add("Text", orders,
"OrderNumber");
order.PropertyChanged += delegate
{
err.SetError(tb2, ((IDataErrorInfo)order)
["OrderNumber"]);
};
dgv.DataSource = orders;
dgv.Dock = DockStyle.Bottom;
f.Controls.Add(tb1);
f.Controls.Add(tb2);
f.Controls.Add(dgv);
Application.Run(f);
}
}