string dynMethodId = "";
bool resolved = false;
+ public bool TwoWayBinding = false;
+
public string NewDynMethodId {
get {
if (!string.IsNullOrEmpty (dynMethodId))
#region CTOR
public Binding(){}
- public Binding(MemberReference _source, string _expression)
+ public Binding(MemberReference _target, string _expression)
{
- Target = _source;
+ Target = _target;
Expression = _expression;
}
- public Binding(object _source, string _member, string _expression)
+ public Binding(object _target, string _member, string _expression)
{
- Target = new MemberReference (_source, _source.GetType().GetMember (_member) [0]);
+ Target = new MemberReference (_target, _target.GetType().GetMember (_member) [0]);
Expression = _expression;
}
+ public Binding(object _target, string _targetMember, object _source, string _sourceMember)
+ {
+ Target = new MemberReference (_target, _target.GetType().GetMember (_targetMember) [0]);
+ Source = new MemberReference (_source, _source.GetType().GetMember (_sourceMember) [0]);
+ }
+ public Binding(MemberReference _target, MemberReference _source)
+ {
+ Target = _target;
+ Source = _source;
+ }
#endregion
- public bool FindTarget(){
+ public bool FindSource(){
+ if (Source != null)
+ return true;
+
string member = null;
//if binding exp = '{}' => binding is done on datasource
return true;
}
- string[] bindingExp = Expression.Split ('/');
+ string expression = Expression;
+
+ if (Expression.StartsWith ("²")) {
+ expression = expression.Substring (1);
+ TwoWayBinding = true;
+ }
+
+ string[] bindingExp = expression.Split ('/');
if (bindingExp.Length == 1) {
//datasource binding
return false;
}
- if (Source.FindMember (member))
+ if (Source.FindMember (member)) {
+ if (TwoWayBinding) {
+ IBindable source = Source.Instance as IBindable;
+ if (source == null)
+ throw new Exception (Target.Instance.ToString() + " does not implement IBindable for 2 way bindings");
+ source.Bindings.Add (new Binding (Source, Target));
+ }
return true;
+ }
Debug.WriteLine ("Binding member not found: " + member);
+ Source = null;
return false;
}
public void Reset()
public static class CompilerServices
{
+ public static void ResolveBindings(List<Binding> Bindings)
+ {
+ if (Bindings == null)
+ return;
+ if (Bindings.Count == 0)
+ return;
+ #if DEBUG_BINDING
+ Debug.WriteLine ("Resolve Bindings => " + this.ToString ());
+ #endif
+ //grouped bindings by Instance of Source
+ Dictionary<object,List<Binding>> resolved = new Dictionary<object, List<Binding>>();
+
+ foreach (Binding b in Bindings) {
+ if (b.Resolved)
+ continue;
+ if (b.Target.Member.MemberType == MemberTypes.Event) {
+ if (b.Expression.StartsWith("{")){
+ CompilerServices.CompileEventSource(b);
+ continue;
+ }
+ if (!b.FindSource ())
+ continue;
+ //register handler for event
+ if (b.Source.Method == null) {
+ Debug.WriteLine ("\tError: Handler Method not found: " + b.ToString());
+ continue;
+ }
+ try {
+ MethodInfo addHandler = b.Target.Event.GetAddMethod ();
+ Delegate del = Delegate.CreateDelegate (b.Target.Event.EventHandlerType, b.Source.Instance, b.Source.Method);
+ addHandler.Invoke (b.Target.Instance, new object[] { del });
+
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\tHandler binded => " + b.ToString());
+ #endif
+ b.Resolved = true;
+ } catch (Exception ex) {
+ Debug.WriteLine ("\tERROR: " + ex.ToString());
+ }
+ continue;
+ }
+
+ if (!b.FindSource ())
+ continue;
+
+ List<Binding> bindings = null;
+ if (!resolved.TryGetValue (b.Source.Instance, out bindings)) {
+ bindings = new List<Binding> ();
+ resolved [b.Source.Instance] = bindings;
+ }
+ bindings.Add (b);
+ b.Resolved = true;
+ }
+
+ MethodInfo stringEquals = typeof(string).GetMethod
+ ("Equals", new Type[3] {typeof(string), typeof(string), typeof(StringComparison)});
+ Type target_Type = Bindings[0].Target.Instance.GetType();
+ EventInfo ei = typeof(IValueChange).GetEvent("ValueChanged");
+ MethodInfo evtInvoke = ei.EventHandlerType.GetMethod ("Invoke");
+ ParameterInfo[] evtParams = evtInvoke.GetParameters ();
+ Type handlerArgsType = evtParams [1].ParameterType;
+ Type[] args = {typeof(object), typeof(object),handlerArgsType};
+ FieldInfo fiNewValue = typeof(ValueChangeEventArgs).GetField("NewValue");
+ FieldInfo fiMbName = typeof(ValueChangeEventArgs).GetField("MemberName");
+
+ //group;only one dynMethods by target (valuechanged event source)
+ //changed value name tested in switch
+ //IEnumerable<Binding[]> groupedByTarget = resolved.GroupBy (g => g.Target.Instance, g => g, (k, g) => g.ToArray ());
+ foreach (List<Binding> grouped in resolved.Values) {
+ int i = 0;
+ Type source_Type = grouped[0].Source.Instance.GetType();
+
+ DynamicMethod dm = null;
+ ILGenerator il = null;
+
+ System.Reflection.Emit.Label[] jumpTable = null;
+ System.Reflection.Emit.Label endMethod = new System.Reflection.Emit.Label();
+
+ #region Retrieve EventHandler parameter type
+ //EventInfo ei = targetType.GetEvent ("ValueChanged");
+ //no dynamic update if ValueChanged interface is not implemented
+ if (source_Type.GetInterfaces().Contains(typeof(IValueChange))){
+ dm = new DynamicMethod(grouped[0].NewDynMethodId,
+ MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
+ CallingConventions.Standard,
+ typeof(void),
+ args,
+ target_Type,true);
+
+ il = dm.GetILGenerator(256);
+
+ endMethod = il.DefineLabel();
+ jumpTable = new System.Reflection.Emit.Label[grouped.Count];
+ for (i = 0; i < grouped.Count; i++)
+ jumpTable [i] = il.DefineLabel ();
+ il.DeclareLocal(typeof(string));
+ il.DeclareLocal(typeof(object));
+
+ il.Emit(OpCodes.Nop);
+ il.Emit(OpCodes.Ldarg_0);
+ //il.Emit(OpCodes.Isinst, sourceType);
+ //push new value onto stack
+ il.Emit(OpCodes.Ldarg_2);
+ il.Emit(OpCodes.Ldfld, fiNewValue);
+ il.Emit(OpCodes.Stloc_1);
+ //push name
+ il.Emit(OpCodes.Ldarg_2);
+ il.Emit(OpCodes.Ldfld, fiMbName);
+ il.Emit(OpCodes.Stloc_0);
+ il.Emit(OpCodes.Ldloc_0);
+ il.Emit(OpCodes.Brfalse, endMethod);
+ }
+ #endregion
+
+ i = 0;
+ foreach (Binding b in grouped) {
+ #region initialize target with actual value
+ object targetValue = null;
+ if (b.Source.Member != null){
+ if (b.Source.Member.MemberType == MemberTypes.Property)
+ targetValue = b.Source.Property.GetGetMethod ().Invoke (b.Source.Instance, null);
+ else if (b.Source.Member.MemberType == MemberTypes.Field)
+ targetValue = b.Source.Field.GetValue (b.Source.Instance);
+ else if (b.Source.Member.MemberType == MemberTypes.Method){
+ MethodInfo mthSrc = b.Source.Method;
+ if (mthSrc.IsDefined(typeof(ExtensionAttribute), false))
+ targetValue = mthSrc.Invoke(null, new object[] {b.Source.Instance});
+ else
+ targetValue = mthSrc.Invoke(b.Source.Instance, null);
+ }else
+ throw new Exception ("unandled source member type for binding");
+ }else if (string.IsNullOrEmpty(b.Expression))
+ targetValue= grouped [0].Source.Instance;//empty binding exp=> bound to target object by default
+ //TODO: handle other dest type conversions
+ if (b.Target.Property.PropertyType == typeof(string)){
+ if (targetValue == null){
+ //set default value
+
+ }else
+ targetValue = targetValue.ToString ();
+ }
+ if (targetValue != null)
+ b.Target.Property.GetSetMethod ().Invoke
+ (b.Target.Instance, new object[] { b.Target.Property.PropertyType.Cast(targetValue)});
+ else
+ b.Target.Property.GetSetMethod ().Invoke
+ (b.Target.Instance, new object[] { targetValue });
+ #endregion
+
+ //if no dyn update, skip jump table
+ if (il == null)
+ continue;
+
+ il.Emit (OpCodes.Ldloc_0);
+ if (b.Source.Member != null)
+ il.Emit (OpCodes.Ldstr, b.Source.Member.Name);
+ else
+ il.Emit (OpCodes.Ldstr, b.Expression.Split('/').LastOrDefault());
+ il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+ il.Emit (OpCodes.Callvirt, stringEquals);
+ il.Emit (OpCodes.Brtrue, jumpTable[i]);
+ i++;
+ }
+
+ if (il == null)
+ continue;
+
+ il.Emit (OpCodes.Br, endMethod);
+
+ i = 0;
+ foreach (Binding b in grouped) {
+
+ il.MarkLabel (jumpTable [i]);
+ il.Emit(OpCodes.Ldloc_1);
+
+ //by default, target value type is deducted from source member type to allow
+ //memberless binding, if targetMember exists, it will be used to determine target
+ //value type for conversion
+ Type targetValueType = b.Target.Property.PropertyType;
+ if (b.Source.Member != null) {
+ if (b.Source.Member.MemberType == MemberTypes.Property)
+ targetValueType = b.Source.Property.PropertyType;
+ else if (b.Source.Member.MemberType == MemberTypes.Field)
+ targetValueType = b.Source.Field.FieldType;
+ else
+ throw new Exception ("unhandle target member type in binding");
+ }
+
+ if (b.Target.Property.PropertyType == typeof(string)) {
+ MemberReference tostring = new MemberReference (b.Target.Instance);
+ if (!tostring.FindMember ("ToString"))
+ throw new Exception ("ToString method not found");
+ il.Emit (OpCodes.Callvirt, tostring.Method);
+ }else if (!targetValueType.IsValueType)
+ il.Emit(OpCodes.Castclass, targetValueType);
+ else if (b.Target.Property.PropertyType != targetValueType)
+ il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod( b.Target.Property.PropertyType ));
+ else
+ il.Emit(OpCodes.Unbox_Any, b.Target.Property.PropertyType);
+
+ il.Emit(OpCodes.Callvirt, b.Target.Property.GetSetMethod());
+ il.Emit (OpCodes.Br, endMethod);
+ i++;
+
+ }
+ il.MarkLabel(endMethod);
+ il.Emit(OpCodes.Pop);
+ il.Emit(OpCodes.Ret);
+
+ Delegate del = dm.CreateDelegate(ei.EventHandlerType, Bindings[0].Target.Instance);
+ MethodInfo addHandler = ei.GetAddMethod ();
+ addHandler.Invoke(grouped [0].Source.Instance, new object[] {del});
+ }
+ }
+
+ /// <summary>
+ /// Compile events expression in GOML attributes
+ /// </summary>
+ /// <param name="es">Event binding details</param>
+ public static void CompileEventSource(Binding binding)
+ {
+ #if DEBUG_BINDING
+ Debug.WriteLine ("\tCompile Event Source => " + binding.ToString());
+ #endif
+
+ Type target_type = binding.Target.Instance.GetType();
+
+ #region Retrieve EventHandler parameter type
+ MethodInfo evtInvoke = binding.Target.Event.EventHandlerType.GetMethod ("Invoke");
+ ParameterInfo[] evtParams = evtInvoke.GetParameters ();
+ Type handlerArgsType = evtParams [1].ParameterType;
+ #endregion
+
+ Type[] args = {typeof(object), typeof(object),handlerArgsType};
+ DynamicMethod dm = new DynamicMethod(binding.NewDynMethodId,
+ typeof(void),
+ args,
+ target_type);
+
+
+ #region IL generation
+ ILGenerator il = dm.GetILGenerator(256);
+
+ string src = binding.Expression.Trim();
+
+ if (! (src.StartsWith("{") || src.EndsWith ("}")))
+ throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.Target.Member.Name, binding.Expression));
+
+ src = src.Substring (1, src.Length - 2);
+ string[] srcLines = src.Split (new char[] { ';' });
+
+ foreach (string srcLine in srcLines) {
+ string statement = srcLine.Trim ();
+
+ string[] operandes = statement.Split (new char[] { '=' });
+ if (operandes.Length < 2) //not an affectation
+ {
+ continue;
+ }
+ string lop = operandes [0].Trim ();
+ string rop = operandes [operandes.Length-1].Trim ();
+
+ #region LEFT OPERANDES
+ GraphicObject lopObj = binding.Target.Instance as GraphicObject; //default left operand base object is
+ //the first arg (object sender) of the event handler
+
+ il.Emit(OpCodes.Ldarg_0); //load sender ref onto the stack
+
+ string[] lopParts = lop.Split (new char[] { '.' });
+ if (lopParts.Length > 1) {//should search also for member of es.Source
+ MethodInfo FindByNameMi = typeof(GraphicObject).GetMethod("FindByName");
+ for (int j = 0; j < lopParts.Length - 1; j++) {
+ il.Emit (OpCodes.Ldstr, lopParts[j]);
+ il.Emit(OpCodes.Callvirt, FindByNameMi);
+ }
+ }
+
+ int i = lopParts.Length -1;
+
+ MemberInfo[] lopMbis = lopObj.GetType().GetMember (lopParts[i]);
+
+ if (lopMbis.Length<1)
+ throw new Exception (string.Format("CROW BINDING: Member not found '{0}'", lop));
+
+ OpCode lopSetOC;
+ dynamic lopSetMbi;
+ Type lopT = null;
+ switch (lopMbis[0].MemberType) {
+ case MemberTypes.Property:
+ PropertyInfo lopPi = target_type.GetProperty (lopParts[i]);
+ MethodInfo dstMi = lopPi.GetSetMethod ();
+ lopT = lopPi.PropertyType;
+ lopSetMbi = dstMi;
+ lopSetOC = OpCodes.Callvirt;
+ break;
+ case MemberTypes.Field:
+ FieldInfo dstFi = target_type.GetField(lopParts[i]);
+ lopT = dstFi.FieldType;
+ lopSetMbi = dstFi;
+ lopSetOC = OpCodes.Stfld;
+ break;
+ default:
+ throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i]));
+ }
+ #endregion
+
+ #region RIGHT OPERANDES
+ if (rop.StartsWith("\'")){
+ if (!rop.EndsWith("\'"))
+ throw new Exception (string.Format
+ ("GOML:malformed string constant in handler: {0}", rop));
+ string strcst = rop.Substring (1, rop.Length - 2);
+
+ il.Emit(OpCodes.Ldstr,strcst);
+
+ }else{
+ if (lopT.IsEnum)
+ throw new NotImplementedException();
+
+ MethodInfo lopParseMi = lopT.GetMethod("Parse");
+ if (lopParseMi == null)
+ throw new Exception (string.Format
+ ("GOML:no parse method found in: {0}", lopT.Name));
+ il.Emit(OpCodes.Ldstr, rop);
+ il.Emit(OpCodes.Callvirt, lopParseMi);
+ il.Emit(OpCodes.Unbox_Any, lopT);
+ }
+
+ #endregion
+
+ //emit left operand assignment
+ il.Emit(lopSetOC, lopSetMbi);
+ }
+
+ il.Emit(OpCodes.Ret);
+
+ #endregion
+
+ Delegate del = dm.CreateDelegate(binding.Target.Event.EventHandlerType, binding.Target.Instance);
+ MethodInfo addHandler = binding.Target.Event.GetAddMethod ();
+ addHandler.Invoke(binding.Target.Instance, new object[] {del});
+
+ binding.Resolved = true;
+ }
+
#region conversions
internal static MethodInfo GetConvertMethod( Type targetType )
#if DEBUG_BINDING
Debug.WriteLine ("Resolve Bindings => " + this.ToString ());
#endif
- //grouped bindings by Instance of Source
- Dictionary<object,List<Binding>> resolved = new Dictionary<object, List<Binding>>();
- foreach (Binding b in Bindings) {
- if (b.Resolved)
- continue;
-
- if (b.Target.Member.MemberType == MemberTypes.Event) {
- if (b.Expression.StartsWith("{")){
- CompileEventSource(b);
- continue;
- }
- if (!b.FindTarget ())
- continue;
- //register handler for event
- if (b.Source.Method == null) {
- Debug.WriteLine ("\tError: Handler Method not found: " + b.ToString());
- continue;
- }
- try {
- MethodInfo addHandler = b.Target.Event.GetAddMethod ();
- Delegate del = Delegate.CreateDelegate (b.Target.Event.EventHandlerType, b.Source.Instance, b.Source.Method);
- addHandler.Invoke (this, new object[] { del });
-
- #if DEBUG_BINDING
- Debug.WriteLine ("\tHandler binded => " + b.ToString());
- #endif
- b.Resolved = true;
- } catch (Exception ex) {
- Debug.WriteLine ("\tERROR: " + ex.ToString());
- }
- continue;
- }
-
- if (!b.FindTarget ())
- continue;
-
- List<Binding> bindings = null;
- if (!resolved.TryGetValue (b.Source.Instance, out bindings)) {
- bindings = new List<Binding> ();
- resolved [b.Source.Instance] = bindings;
- }
- bindings.Add (b);
- b.Resolved = true;
-
- }
-
- MethodInfo stringEquals = typeof(string).GetMethod
- ("Equals", new Type[3] {typeof(string), typeof(string), typeof(StringComparison)});
- Type sourceType = this.GetType();
- EventInfo ei = typeof(IValueChange).GetEvent("ValueChanged");
- MethodInfo evtInvoke = ei.EventHandlerType.GetMethod ("Invoke");
- ParameterInfo[] evtParams = evtInvoke.GetParameters ();
- Type handlerArgsType = evtParams [1].ParameterType;
- Type[] args = {typeof(object), typeof(object),handlerArgsType};
- FieldInfo fiNewValue = typeof(ValueChangeEventArgs).GetField("NewValue");
- FieldInfo fiMbName = typeof(ValueChangeEventArgs).GetField("MemberName");
-
- //group;only one dynMethods by target (valuechanged event source)
- //changed value name tested in switch
- //IEnumerable<Binding[]> groupedByTarget = resolved.GroupBy (g => g.Target.Instance, g => g, (k, g) => g.ToArray ());
- foreach (List<Binding> grouped in resolved.Values) {
- int i = 0;
- Type targetType = grouped[0].Source.Instance.GetType();
-
- DynamicMethod dm = null;
- ILGenerator il = null;
-
- System.Reflection.Emit.Label[] jumpTable = null;
- System.Reflection.Emit.Label endMethod = new System.Reflection.Emit.Label();
-
- #region Retrieve EventHandler parameter type
- //EventInfo ei = targetType.GetEvent ("ValueChanged");
- //no dynamic update if ValueChanged interface is not implemented
- if (targetType.GetInterfaces().Contains(typeof(IValueChange))){
- dm = new DynamicMethod(grouped[0].NewDynMethodId,
- MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
- CallingConventions.Standard,
- typeof(void),
- args,
- sourceType,true);
-
- il = dm.GetILGenerator(256);
-
- endMethod = il.DefineLabel();
- jumpTable = new System.Reflection.Emit.Label[grouped.Count];
- for (i = 0; i < grouped.Count; i++)
- jumpTable [i] = il.DefineLabel ();
- il.DeclareLocal(typeof(string));
- il.DeclareLocal(typeof(object));
-
- il.Emit(OpCodes.Nop);
- il.Emit(OpCodes.Ldarg_0);
- //il.Emit(OpCodes.Isinst, sourceType);
- //push new value onto stack
- il.Emit(OpCodes.Ldarg_2);
- il.Emit(OpCodes.Ldfld, fiNewValue);
- il.Emit(OpCodes.Stloc_1);
- //push name
- il.Emit(OpCodes.Ldarg_2);
- il.Emit(OpCodes.Ldfld, fiMbName);
- il.Emit(OpCodes.Stloc_0);
- il.Emit(OpCodes.Ldloc_0);
- il.Emit(OpCodes.Brfalse, endMethod);
- }
- #endregion
-
- i = 0;
- foreach (Binding b in grouped) {
- #region initialize target with actual value
- object targetValue = null;
- if (b.Source.Member != null){
- if (b.Source.Member.MemberType == MemberTypes.Property)
- targetValue = b.Source.Property.GetGetMethod ().Invoke (b.Source.Instance, null);
- else if (b.Source.Member.MemberType == MemberTypes.Field)
- targetValue = b.Source.Field.GetValue (b.Source.Instance);
- else if (b.Source.Member.MemberType == MemberTypes.Method){
- MethodInfo mthSrc = b.Source.Method;
- if (mthSrc.IsDefined(typeof(ExtensionAttribute), false))
- targetValue = mthSrc.Invoke(null, new object[] {b.Source.Instance});
- else
- targetValue = mthSrc.Invoke(b.Source.Instance, null);
- }else
- throw new Exception ("unandled source member type for binding");
- }else if (string.IsNullOrEmpty(b.Expression))
- targetValue= grouped [0].Source.Instance;//empty binding exp=> bound to target object by default
- //TODO: handle other dest type conversions
- if (b.Target.Property.PropertyType == typeof(string)){
- if (targetValue == null){
- //set default value
-
- }else
- targetValue = targetValue.ToString ();
- }
- if (targetValue != null)
- b.Target.Property.GetSetMethod ().Invoke
- (this, new object[] { b.Target.Property.PropertyType.Cast(targetValue)});
- else
- b.Target.Property.GetSetMethod ().Invoke
- (this, new object[] { targetValue });
- #endregion
-
- //if no dyn update, skip jump table
- if (il == null)
- continue;
-
- il.Emit (OpCodes.Ldloc_0);
- if (b.Source.Member != null)
- il.Emit (OpCodes.Ldstr, b.Source.Member.Name);
- else
- il.Emit (OpCodes.Ldstr, b.Expression.Split('/').LastOrDefault());
- il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
- il.Emit (OpCodes.Callvirt, stringEquals);
- il.Emit (OpCodes.Brtrue, jumpTable[i]);
- i++;
- }
-
- if (il == null)
- continue;
-
- il.Emit (OpCodes.Br, endMethod);
-
- i = 0;
- foreach (Binding b in grouped) {
-
- il.MarkLabel (jumpTable [i]);
- il.Emit(OpCodes.Ldloc_1);
-
- //by default, target value type is deducted from source member type to allow
- //memberless binding, if targetMember exists, it will be used to determine target
- //value type for conversion
- Type targetValueType = b.Target.Property.PropertyType;
- if (b.Source.Member != null) {
- if (b.Source.Member.MemberType == MemberTypes.Property)
- targetValueType = b.Source.Property.PropertyType;
- else if (b.Source.Member.MemberType == MemberTypes.Field)
- targetValueType = b.Source.Field.FieldType;
- else
- throw new Exception ("unhandle target member type in binding");
- }
-
- if (b.Target.Property.PropertyType == typeof(string)) {
- MemberReference tostring = new MemberReference (b.Target.Instance);
- if (!tostring.FindMember ("ToString"))
- throw new Exception ("ToString method not found");
- il.Emit (OpCodes.Callvirt, tostring.Method);
- }else if (!targetValueType.IsValueType)
- il.Emit(OpCodes.Castclass, targetValueType);
- else if (b.Target.Property.PropertyType != targetValueType)
- il.Emit(OpCodes.Callvirt, CompilerServices.GetConvertMethod( b.Target.Property.PropertyType ));
- else
- il.Emit(OpCodes.Unbox_Any, b.Target.Property.PropertyType);
-
- il.Emit(OpCodes.Callvirt, b.Target.Property.GetSetMethod());
- il.Emit (OpCodes.Br, endMethod);
- i++;
-
- }
- il.MarkLabel(endMethod);
- il.Emit(OpCodes.Pop);
- il.Emit(OpCodes.Ret);
-
- Delegate del = dm.CreateDelegate(ei.EventHandlerType, this);
- MethodInfo addHandler = ei.GetAddMethod ();
- addHandler.Invoke(grouped [0].Source.Instance, new object[] {del});
- }
+ CompilerServices.ResolveBindings (Bindings);
}
- /// <summary>
- /// Compile events expression in GOML attributes
- /// </summary>
- /// <param name="es">Event binding details</param>
- public void CompileEventSource(Binding binding)
- {
- #if DEBUG_BINDING
- Debug.WriteLine ("\tCompile Event Source => " + binding.ToString());
- #endif
-
- Type sourceType = this.GetType();
-
- #region Retrieve EventHandler parameter type
- MethodInfo evtInvoke = binding.Target.Event.EventHandlerType.GetMethod ("Invoke");
- ParameterInfo[] evtParams = evtInvoke.GetParameters ();
- Type handlerArgsType = evtParams [1].ParameterType;
- #endregion
-
- Type[] args = {typeof(object), typeof(object),handlerArgsType};
- DynamicMethod dm = new DynamicMethod(binding.NewDynMethodId,
- typeof(void),
- args,
- sourceType);
-
-
- #region IL generation
- ILGenerator il = dm.GetILGenerator(256);
-
- string src = binding.Expression.Trim();
-
- if (! (src.StartsWith("{") || src.EndsWith ("}")))
- throw new Exception (string.Format("GOML:Malformed {0} Event handler: {1}", binding.Target.Member.Name, binding.Expression));
-
- src = src.Substring (1, src.Length - 2);
- string[] srcLines = src.Split (new char[] { ';' });
-
- foreach (string srcLine in srcLines) {
- string statement = srcLine.Trim ();
-
- string[] operandes = statement.Split (new char[] { '=' });
- if (operandes.Length < 2) //not an affectation
- {
- continue;
- }
- string lop = operandes [0].Trim ();
- string rop = operandes [operandes.Length-1].Trim ();
-
- #region LEFT OPERANDES
- GraphicObject lopObj = this; //default left operand base object is
- //the first arg (object sender) of the event handler
-
- il.Emit(OpCodes.Ldarg_0); //load sender ref onto the stack
-
- string[] lopParts = lop.Split (new char[] { '.' });
- if (lopParts.Length > 1) {//should search also for member of es.Source
- MethodInfo FindByNameMi = typeof(GraphicObject).GetMethod("FindByName");
- for (int j = 0; j < lopParts.Length - 1; j++) {
- il.Emit (OpCodes.Ldstr, lopParts[j]);
- il.Emit(OpCodes.Callvirt, FindByNameMi);
- }
- }
- int i = lopParts.Length -1;
-
- MemberInfo[] lopMbis = lopObj.GetType().GetMember (lopParts[i]);
-
- if (lopMbis.Length<1)
- throw new Exception (string.Format("CROW BINDING: Member not found '{0}'", lop));
-
- OpCode lopSetOC;
- dynamic lopSetMbi;
- Type lopT = null;
- switch (lopMbis[0].MemberType) {
- case MemberTypes.Property:
- PropertyInfo lopPi = sourceType.GetProperty (lopParts[i]);
- MethodInfo dstMi = lopPi.GetSetMethod ();
- lopT = lopPi.PropertyType;
- lopSetMbi = dstMi;
- lopSetOC = OpCodes.Callvirt;
- break;
- case MemberTypes.Field:
- FieldInfo dstFi = sourceType.GetField(lopParts[i]);
- lopT = dstFi.FieldType;
- lopSetMbi = dstFi;
- lopSetOC = OpCodes.Stfld;
- break;
- default:
- throw new Exception (string.Format("GOML:member type not handle: {0}", lopParts[i]));
- }
- #endregion
-
- #region RIGHT OPERANDES
- if (rop.StartsWith("\'")){
- if (!rop.EndsWith("\'"))
- throw new Exception (string.Format
- ("GOML:malformed string constant in handler: {0}", rop));
- string strcst = rop.Substring (1, rop.Length - 2);
-
- il.Emit(OpCodes.Ldstr,strcst);
-
- }else{
- if (lopT.IsEnum)
- throw new NotImplementedException();
-
- MethodInfo lopParseMi = lopT.GetMethod("Parse");
- if (lopParseMi == null)
- throw new Exception (string.Format
- ("GOML:no parse method found in: {0}", lopT.Name));
- il.Emit(OpCodes.Ldstr, rop);
- il.Emit(OpCodes.Callvirt, lopParseMi);
- il.Emit(OpCodes.Unbox_Any, lopT);
- }
-
- #endregion
-
- //emit left operand assignment
- il.Emit(lopSetOC, lopSetMbi);
- }
-
- il.Emit(OpCodes.Ret);
-
- #endregion
-
- Delegate del = dm.CreateDelegate(binding.Target.Event.EventHandlerType,this);
- MethodInfo addHandler = binding.Target.Event.GetAddMethod ();
- addHandler.Invoke(this, new object[] {del});
-
- binding.Resolved = true;
- }
/// <summary>
/// Remove dynamic delegates by ids from dataSource
/// and delete ref of this in Shared interface refs