private static void BuildPath(SerializedProperty prop, StringBuilder sw) { SerializedProperty cprop; SerializedProperty pprop; INPCBindingEditor.GetCPathProperties(prop, out cprop, out pprop); var oval = cprop.objectReferenceValue; if (oval == null) { return; } var ppath = new INPCBinding.PropertyPath(pprop.stringValue, oval.GetType()); if (!ppath.IsValid) { return; } if (_paths.Contains(ppath.PPath)) { return; } _paths.Add(ppath.PPath); sw.AppendFormat(@" ppa.Register( new[] {{ {0} }}, obj => {{ if(obj == null) return null; var v0 = (({1})obj).{2}; {3} }}, (obj, value) => {{ {4} }});", string.Join(",\r\n", ppath.PPath.Select(p => string.Format(" INPCBinding.PropertyPath.GetProperty(typeof({0}), \"{1}\")", GetFullName(p.DeclaringType), p.Name)) .ToArray()), GetFullName(ppath.PPath[0].DeclaringType), ppath.Parts[0], BuildGetterEnd(ppath), BuildSetterEnd(ppath)) .AppendLine().AppendLine(); }
static string BuildGetterEnd(INPCBinding.PropertyPath ppath) { if (ppath.Parts.Length == 1) { return(string.Format(" return v0;")); } var sb = new StringBuilder(); var i = 1; for (; i < ppath.Parts.Length - 1; i++) { sb.AppendFormat(" var v{0} = v{1}.{2}", i, i - 1, ppath.Parts[i]) .AppendLine() .AppendFormat(" if (v{0} == null) return null;", i) .AppendLine(); } sb.AppendFormat(" return v{0}.{1};", i - 1, ppath.Parts[i]); return(sb.ToString()); }
/// <summary> /// draw an INPCBinding.ComponentPath property /// </summary> /// <param name="position"></param> /// <param name="property"></param> /// <param name="label"></param> /// <param name="filter"></param> public static void DrawCRefProp(SerializedProperty property, GUIContent label, Type filter, bool resolveDataContext = true) { EditorGUILayout.LabelField(property.displayName); SerializedProperty cprop, pprop; GetCPathProperties(property, out cprop, out pprop); EditorGUI.indentLevel++; var position = EditorGUILayout.GetControlRect(true); ComponentReferenceDrawer.PropertyField(position, cprop); if (cprop.objectReferenceValue != null) { var name = "propfield" + (GUIUtility.GetControlID(FocusType.Keyboard) + 1); GUI.SetNextControlName(name); EditorGUILayout.PropertyField(pprop); var orv = cprop.objectReferenceValue; Type ortype; if (orv is DataContext && resolveDataContext) { ortype = (orv as DataContext).Type; } else { ortype = orv.GetType(); } if (ortype == null) { pprop.stringValue = null; } else { var path = new INPCBinding.PropertyPath(pprop.stringValue, ortype); Type rtype; var idx = Array.FindIndex(path.PPath, p => p == null); if (path.IsValid) { rtype = path.PPath.Length == 1 ? ortype : path.PPath[path.PPath.Length - 1].PropertyType; } else { rtype = idx - 1 < 0 ? ortype : path.PPath[idx - 1].PropertyType; } var lrect = GUILayoutUtility.GetLastRect(); EditorGUI.Toggle(new Rect(lrect.x + EditorGUIUtility.fieldWidth + 5, lrect.y, lrect.width, lrect.height), path.IsValid); var props = rtype.GetProperties(BindingFlags.Instance | BindingFlags.Public); if (GUI.GetNameOfFocusedControl() == name) { var propNames = props.Select(p => p.Name) .OrderByDescending( s => s.IndexOf(path.Parts.LastOrDefault() ?? "", StringComparison.OrdinalIgnoreCase) == 0) .ToArray(); var propstring = string.Join("\n", propNames); EditorGUILayout.HelpBox(propstring, MessageType.None); } } } else { pprop.stringValue = null; } EditorGUI.indentLevel--; }
/// <summary> /// draw an INPCBinding.ComponentPath property /// </summary> /// <param name="targetId"></param> /// <param name="property"></param> /// <param name="label"></param> /// <param name="filter"></param> /// <param name="resolveDataContext"></param> public static void DrawCRefProp(int targetId, string focusedControl, SerializedProperty property, GUIContent label, Type filter, bool resolveDataContext = true) { EditorGUILayout.LabelField(property.displayName); SerializedProperty cprop, pprop; GetCPathProperties(property, out cprop, out pprop); EditorGUI.indentLevel++; var position = EditorGUILayout.GetControlRect(true); ComponentReferenceDrawer.PropertyField(position, cprop); if (cprop.objectReferenceValue != null) { var name = "prop_" + property.propertyPath + "_" + targetId; GUI.SetNextControlName(name); EditorGUILayout.PropertyField(pprop); var orv = cprop.objectReferenceValue; Type ortype; if (orv is DataContext && resolveDataContext) { ortype = (orv as DataContext).Type; } else { ortype = orv.GetType(); } if (ortype == null) { // Handle invalid DataContext types if (!string.IsNullOrEmpty(pprop.stringValue)) { var style = new GUIStyle(EditorStyles.textField); style.normal.textColor = Color.red; EditorGUILayout.TextField(string.Format("Error: {0}/{1} is bound to property \"{2}\" of an invalid DataContext Type.", property.displayName, pprop.displayName, pprop.stringValue), style); } } else { var path = new INPCBinding.PropertyPath(pprop.stringValue, ortype); Type rtype; var idx = Array.FindIndex(path.PPath, p => p == null); if (path.IsValid) { rtype = path.PropertyType; } else { rtype = idx - 1 < 0 ? ortype : path.PPath[idx - 1].PropertyType; // Improve handling of invalid DataContext types var style = new GUIStyle(EditorStyles.textField); style.normal.textColor = Color.red; EditorGUILayout.TextField(string.Format("Error: {0}/{1} invalid property \"{2}\" of a valid DataContext.", property.displayName, pprop.displayName, pprop.stringValue), style); } var lrect = GUILayoutUtility.GetLastRect(); var props = rtype.GetProperties(BindingFlags.Instance | BindingFlags.Public); if (focusedControl == name) { var propNames = props.Select(p => p.Name) .OrderByDescending( s => s.IndexOf(path.Parts.LastOrDefault() ?? "", StringComparison.OrdinalIgnoreCase) == 0) .ToArray(); var propstring = string.Join("\n", propNames); EditorGUILayout.HelpBox(propstring, MessageType.None); } } } else { // Improve handling of invalid DataContext types if (!string.IsNullOrEmpty(pprop.stringValue)) { var style = new GUIStyle(EditorStyles.textField); style.normal.textColor = Color.red; EditorGUILayout.TextField(string.Format("Error: {0}/{1} is bound to property \"{2}\" of an invalid component object reference.", property.displayName, pprop.displayName, pprop.stringValue), style); } } EditorGUI.indentLevel--; }