I guess you want to implement a datamodel that is able to interact with the UI components, without knowing anything about them.
.Net provides a solid foundation for developing this kind of data objects.
I usually call this kind of objects for entities, and the first thing you need to look at is the
INotifyPropertyChanged[
^] interface.
public class EntityBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnChanged(string propertyName)
{
if(PropertyChanged != null)
{
var eventArgs = new PropertyChangedEventArgs(propertyName)
PropertyChanged(this, eventArgs);
}
}
}
The next interface you need to be familiar with is the
IEditableObject[
^] which allows your object to back out of an editing operation.
public class EntityBaseData
{
public virtual EntityBaseData Clone()
{
return new EntityBaseData();
}
}
public class EntityBase : INotifyPropertyChanged, IEditableObject
{
EntityBaseData originalData;
EntityBaseData data;
public event PropertyChangedEventHandler PropertyChanged;
protected void OnChanged(string propertyName)
{
if(PropertyChanged != null)
{
var eventArgs = new PropertyChangedEventArgs(propertyName)
PropertyChanged(this, eventArgs);
}
}
protected virtual EntityBaseData CreateData()
{
EntityBaseData result = new EntityBaseData();
return result;
}
protected virtual void SaveData()
{
}
protected EntityBaseData GetData()
{
if(data == null)
{
data = CreateData();
}
return data;
}
void IEditableObject.BeginEdit()
{
if(originalData == null)
{
originalData = GetData();
data = originalData.Clone();
}
}
void IEditableObject.CancelEdit()
{
if(originalData != null)
{
data = originalData;
originalData = null;
OnChanged("");
}
}
void IEditableObject.EndEdit()
{
SaveData();
originalData = null;
}
}
You would use the above classes in this manner:
public class PersonData : EntityBaseData
{
int id;
string name;
public PersonData()
{ }
public override EntityBaseData Clone()
{
PersonData result = new PersonData();
result.Id = Id;
result.Name = Name;
return result;
}
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
}
public class PersonEnity : EntityBase
{
private PersonData Data
{
get
{
return (PersonData)GetData();
}
}
protected override EntityBaseData CreateData()
{
return new PersonData();
}
public int Id
{
get
{
return Data.Id;
}
set
{
if (Data.Id == value)
{
return;
}
Data.Id = value;
OnChanged("Id");
}
}
public string Name
{
get
{
return Data.Name;
}
set
{
if (Data.Name == value)
{
return;
}
Data.Name = value;
OnChanged("Name");
}
}
}
This works well for a single object, but it is quite common to work with lists of objects, which brings us to the generic
BindingList[
^] class:
public class BindingListEx<T> : BindingList<T>, ITypedList
{
[NonSerialized()]
private PropertyDescriptorCollection propertyDescriptorCollection;
public PropertyDescriptorCollection GetItemProperties(PropertyDescriptor[] listAccessors)
{
if (listAccessors != null && listAccessors.Length > 0)
{
PropertyDescriptorCollection result = ListBindingHelper.GetListItemProperties(listAccessors[0].PropertyType);
return result;
}
else
{
if (propertyDescriptorCollection == null)
{
propertyDescriptorCollection = TypeDescriptor.GetProperties(typeof(T), new Attribute[] { new BrowsableAttribute(true) });
}
return propertyDescriptorCollection;
}
}
public string GetListName(PropertyDescriptor[] listAccessors)
{
string result = typeof(T).Name;
return result;
}
}
Note that I'm also implementing the
ITypedList[
^] interface, which provides type information used by Visual Studio during designtime (Windows Forms)
The next thing you need is a
Component[
^]
public class BindingComponent<T> : Component,IListSource
{
BindingListEx<T> items;
public BindingComponent()
{
items = new BindingListEx<T>();
}
public BindingListEx<T> Items
{
get
{
return items;
}
}
public bool ContainsListCollection
{
get { return false; }
}
public System.Collections.IList GetList()
{
return Items;
}
}
The above can now be used to create a bindable data source for PersonEntity
public class PersonsComponent : BindingComponent<PersonEnity>
{
public PersonsComponent()
{
}
}
The above can be used with Visual Studio where PersonsComponent should show up in the toolbox.
Well, this is the basics for creating entity classes in .Net.
Best regards
Espen Harlinn