1 前面已经谈到UI通过对象属性的名称从对象中获取值,UI控件的值是在changed 事件后赋给对象。因为对象实体是已知的,UI控件的值对应的是对象的属性,所以根据对象中属性名称获取值是比较容易的。当然设置对象与获取对象的值,都在对象实体中有相应的方法。这个方法比较通用,现在有不少架构都这么写.下面两个方法都使用了反射对property进行读写.
UI 与对象实体的通信
1 前面已经谈到UI通过对象属性的名称从对象中获取值,UI控件的值是在changed 事件后赋给对象。因为对象实体是已知的,UI控件的值对应的是对象的属性,所以根据对象中属性名称获取值是比较容易的。当然设置对象与获取对象的值,都在对象实体中有相应的方法。这个方法比较通用,现在有不少架构都这么写.下面两个方法都使用了反射对property进行读写.
![]()
![]()
public object GetValue(string propertyName)
![]()
![]()
{
![]()
Type t;
![]()
System.Reflection.PropertyInfo p;
![]()
System.Reflection.MethodInfo m;
![]()
object rtn;
![]()
if ((propertyName == "UniqueID"))
![]()
![]()
{
![]()
return mUniqueID;
![]()
}
![]()
string nestedPropertyName = string.Empty;
![]()
bool nestedProperty = false;
![]()
int dotIndex;
![]()
dotIndex = propertyName.IndexOf('.');
![]()
if ((dotIndex > -1))
![]()
![]()
{
![]()
nestedPropertyName = propertyName.Substring(dotIndex + 1);
![]()
propertyName = propertyName.Substring(0, dotIndex);
![]()
nestedProperty = true;
![]()
}
![]()
t = this.GetType();
![]()
p = t.GetProperty(propertyName);
![]()
if (p != null)
![]()
![]()
{
![]()
m = p.GetGetMethod(false);
![]()
if ((m == null))
![]()
![]()
{
![]()
throw new Exception("Property: " + t.Name + "." + propertyName + " has no GET method.");
![]()
}
![]()
}
![]()
else
![]()
![]()
{
![]()
m = t.GetMethod(propertyName);
![]()
if ((m == null))
![]()
![]()
{
![]()
throw new Exception("Function: " + t.Name + "." + propertyName + " does not exist.");
![]()
}
![]()
}
![]()
rtn = m.Invoke(this, null);
![]()
if ((!((rtn == null)) && nestedProperty))
![]()
![]()
{
![]()
rtn = ((BizObject)(rtn)).GetValue(nestedPropertyName);
![]()
}
![]()
return rtn;
![]()
}
![]()
![]()
public void SetProperty(string propertyName, object value)
![]()
![]()
{
![]()
try
![]()
![]()
{
![]()
Type t;
![]()
System.Reflection.PropertyInfo p;
![]()
System.Reflection.MethodInfo m;
![]()
string nestedPropertyName = string.Empty;
![]()
bool nestedProperty = false;
![]()
int dotIndex;
![]()
System.Exception Ex;
![]()
t = this.GetType();
![]()
dotIndex = propertyName.IndexOf('.');
![]()
if ((dotIndex > -1))
![]()
![]()
{
![]()
nestedPropertyName = propertyName.Substring(dotIndex + 1);
![]()
propertyName = propertyName.Substring(0, dotIndex);
![]()
nestedProperty = true;
![]()
}
![]()
p = t.GetProperty(propertyName);
![]()
if ((p == null))
![]()
![]()
{
![]()
Ex = new CustomBizObjectException("Property: " + t.Name + "." + propertyName + " does not exist.");
![]()
Ex.Source = "BizObject_SetProperty(propertyName, value)";
![]()
throw Ex;
![]()
}
![]()
else
![]()
![]()
{
![]()
if (nestedProperty)
![]()
![]()
{
![]()
object rtn;
![]()
rtn = this.GetValue(propertyName);
![]()
if ((rtn == null))
![]()
![]()
{
![]()
Ex = new CustomBizObjectException(t.Name + "." + propertyName + " does not exist.");
![]()
Ex.Source = "BizObject_SetProperty(propertyName, value)";
![]()
throw Ex;
![]()
}
![]()
else
![]()
![]()
{
![]()
((BizObject)(rtn)).SetProperty(nestedPropertyName, value);
![]()
}
![]()
}
![]()
else
![]()
![]()
{
![]()
m = p.GetSetMethod(false);
![]()
if ((m == null))
![]()
![]()
{
![]()
Ex = new CustomBizObjectException("Function: " + t.Name + "." + propertyName + " has no SET method.");
![]()
Ex.Source = "BizObject_SetProperty(propertyName, value)";
![]()
throw Ex;
![]()
}
![]()
else
![]()
![]()
{
![]()
if ((value == null))
![]()
![]()
{
![]()
![]()
m.Invoke(this, new object[]
{ null });
![]()
}
![]()
else if ((value.GetType().IsSubclassOf(p.PropertyType)))
![]()
![]()
{
![]()
![]()
m.Invoke(this, new object[]
{ value });
![]()
}
![]()
else
![]()
![]()
{
![]()
![]()
m.Invoke(this, new object[]
{ System.Convert.ChangeType(value, p.PropertyType) });
![]()
}
![]()
}
![]()
}
![]()
}
![]()
}
![]()
catch (Exception ex)
![]()
![]()
{
![]()
ex = new CustomBizObjectException("Caught Exception when Setting " + this.GetType().Name + "." + propertyName, ex);
![]()
ex.Source = "BizObject_SetProperty(propertyName, value)";
![]()
throw ex;
![]()
}
![]()
![]()
}
![]()
![]()
2 新建,保存,刷新,取消
在主窗口中应该可以看到 新建,保存,刷新,取消这几个BUTTON。Mediar.framework 把所有的对象看归纳成只有这几个操作,通过这几个操作来控制对象。这几个button的事件调用活动窗口中的相应方法,最后调用对应的对象中相关方法.
主窗体中:
![]()
![]()
private void toolStripBase_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
![]()
![]()
{
![]()
BizObjectBoundEdit m = this.ActiveMdiChild as BizObjectBoundEdit;
![]()
![]()
switch (e.ClickedItem.Name)
![]()
![]()
{
![]()
case "toolStripButtonNew":
![]()
m.NewButtonPressed();
![]()
ActiveMenu();
![]()
break;
![]()
case "toolStripButtonCancel":
![]()
m.CancelButtonPressed();
![]()
break;
![]()
case "toolStripButtonSave":
![]()
m.UpdateButtonPressed();
![]()
break;
![]()
case "toolStripButtonRefresh":
![]()
m.RefreshButtonPressed();
![]()
break;
![]()
}
![]()
}
![]()
![]()
![]()
所有的对象UI都继承一个基础窗体,下面的方法作为共用方法写在这个基础窗体中。mRootBizObject 为窗体中对应的对象实体。这里就讲的比较的粗枝大叶了,不然决对不是一个短短的文章可以写清楚的。
![]()
![]()
public virtual void NewButtonPressed()
![]()
![]()
{
![]()
this.Cursor = Cursors.WaitCursor;
![]()
if (mRootBizObject == null)
![]()
![]()
{
![]()
ChangeRootBizObject(this.CreateNewBizObject(null));
![]()
}
![]()
else
![]()
![]()
{
![]()
ChangeRootBizObject(this.CreateNewBizObject(mRootBizObject.GetType()));
![]()
}
![]()
DisplayObject(mRootBizObject);
![]()
this.Cursor = Cursors.Default;
![]()
}
![]()
![]()
public virtual void CancelButtonPressed()
![]()
![]()
{
![]()
this.Cursor = Cursors.WaitCursor;
![]()
mRootBizObject.CancelEdit();
![]()
DisplayObject(mRootBizObject);
![]()
this.Cursor = Cursors.Default;
![]()
}
![]()
![]()
public virtual bool UpdateButtonPressed()
![]()
![]()
{
![]()
bool retVal;
![]()
this.Cursor = Cursors.WaitCursor;
![]()
if (mRootBizObject.Update())
![]()
![]()
{
![]()
retVal = true;
![]()
}
![]()
else
![]()
![]()
{
![]()
retVal = false;
![]()
MessageBox.Show("Your changes were NOT saved. Please review any error messages and try your save again.", mFriendlyClassName, MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1);
![]()
}
![]()
this.Cursor = Cursors.Default;
![]()
return retVal;
![]()
}
![]()
![]()
public virtual void RefreshButtonPressed()
![]()
![]()
{
![]()
this.Cursor = Cursors.WaitCursor;
![]()
mRootBizObject.ReSelect();
![]()
this.Cursor = Cursors.Default;
![]()
}
![]()
![]()
![]()
新建需要通过工厂中的 CreateBizObject方法,因为每个对象都需要包括一个工厂,就需要在新建的时候构造传入。对象新建可以在InitializeValues方法设对象default 值。
![]()
![]()
public BizObject CreateBizObject()
![]()
![]()
{
![]()
BizObject bo;
![]()
bo = CreateBizObject(this);
![]()
UpdateCache(bo);
![]()
return bo;
![]()
}
![]()
![]()
protected override BizObject CreateBizObject(BizObjectFactory bof)
![]()
![]()
{
![]()
return new Contact(bof);
![]()
}
![]()
![]()
取消就把Original值覆盖到当前值.
public void CancelEdit()
![]()
![]()
{
![]()
CancelEditChildren();
![]()
if ((mIsDirty))
![]()
![]()
{
![]()
RestoreLastPersistedValues();
![]()
this.OnBizObjectUpdatedEvent(new BizObjectUpdatedEventArgs(BizObjectUpdatedType.Changed));
![]()
}
![]()
}
![]()
protected override void RestoreLastPersistedValues()
![]()
![]()
{
![]()
mDisplayID[AttributeValueVersion.Current] = mDisplayID[AttributeValueVersion.Original];
![]()
mFirstName[AttributeValueVersion.Current] = mFirstName[AttributeValueVersion.Original];
![]()
mLastName[AttributeValueVersion.Current] = mLastName[AttributeValueVersion.Original];
![]()
mDescription[AttributeValueVersion.Current] = mDescription[AttributeValueVersion.Original];
![]()
mCompanyName[AttributeValueVersion.Current] = mCompanyName[AttributeValueVersion.Original];
![]()
mContactType[AttributeValueVersion.Current].UniqueID = mContactType[AttributeValueVersion.Original].UniqueID;
![]()
// mAddress[AttributeValueVersion.Current].UniqueID = mAddress[AttributeValueVersion.Original].UniqueID;
![]()
mEmailAddress[AttributeValueVersion.Current] = mEmailAddress[AttributeValueVersion.Original];
![]()
mWebSiteURL[AttributeValueVersion.Current] = mWebSiteURL[AttributeValueVersion.Original];
![]()
mNotes[AttributeValueVersion.Current] = mNotes[AttributeValueVersion.Original];
![]()
![]()
base.RestoreLastPersistedValues();
![]()
}
![]()
![]()
保存就把数据更新到数据库,然后再刷新当前的实体。也许有人要问:刚才保存的为什么要刷新呀?刷新目是把RecordVersion取出来,RecordVersion是timestamp类型,每更新一次数据库,该字段就是有一个新值。在更新数据库之前会和数据库中的值比较,这是防止两个人在同时修改一个对象时引发冲突。
![]()
![]()
public virtual bool Update(string AssemblyName)
![]()
![]()
{
![]()
BeginEdit();
![]()
DataSet ds;
![]()
DataRow dr;
![]()
BizObject bobjClone;
![]()
bool success = false;
![]()
if (!mAllowEdit)
![]()
![]()
{
![]()
throw new Exception("Object marked to disallow edits");
![]()
}
![]()
if (!Validate())
![]()
![]()
{
![]()
return false;
![]()
}
![]()
![]()
ds = mBOFactory.CreateDataObject();
![]()
dr = GetDataObjectRow(ds);
![]()
![]()
try
![]()
![]()
{
![]()
mBOFactory.Update( ref ds, AssemblyName);
![]()
![]()
success = !(ds.HasErrors);
![]()
if ((ds.HasErrors && DBUtility.HasDBConcurrencyError(ds)))
![]()
![]()
{
![]()
bobjClone = this.Clone(true);
![]()
OnBizObjectConcurrencyErrorEvent(new BizObjectConcurrencyErrorEventArgs(bobjClone));
![]()
}
![]()
else
![]()
![]()
{
![]()
Refresh(ds);
![]()
}
![]()
}
![]()
catch (CustomBizObjectException ex)
![]()
![]()
{
![]()
ExceptionManager.Publish(ex);
![]()
throw ex;
![]()
}
![]()
catch (Exception ex)
![]()
![]()
{
![]()
success = false;
![]()
this.OnBizObjectErrorEvent(new BizObjectErrorEventArgs(BizObjectErrorType.DBError, ex.Message, ""));
![]()
}
![]()
![]()
this.EndEdit();
![]()
return success;
![]()
![]()
}
![]()
![]()
Factory类中,就会调用数据层的更新方法。
public void Update(ref DataSet ds, string AssemblyName)
![]()
![]()
{
![]()
DataAccess da;
![]()
da = GetDataAccess(AssemblyName);
![]()
ds= da.Update(ds,true);
![]()
}
![]()
刷新就是从数据库重取数据,然后更新对象属性的值。
![]()
![]()
public virtual void ReSelect()
![]()
![]()
{
![]()
this.ReSelect(QueryFor.Complete);
![]()
}
![]()
![]()
public virtual void ReSelect(QueryFor queryFor)
![]()
![]()
{
![]()
if (this.mIsDirty)
![]()
![]()
{
![]()
throw new CustomBizObjectException("Can not ReSelect if BizObject is dirty.");
![]()
}
![]()
this.mBOFactory.ReSelect(this, queryFor, mDataAccessAssemblyName);
![]()
}
![]()
// mBOFactory 中
![]()
protected internal void ReSelect(BizObject bobj, QueryFor queryFor, string DAAssemblyName)
![]()
![]()
{
![]()
DataSet ds;
![]()
ds = this.GetDataAccess(DAAssemblyName).Select(bobj.UniqueID, QueryFor.Complete);
![]()
this.BuildBizObject(bobj.UniqueID, ds, queryFor);
![]()
}
![]()
![]()
![]()