aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/GraphicObjects/GraphicObject.cs
diff options
context:
space:
mode:
authorj-p <jp.bruyere@live.be>2016-03-16 10:41:22 +0000
committerj-p <jp.bruyere@live.be>2016-03-16 10:41:22 +0000
commit356bfaaed4f46a727ae033f37f362b062c8c32d9 (patch)
tree60d62ce23dbf7c1dc8ec5de4f0dcdb77eb66789c /src/GraphicObjects/GraphicObject.cs
parent6b0d7e5a317f4deb808b59f4393fb8b5d0488587 (diff)
parentc85cd50c4a6553679ebf92058aa1f609ede56d27 (diff)
Merge pull request #5 from jpbruyere/TwoWayBindings
Two way bindings
Diffstat (limited to 'src/GraphicObjects/GraphicObject.cs')
-rw-r--r--src/GraphicObjects/GraphicObject.cs338
1 files changed, 5 insertions, 333 deletions
diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs
index cddc918a..c526e909 100644
--- a/src/GraphicObjects/GraphicObject.cs
+++ b/src/GraphicObjects/GraphicObject.cs
@@ -156,6 +156,7 @@ namespace Crow
public event EventHandler<MouseMoveEventArgs> MouseLeave;
public event EventHandler<KeyboardKeyEventArgs> KeyDown;
public event EventHandler<KeyboardKeyEventArgs> KeyUp;
+ public event EventHandler<KeyPressEventArgs> KeyPress;
public event EventHandler Focused;
public event EventHandler Unfocused;
public event EventHandler<LayoutingEventArgs> LayoutChanged;
@@ -939,6 +940,9 @@ namespace Crow
public virtual void onKeyDown(object sender, KeyboardKeyEventArgs e){
KeyDown.Raise (sender, e);
}
+ public virtual void onKeyPress(object sender, KeyPressEventArgs e){
+ KeyPress.Raise (sender, e);
+ }
#endregion
#region Mouse handling
@@ -1055,342 +1059,10 @@ namespace Crow
#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