aboutsummaryrefslogtreecommitdiffstatsci
path: root/src
diff options
context:
space:
mode:
authorjpbruyere <jp.bruyere@hotmail.com>2016-11-22 11:01:58 +0100
committerjpbruyere <jp.bruyere@hotmail.com>2016-11-22 11:01:58 +0100
commit19fd0792d6b89a8fbe39cf5069f0dd02fa548b64 (patch)
treeba483e320d1a2a9a8f58920e61f717a21ffa441d /src
parent4fb8b3a075bd8232be6fdcbb1f5a3b45265d33b4 (diff)
graphic tree bindings valuechanges implementation
Diffstat (limited to 'src')
-rw-r--r--src/CompilerServices/CompilerServices.cs12
-rw-r--r--src/GraphicObjects/GraphicObject.cs2
-rw-r--r--src/IML/Context.cs12
-rw-r--r--src/IML/MemberAddress.cs3
-rw-r--r--src/IML/Node.cs45
-rw-r--r--src/IML/NodeAddress.cs26
-rw-r--r--src/Instantiator.cs307
7 files changed, 268 insertions, 139 deletions
diff --git a/src/CompilerServices/CompilerServices.cs b/src/CompilerServices/CompilerServices.cs
index 18bc78ea..85e240e9 100644
--- a/src/CompilerServices/CompilerServices.cs
+++ b/src/CompilerServices/CompilerServices.cs
@@ -12,7 +12,6 @@ namespace Crow
{
public static class CompilerServices
{
- static MethodInfo miAddBinding = typeof(GraphicObject).GetMethod ("BindMember");
static FieldInfo miSetCurIface = typeof(GraphicObject).GetField ("currentInterface",
BindingFlags.NonPublic | BindingFlags.Instance);
internal static MethodInfo stringEquals = typeof (string).GetMethod
@@ -40,7 +39,8 @@ namespace Crow
#region ValueChange Reflexion member info
internal static EventInfo eiValueChange = typeof (IValueChange).GetEvent ("ValueChanged");
internal static MethodInfo miInvokeValueChange = eiValueChange.EventHandlerType.GetMethod ("Invoke");
- internal static Type [] argsValueChange = { typeof (object), typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
+ internal static Type [] argsBoundValueChange = { typeof (object), typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
+ internal static Type [] argsValueChange = { typeof (object), miInvokeValueChange.GetParameters () [1].ParameterType };
internal static FieldInfo fiNewValue = typeof (ValueChangeEventArgs).GetField ("NewValue");
internal static FieldInfo fiMbName = typeof (ValueChangeEventArgs).GetField ("MemberName");
internal static MethodInfo miValueChangeAdd = eiValueChange.GetAddMethod ();
@@ -69,12 +69,6 @@ namespace Crow
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Stfld, miSetCurIface);
}
- public static void emitBindingCreation(ILGenerator il, string memberName, string expression){
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldstr, memberName);
- il.Emit (OpCodes.Ldstr, expression);
- il.Emit (OpCodes.Callvirt, miAddBinding);
- }
public static void EmitSetValue(ILGenerator il, PropertyInfo pi, object val){
il.Emit (OpCodes.Ldloc_0);
@@ -267,7 +261,7 @@ namespace Crow
MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
CallingConventions.Standard,
typeof (void),
- argsValueChange,
+ argsBoundValueChange,
target_Type, true);
il = dm.GetILGenerator (256);
diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs
index f9b58e00..2cdc2aef 100644
--- a/src/GraphicObjects/GraphicObject.cs
+++ b/src/GraphicObjects/GraphicObject.cs
@@ -659,7 +659,7 @@ namespace Crow
string expression;
if (!getDefaultEvent(ei, styling, out expression))
continue;
- CompilerServices.emitBindingCreation (il, ei.Name, expression);
+ //CompilerServices.emitBindingCreation (il, ei.Name, expression);
}
foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
diff --git a/src/IML/Context.cs b/src/IML/Context.cs
index 44a9018b..e5d33374 100644
--- a/src/IML/Context.cs
+++ b/src/IML/Context.cs
@@ -44,13 +44,15 @@ namespace Crow.IML
//public SubNodeType curSubNodeType;
public Stack<Node> nodesStack = new Stack<Node> ();
- public Dictionary<string, string> Names = new Dictionary<string, string> ();
+ public Dictionary<string, List<NodeAddress>> Names = new Dictionary<string, List<NodeAddress>>();
public Dictionary<string, Dictionary<string, MemberAddress>> PropertyBindings = new Dictionary<string, Dictionary<string, MemberAddress>> ();
- public Dictionary<NodeAddress, Dictionary<string, MemberAddress>> Bindings =
- new Dictionary<NodeAddress, Dictionary<string, MemberAddress>>();
- public List<DataSourceBinding> DataSourceBindings = new List<DataSourceBinding>();
-
+ public Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>> Bindings =
+ new Dictionary<NodeAddress, Dictionary<string, List<MemberAddress>>>();
+ //public List<DataSourceBinding> DataSourceBindings = new List<DataSourceBinding>();
+ public Dictionary<NamedNodeAddress, Dictionary<string, MemberAddress>> NamedBindings =
+ new Dictionary<NamedNodeAddress, Dictionary<string, MemberAddress>>();
+
public Context (Type rootType)
{
RootType = rootType;
diff --git a/src/IML/MemberAddress.cs b/src/IML/MemberAddress.cs
index 89a293c3..7f3c93da 100644
--- a/src/IML/MemberAddress.cs
+++ b/src/IML/MemberAddress.cs
@@ -30,9 +30,10 @@ namespace Crow.IML
public struct MemberAddress
{
string memberName;
- MemberInfo member;
+ public MemberInfo member;
public NodeAddress Address;
+ public PropertyInfo Property { get { return member as PropertyInfo; }}
// public string Name {
// get { return memberName; }
// set { memberName = value; }
diff --git a/src/IML/Node.cs b/src/IML/Node.cs
index 9bc8f82a..a503a3bb 100644
--- a/src/IML/Node.cs
+++ b/src/IML/Node.cs
@@ -20,6 +20,8 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
using System;
using System.Reflection;
+using System.Reflection.Emit;
+using System.Collections.Generic;
namespace Crow.IML
{
@@ -43,24 +45,19 @@ namespace Crow.IML
#region Equality Compare
public override bool Equals (object obj)
{
- return obj is Node && this == (Node)obj;
+ if (obj == null)
+ return false;
+ Node n = (Node)obj;
+ return CrowType == n.CrowType && Index == n.Index;
}
public override int GetHashCode ()
{
return CrowType.GetHashCode () ^ Index.GetHashCode ();
}
- public static bool operator == (Node x, Node y)
- {
- return x.CrowType == y.CrowType && x.Index == y.Index;
- }
- public static bool operator != (Node x, Node y)
- {
- return !(x == y);
- }
#endregion
- public bool IsTemplate {
- get { return typeof (TemplatedControl).IsAssignableFrom (CrowType) && Index == 0; }
+ public bool HasTemplate {
+ get { return typeof (TemplatedControl).IsAssignableFrom (CrowType);}
}
public MethodInfo AddMethod {
get {
@@ -69,14 +66,36 @@ namespace Crow.IML
if (typeof (Container).IsAssignableFrom (CrowType))
return CompilerServices.miSetChild;
if (typeof (TemplatedContainer).IsAssignableFrom (CrowType))
- return Index == 0 ? CompilerServices.miLoadTmp : CompilerServices.miSetContent;
+ return Index < 0 ? CompilerServices.miLoadTmp : CompilerServices.miSetContent;
if (typeof (TemplatedGroup).IsAssignableFrom (CrowType))
- return Index == 0 ? CompilerServices.miLoadTmp : CompilerServices.miAddItem;
+ return Index < 0 ? CompilerServices.miLoadTmp : CompilerServices.miAddItem;
if (typeof (TemplatedControl).IsAssignableFrom (CrowType))
return CompilerServices.miLoadTmp;
return null;
}
}
+ public void EmitGetInstance (ILGenerator il){
+ if (typeof (Group).IsAssignableFrom (CrowType)) {
+ il.Emit (OpCodes.Ldfld, typeof(Group).GetField ("children", BindingFlags.Instance | BindingFlags.NonPublic));
+ il.Emit(OpCodes.Ldc_I4, Index);
+ il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+ return;
+ }
+ if (typeof(Container).IsAssignableFrom (CrowType) || Index < 0) {
+ il.Emit (OpCodes.Ldfld, typeof(PrivateContainer).GetField ("child", BindingFlags.Instance | BindingFlags.NonPublic));
+ return;
+ }
+ if (typeof(TemplatedContainer).IsAssignableFrom (CrowType)) {
+ il.Emit (OpCodes.Callvirt, typeof(TemplatedContainer).GetProperty ("Content").GetGetMethod ());
+ return;
+ }
+ if (typeof(TemplatedGroup).IsAssignableFrom (CrowType)) {
+ il.Emit (OpCodes.Callvirt, typeof(TemplatedGroup).GetProperty ("Items").GetGetMethod ());
+ il.Emit(OpCodes.Ldc_I4, Index);
+ il.Emit (OpCodes.Callvirt, typeof(List<GraphicObject>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
+ return;
+ }
+ }
public static implicit operator string (Node sn)
{
diff --git a/src/IML/NodeAddress.cs b/src/IML/NodeAddress.cs
index 12ecec38..b7517b1f 100644
--- a/src/IML/NodeAddress.cs
+++ b/src/IML/NodeAddress.cs
@@ -28,9 +28,16 @@ namespace Crow.IML
{
public NodeAddress (Node[] nodes) : base(nodes) {
}
+
+ public Type NodeType { get { return this[this.Count -1].CrowType; }}
+
public override bool Equals (object obj)
{
- return obj is NodeAddress && this == obj as NodeAddress;
+ if (obj == null)
+ return false;
+
+ NodeAddress na = (NodeAddress)obj;
+ return this.SequenceEqual (na);
}
public override int GetHashCode ()
{
@@ -41,21 +48,20 @@ namespace Crow.IML
return hash;
}
}
- public static bool operator == (NodeAddress x, NodeAddress y)
- {
- return x.SequenceEqual (y);
- }
- public static bool operator != (NodeAddress x, NodeAddress y)
- {
- return !(x == y);
- }
public override string ToString ()
{
string tmp = "";
foreach (Node n in this)
- tmp += string.Format ("{0}[{1}];", n.CrowType.Name, n.Index);
+ tmp += string.Format ("{0};", n.Index);
return tmp;
}
}
+
+ public class NamedNodeAddress : NodeAddress {
+ public string Name;
+ public NamedNodeAddress(string name, Node[] nodes) : base(nodes){
+ Name = name;
+ }
+ }
}
diff --git a/src/Instantiator.cs b/src/Instantiator.cs
index 0bd33278..e6924447 100644
--- a/src/Instantiator.cs
+++ b/src/Instantiator.cs
@@ -85,7 +85,8 @@ namespace Crow
List<DynamicMethod> dsValueChangedDynMeths = new List<DynamicMethod>();
List<Delegate> dataSourceChangedDelegates = new List<Delegate>();
-
+ Dictionary<string, Delegate> bindingDelegates = new Dictionary<string, Delegate>();//valuechanged del
+ Dictionary<string, Delegate> bindingInitializer = new Dictionary<string, Delegate>();//initialize with actual values of binding origine
#region IML parsing
/// <summary>
/// Parses IML and build a dynamic method that will be used to instanciate one or multiple occurence of the IML file or fragment
@@ -132,7 +133,7 @@ namespace Crow
ctx.il.Emit (OpCodes.Ldloc_0);//save current go onto the stack if child has to be added
- if (ctx.CurrentNode.IsTemplate)
+ if (ctx.CurrentNode.HasTemplate)
emitTemplateLoad (ctx, tmpXml);
emitGOLoad (ctx, tmpXml);
@@ -140,6 +141,7 @@ namespace Crow
ctx.il.Emit (OpCodes.Pop);//pop saved ref to current object
}
void emitTemplateLoad (Context ctx, string tmpXml) {
+ ctx.CurrentNode.Index--;//template indexing use -1
//if its a template, first read template elements
using (XmlTextReader reader = new XmlTextReader (tmpXml, XmlNodeType.Element, null)) {
List<string []> itemTemplateIds = new List<string []> ();
@@ -248,23 +250,22 @@ namespace Crow
if (mi == null)
throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNode.CrowType.Name);
if (mi.MemberType == MemberTypes.Event) {
- CompilerServices.emitBindingCreation (ctx.il, reader.Name, reader.Value);
+ //CompilerServices.emitBindingCreation (ctx.il, reader.Name, reader.Value);
continue;
}
PropertyInfo pi = mi as PropertyInfo;
if (pi == null)
throw new Exception ("Member '" + reader.Name + "' not found in " + ctx.CurrentNode.CrowType.Name);
- //if (pi.Name == "Name")
- // ctx.Names.Add (reader.Value, Node.AddressToString (ctx.nodesStack.ToArray ()));
-
- if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase)) {
-
-
+ if (pi.Name == "Name"){
+ if (!ctx.Names.ContainsKey(reader.Value))
+ ctx.Names[reader.Value] = new List<NodeAddress>();
+ ctx.Names[reader.Value].Add(ctx.CurrentNodeAddress);
+ }
+
+ if (reader.Value.StartsWith ("{", StringComparison.OrdinalIgnoreCase))
readPropertyBinding (ctx, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
-
- //CompilerServices.emitBindingCreation (reader.il, reader.Name, reader.Value.Substring (1, reader.Value.Length - 2));
- } else
+ else
CompilerServices.EmitSetValue (ctx.il, pi, reader.Value);
}
@@ -280,6 +281,8 @@ namespace Crow
ctx.nodesStack.Push (ctx.CurrentNode);
readChildren (reader, ctx);
ctx.nodesStack.Pop ();
+
+ emitCheckAndBindValueChanged (ctx);
}
}
/// <summary>
@@ -338,6 +341,29 @@ namespace Crow
}
#endregion
+
+ void emitCheckAndBindValueChanged(Context ctx){
+ System.Reflection.Emit.Label labContinue = ctx.il.DefineLabel ();
+ string strNA = ctx.CurrentNodeAddress.ToString ();
+ //first, test if current node is in bindingDelegate dictionnary
+ ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("bindingDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
+ ctx.il.Emit (OpCodes.Ldstr, strNA);//load binding id for current node
+ ctx.il.Emit (OpCodes.Call, typeof(Dictionary<string,Delegate>).GetMethod ("ContainsKey"));
+
+ ctx.il.Emit (OpCodes.Brfalse, labContinue);//if not present, do nothing
+
+ //fetch delegate
+ ctx.il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
+ ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("bindingDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
+ ctx.il.Emit (OpCodes.Ldstr, strNA);//load binding id for current node
+ ctx.il.Emit (OpCodes.Call, typeof(Dictionary<string, Delegate>).GetMethod ("get_Item", new Type[] { typeof(string) }));
+
+ //attach to valuechanged handler
+ ctx.il.Emit(OpCodes.Callvirt, typeof(IValueChange).GetEvent("ValueChanged").AddMethod);
+
+ ctx.il.MarkLabel (labContinue);
+ }
/// <summary>
/// Tries the find target.
/// </summary>
@@ -360,64 +386,62 @@ namespace Crow
twoWay = true;
}
- string [] bindingExp = expression.Split ('/');
+ string[] bindingExp = expression.Split ('/');
if (bindingExp.Length == 1) {
//datasource binding
- processDataSourceBinding(ctx, sourceMember, bindingExp [0]);
+ processDataSourceBinding (ctx, sourceMember, bindingExp [0]);
+ return;
+ }
+
+ NodeAddress currentNode = ctx.CurrentNodeAddress;
+ int ptr = currentNode.Count - 1;
+ //if exp start with '/' => Graphic tree parsing start at source
+ if (string.IsNullOrEmpty (bindingExp [0])) {
+ //TODO:
+ } else if (bindingExp [0] == ".") { //search template root
+ while (ptr > 0) {
+ ptr--;
+ if (typeof(TemplatedControl).IsAssignableFrom (currentNode [ptr].CrowType))
+ break;
+ }
+ } else if (bindingExp [0] == "..") { //search starting at current node
+ int levelUp = bindingExp.Length - 1;
+ if (levelUp > ptr)
+ throw new Exception ("Binding error: try to bind outside IML source");
+ ptr -= levelUp;
}
-// else {
-// int ptr = 0;
-//
-// //if exp start with '/' => Graphic tree parsing start at source
-// if (string.IsNullOrEmpty (bindingExp [0]))
-// ptr++;
-// else if (bindingExp[0] == "."){ //search template root
-// do {
-// target = new NodeAddress(ctx.
-// if (tmpTarget == null)
-// return false;
-// if (tmpTarget is Interface)
-// throw new Exception ("Not in Templated Control");
-// } while (!(tmpTarget is TemplatedControl));
-// ptr++;
-// }
-// while (ptr < bindingExp.Length - 1) {
-// if (tmpTarget == null) {
-// #if DEBUG_BINDING
-// Debug.WriteLine ("\tTarget not found => " + this.ToString());
-// #endif
-// return false;
-// }
-// if (bindingExp [ptr] == "..")
-// tmpTarget = tmpTarget.LogicalParent;
-// else if (bindingExp [ptr] == ".") {
-// if (ptr > 0)
-// throw new Exception ("Syntax error in binding, './' may only appear in first position");
-// tmpTarget = Source.Instance as ILayoutable;
-// } else
-// tmpTarget = (tmpTarget as GraphicObject).FindByName (bindingExp [ptr]);
-// ptr++;
-// }
-//
-// if (tmpTarget == null) {
-// #if DEBUG_BINDING
-// Debug.WriteLine ("\tBinding Target not found => " + this.ToString());
-// #endif
-// return false;
-// }
-//
-// string [] bindTrg = bindingExp [ptr].Split ('.');
-//
-// if (bindTrg.Length == 1)
-// memberName = bindTrg [0];
-// else if (bindTrg.Length == 2) {
-// tmpTarget = (tmpTarget as GraphicObject).FindByName (bindTrg [0]);
-// memberName = bindTrg [1];
-// } else
-// throw new Exception ("Syntax error in binding, expected 'go dot member'");
-//
+ Node[] targetNode = new Node[ptr+1];
+ Array.Copy (currentNode.ToArray (), targetNode, ptr + 1);
+ NodeAddress targetNA = new NodeAddress (targetNode);
+
+ string [] bindTrg = bindingExp [currentNode.Count - 1 - ptr].Split ('.');
+
+ if (bindTrg.Length == 1)
+ memberName = bindTrg [0];
+ else if (bindTrg.Length == 2) {
+ //named target
+ //TODO:
+
+ memberName = bindTrg [1];
+ return;
+ } else
+ throw new Exception ("Syntax error in binding, expected 'go dot member'");
+
+ Dictionary<string, List<MemberAddress>> nodeBindings = null;
+ if (ctx.Bindings.ContainsKey (targetNA))
+ nodeBindings = ctx.Bindings [targetNA];
+ else {
+ nodeBindings = new Dictionary<string, List<MemberAddress>> ();
+ ctx.Bindings [targetNA] = nodeBindings;
+ }
+
+ if (!nodeBindings.ContainsKey (memberName))
+ nodeBindings [memberName] = new List<MemberAddress> ();
+ nodeBindings [memberName].Add (new MemberAddress (currentNode, sourceMember));
+
+ //
// if (tmpTarget == null) {
// #if DEBUG_BINDING
// Debug.WriteLine ("\tBinding Target not found => " + this.ToString());
@@ -441,12 +465,14 @@ namespace Crow
Debug.WriteLine ("Property less binding: " + Target + expression);
#endif
}
-
+ /// <summary>
+ /// create the valuechanged handler, the datasourcechanged handler and emit event handling
+ /// </summary>
void processDataSourceBinding(Context ctx, string sourceMember, string dataSourceMember){
#region create valuechanged method
DynamicMethod dm = new DynamicMethod ("dyn_valueChanged",
typeof (void),
- CompilerServices.argsValueChange, true);
+ CompilerServices.argsBoundValueChange, true);
ILGenerator il = dm.GetILGenerator (256);
@@ -476,6 +502,9 @@ namespace Crow
PropertyInfo piSource = ctx.CurrentNode.CrowType.GetProperty(sourceMember);
Type sourceValueType = piSource.PropertyType;
+ //il.Emit (OpCodes.Call, typeof(object).GetMethod("GetType"));
+ //il.Emit (OpCodes.Call, typeof(Type).GetProperty("IsValueType").GetGetMethod());
+
if (sourceValueType == typeof (string)) {
il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
} else if (!sourceValueType.IsValueType)
@@ -486,8 +515,6 @@ namespace Crow
il.Emit (OpCodes.Unbox_Any, sourceValueType);
il.Emit (OpCodes.Callvirt, piSource.GetSetMethod ());
- //il.Emit (OpCodes.Pop);
- //il.Emit (OpCodes.Pop);
il.MarkLabel (endMethod);
@@ -510,57 +537,38 @@ namespace Crow
CompilerServices.argsDSChange, true);
il = dm.GetILGenerator (256);
- //il.DeclareLocal (typeof(Object[]));
il.Emit (OpCodes.Nop);
-// //load new datasource onto the stack for handler addition at the end
+ //load new datasource onto the stack for handler addition at the end
il.Emit (OpCodes.Ldarg_2);
il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
- #region Load cached delegate
+ //first we have to create delegate from cached dynMethod bound to the GraphicObject currently instanced
+
+ //Load cached delegate
il.Emit(OpCodes.Ldarg_0);//load ref to this instanciator onto the stack
il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("dsValueChangedDynMeths", BindingFlags.Instance | BindingFlags.NonPublic));
- il.Emit(OpCodes.Ldc_I4, dmVC);
+ il.Emit(OpCodes.Ldc_I4, dmVC);//load index of dynmathod
il.Emit(OpCodes.Callvirt, typeof(List<DynamicMethod>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
- #endregion
//load ds changed eventhandlertype
il.Emit(OpCodes.Ldtoken, typeof(EventHandler<ValueChangeEventArgs>));
il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle", new
Type[1]{typeof(RuntimeTypeHandle)}));
- //typeof (GraphicObject).GetEvent ("DataSourceChanged").EventHandlerType;
- //il.Emit(OpCodes.Ldfld, typeof(CompilerServices).GetField("ehTypeDSChange", BindingFlags.Static | BindingFlags.NonPublic););
-
- //create object[] for delegate creation parameters
-// il.Emit (OpCodes.Ldc_I4_1);
-// il.Emit (OpCodes.Newarr, typeof(object));
-// il.Emit (OpCodes.Stloc_0);//save array ref
-// il.Emit (OpCodes.Ldloc_0);//load array ref onto the stack
-// il.Emit (OpCodes.Ldc_I4_0);//0 is the index of the dm in the array
-
- //load datasource change source
- il.Emit (OpCodes.Ldarg_1);
- //il.Emit (OpCodes.Ldfld, CompilerServices.fiDSCNewDS);
- //create bound delegate
- il.Emit (OpCodes.Call, CompilerServices.miCreateBoundDelegate);
- //set delegete as index 0 in the object array
-// il.Emit(OpCodes.Ldelem_I4);
+ il.Emit (OpCodes.Ldarg_1);//load datasource change source
+ il.Emit (OpCodes.Call, CompilerServices.miCreateBoundDelegate);//create bound delegate
//add new delegate to datasource valuechanged event
il.Emit(OpCodes.Callvirt, typeof(IValueChange).GetEvent("ValueChanged").AddMethod);//call add event //il.Emit(OpCodes.Pop);
- //il.Emit(OpCodes.Pop);
- //il.Emit(OpCodes.Pop);
- //il.Emit(OpCodes.Pop);
il.Emit (OpCodes.Ret);
-
- #endregion
-
+ //store dschange delegate in instatiator instance for access while instancing graphic object
int delDSIndex = dataSourceChangedDelegates.Count;
Delegate del = dm.CreateDelegate (CompilerServices.ehTypeDSChange, this);
dataSourceChangedDelegates.Add(del);
+ #endregion
#region Emit datasourcechanged handler binding in the loader context
ctx.il.Emit(OpCodes.Ldloc_0);//load ref to current graphic object
@@ -568,12 +576,111 @@ namespace Crow
ctx.il.Emit(OpCodes.Ldfld, typeof(Instantiator).GetField("dataSourceChangedDelegates", BindingFlags.Instance | BindingFlags.NonPublic));
ctx.il.Emit(OpCodes.Ldc_I4, delDSIndex);//load delegate index
ctx.il.Emit(OpCodes.Callvirt, typeof(List<DynamicMethod>).GetMethod("get_Item", new Type[] { typeof(Int32) }));
-
ctx.il.Emit(OpCodes.Callvirt, typeof(GraphicObject).GetEvent("DataSourceChanged").AddMethod);//call add event
#endregion
- //miValueChangeAdd.Invoke (grouped [0].Target.Instance, new object [] { del });
}
-
+
+ /// <summary>
+ /// Create and store in the instanciator the ValueChanged delegates
+ /// those delegates uses grtree functions to set destination value so they don't
+ /// need to be bound to destination instance as in the ancient system.
+ /// </summary>
+ void emitBindingDelegates(Context ctx){
+ foreach (KeyValuePair<NodeAddress,Dictionary<string, List<MemberAddress>>> bindings in ctx.Bindings ) {
+
+ Type origineNodeType = bindings.Key.NodeType;
+
+ //value changed dyn method
+ DynamicMethod dm = new DynamicMethod ("dyn_valueChanged",
+ typeof (void), CompilerServices.argsValueChange, true);
+
+ ILGenerator il = dm.GetILGenerator (256);
+
+ System.Reflection.Emit.Label [] jumpTable =
+ new System.Reflection.Emit.Label [bindings.Value.Count];
+ System.Reflection.Emit.Label endMethod = il.DefineLabel ();
+
+ il.DeclareLocal (typeof(object));
+
+ il.Emit (OpCodes.Nop);
+ il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+
+ //load source member name
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Ldfld, typeof(ValueChangeEventArgs).GetField ("MemberName"));
+
+ int i = 0;
+ foreach (KeyValuePair<string, List<MemberAddress>> bindingCase in bindings.Value ) {
+ Type origineType = origineNodeType.GetProperty (bindingCase.Key).PropertyType;
+
+ jumpTable [i] = il.DefineLabel ();
+ #region member name test
+ il.Emit (OpCodes.Ldstr, bindingCase.Key);//load name to test
+ il.Emit (OpCodes.Ldc_I4_4);//StringComparison.Ordinal
+ il.Emit (OpCodes.Callvirt, CompilerServices.stringEquals);
+ il.Emit (OpCodes.Brfalse, jumpTable [i]);//if not equal, jump to next case
+ #endregion
+
+ #region destination member affectations
+ foreach (MemberAddress ma in bindingCase.Value) {
+ //first we have to load destination instance onto the stack, it is access
+ //with graphic tree functions deducted from nodes topology
+ il.Emit (OpCodes.Ldarg_0);//load source instance of ValueChanged event
+
+ NodeAddress origine = bindings.Key;
+ NodeAddress destination = ma.Address;
+
+ if (origine.Count < destination.Count){
+ for (int j = origine.Count; j < destination.Count; j++)
+ destination[j].EmitGetInstance(il);
+ }else{
+ for (int j = destination.Count; j < origine.Count; j++)
+ il.Emit(OpCodes.Callvirt, typeof(ILayoutable).GetProperty("Parent").GetGetMethod());
+ }
+ //load new value
+ System.Reflection.Emit.Label labValueType = il.DefineLabel ();
+ il.Emit (OpCodes.Ldarg_1);
+ il.Emit (OpCodes.Ldfld, typeof (ValueChangeEventArgs).GetField ("NewValue"));
+
+ emitConvert(il,origineType, ma.Property.PropertyType);
+
+ //set value
+ il.Emit (OpCodes.Callvirt, ma.Property.GetSetMethod());
+
+ il.Emit (OpCodes.Br, endMethod);
+ il.MarkLabel (jumpTable [i]);
+ }
+ #endregion
+
+ i++;
+ }
+ il.MarkLabel (endMethod);
+ il.Emit (OpCodes.Ret);
+
+ bindingDelegates [bindings.Key.ToString()] = dm.CreateDelegate (typeof(EventHandler<ValueChangeEventArgs>));
+ }
+ }
+ void emitConvert(ILGenerator il, Type origType, Type destType){
+ if (destType == typeof (string))
+ il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+ else if (origType.IsValueType) {
+ if (destType != origType)
+ il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (destType));
+ else
+ il.Emit (OpCodes.Unbox_Any, destType);
+ }else
+ il.Emit (OpCodes.Castclass, destType);
+ }
+ void emitConvertWorking(ILGenerator il, Type sourceValueType){
+ if (sourceValueType == typeof (string)) {
+ il.Emit (OpCodes.Callvirt, CompilerServices.miObjToString);
+ } else if (!sourceValueType.IsValueType)
+ il.Emit (OpCodes.Castclass, sourceValueType);
+ else if (sourceValueType != sourceValueType) {
+ il.Emit (OpCodes.Callvirt, CompilerServices.GetConvertMethod (sourceValueType));
+ } else
+ il.Emit (OpCodes.Unbox_Any, sourceValueType);
+ }
//public string GetImlSourcesCode(){
// try {
// using (StreamReader sr = new StreamReader (imlPath))