public void TreeView1_DragOver(object sender, DragEventArgs e) { InspectorNode targetTreeNode = ((FrameworkElement)e.OriginalSource).DataContext as InspectorNode; if (targetTreeNode == null) { return; } Object data = e.Data.GetData(typeof(Object)); if (data == null) { return; } Type dataType = data.GetType(); Type targetType = targetTreeNode.Type; if (targetType.IsAssignableFrom(dataType) || targetType == typeof(float) && dataType == typeof(double) || targetType == typeof(double) && dataType == typeof(float)) { e.Effects = DragDropEffects.Move; e.Handled = true; } else { e.Effects = DragDropEffects.None; e.Handled = true; } }
public void TreeView1_Drop(object sender, DragEventArgs e) { InspectorNode targetTreeNode = ((FrameworkElement)e.OriginalSource).DataContext as InspectorNode; if (targetTreeNode == null) { return; } Object data = e.Data.GetData(typeof(Object)); if (data == null) { return; } Type dataType = data.GetType(); Type targetType = targetTreeNode.Type; if (targetType.IsAssignableFrom(dataType)) { targetTreeNode.Property = data; e.Handled = true; } else if (targetType == typeof(float) && dataType == typeof(double)) { targetTreeNode.Property = (float)((double)data); } else if (targetType == typeof(double) && dataType == typeof(float)) { targetTreeNode.Property = (double)((float)data); } }
void node_Drop(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(ParameterInfo.ParameterType)) { Parameter = e.Data.GetData(ParameterInfo.ParameterType) as InspectorNode; } }
/// <summary> /// Adds the object to the inspector logger so the user /// can inspect its fields, properties and methods. /// </summary> /// <param name="name">A friendly name to use in the Inspector Tree.</param> /// <param name="o">The object to inspect.</param> /// <param name="autoExpand">Determines whether the node should automatically expand when added to the Inspector Tree.</param> internal void Watch(InspectorNode node) { if (node == null) { return; } WatchedNodes.Add(node); }
public void Watch_Click(object sender, RoutedEventArgs e) { InspectorNode item = ((InspectorNode)TreeView1.SelectedItem); if (item != null) { GearsetResources.Console.Inspector.Watch(item); } }
void TreeView1_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e) { InspectorNode node = e.NewValue as InspectorNode; if (node != null) { Window.methods.DataContext = node.Methods; Window.nodeToExpandAfterUpdate = node; } }
public void ShowPrivate_Click(object sender, RoutedEventArgs e) { InspectorNode item = ((InspectorNode)TreeView1.SelectedItem); if (item == null) { return; } item.IsShowingPrivate = true; }
public override DataTemplate SelectTemplate(Object item, DependencyObject container) { FrameworkElement element = container as FrameworkElement; if (element != null && item != null) { element.DataContext = item; InspectorNode node = item as InspectorNode; Type nodeType = node.Type; // Enums are handled differently if (nodeType.IsEnum) { nodeType = typeof(Enum); } //// The root has a especial case. //if (node.Parent == null) //{ // if (rootTemplateCache.DataTemplate == null) // rootTemplateCache.DataTemplate = element.FindResource(rootTemplateCache.Name) as DataTemplate; // return rootTemplateCache.DataTemplate; //} if (TypeTemplateMap.ContainsKey(nodeType)) { CachedTemplate cache = TypeTemplateMap[nodeType]; if (cache.DataTemplate == null) { cache.DataTemplate = element.FindResource(cache.Name) as DataTemplate; } return(cache.DataTemplate); } else if (typeof(GearConfig).IsAssignableFrom(nodeType)) { if (gearConfigTemplateCache.DataTemplate == null) { gearConfigTemplateCache.DataTemplate = element.FindResource(gearConfigTemplateCache.Name) as DataTemplate; } return(gearConfigTemplateCache.DataTemplate); } else { if (genericTemplateCache.DataTemplate == null) { genericTemplateCache.DataTemplate = element.FindResource(genericTemplateCache.Name) as DataTemplate; } return(genericTemplateCache.DataTemplate); } } return(null); }
//void SavePersistorData_Click(object sender, RoutedEventArgs e) //{ // GearsetResources.Console.SavePersistorData(); //} public void Tree_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e) { if (e.NewValue != null) { InspectorNode node = e.NewValue as InspectorNode; if (node != null) { nodeToExpandAfterUpdate = node; } } }
public void ListView_GotFocus(object sender, RoutedEventArgs e) { InspectorNode node = GearsetResources.Console.Inspector.Window.TreeView1.SelectedItem as InspectorNode; if (node != null) { TreeViewItem item = node.UIContainer as TreeViewItem; if (item != null) { item.IsSelected = false; } } }
/// <summary> /// Use this constructor to create child nodes. /// </summary> /// <param name="type">The type of the field this node represets</param> /// <param name="name">The name of the field this node represets</param> /// <param name="setter">Helper delegate to set the value of the field.</param> /// <param name="getter">Helper delegate to get the value of the field.</param> public InspectorNode(InspectorNode parent, Type type, String name, Setter setter, Getter getter, bool hideCanWriteIcon) { Children = new ObservableCollection<InspectorNode>(); Methods = new ObservableCollection<InspectorNode>(); Name = name; Type = type; _setter = setter; _getter = getter; Parent = parent; Updating = true; _hideCantWriteIcon = hideCanWriteIcon; }
/// <summary> /// Use this constructor to create child nodes. /// </summary> /// <param name="type">The type of the field this node represets</param> /// <param name="name">The name of the field this node represets</param> /// <param name="setter">Helper delegate to set the value of the field.</param> /// <param name="getter">Helper delegate to get the value of the field.</param> public InspectorNode(InspectorNode parent, Type type, String name, Setter setter, Getter getter, bool hideCanWriteIcon) { Children = new ObservableCollection <InspectorNode>(); Methods = new ObservableCollection <InspectorNode>(); Name = name; Type = type; Setter = setter; Getter = getter; Parent = parent; Updating = true; this.hideCantWriteIcon = hideCanWriteIcon; }
public void Clear_Click(object sender, RoutedEventArgs e) { InspectorNode item = ((InspectorNode)TreeView1.SelectedItem); if (item == null) { return; } if (item.CanWrite && !item.Type.IsValueType) { item.Property = null; } }
void UpdateFilterRecursively(InspectorNode node) { if (node.ChildrenView != null) { foreach (var child in node.Children) { UpdateFilterRecursively(child); } node.ChildrenView.View.Refresh(); if (node.UserModified && node.UIContainer != null) { node.UIContainer.IsExpanded = true; } } }
public void Inspect_Click(object sender, RoutedEventArgs e) { InspectorNode item = ((InspectorNode)TreeView1.SelectedItem); if (item == null) { return; } Object o = item.Property; if (o != null && !item.Type.IsValueType) { GearsetResources.Console.Inspect(item.GetPath(), o); } }
public void Remove_Click(object sender, RoutedEventArgs e) { InspectorNode item = ((InspectorNode)TreeView1.SelectedItem); if (item == null) { return; } Object o = item.Property; if (o != null) { GearsetResources.Console.RemoveInspect(o); } }
/// <summary> /// Remove the object from the inspector, if exist. /// </summary> /// <param name="o">The object to remove.</param> public void RemoveInspect(Object o) { InspectorNode container = null; foreach (var node in InspectedObjects) { if (node.Target == o) { container = node; break;; } } if (container != null) { InspectedObjects.Remove(container); } }
/// <summary> /// Get the TreeViewItems (containers) and let the InspectorTreeNodes /// know where they are. /// </summary> void ItemContainerGenerator_StatusChanged(object sender, EventArgs e) { if (UIContainer.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { int i = 0; foreach (var item in Children) { InspectorNode child = (InspectorNode)item; if (child.UIContainer == null || (child.UIContainer != null && child.UIContainer.Header != null && child.UIContainer.Header.ToString().Equals("{DisconnectedItem}"))) { child.UIContainer = (TreeViewItem)UIContainer.ItemContainerGenerator.ContainerFromItem(child); if (GearsetResources.Console.Inspector.Config.ModifiedOnly && child.UIContainer != null) { child.UIContainer.IsExpanded = true; } } i++; } } }
/// <summary> /// Get the TreeViewItems (containers) and let the InspectorTreeNodes /// know where they are. /// </summary> void ItemContainerGenerator1_StatusChanged(object sender, EventArgs e) { if (Window.TreeView1.ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated) { foreach (var obj in Window.TreeView1.Items) { InspectorNode o = (InspectorNode)obj; if (o.UIContainer == null || (o.UIContainer != null && o.UIContainer.Header != null && o.UIContainer.Header.ToString().Equals("{DisconnectedItem}"))) { TreeViewItem item = Window.TreeView1.ItemContainerGenerator.ContainerFromItem(o) as TreeViewItem; o.UIContainer = item; // If we're in the Modified only view, expand everything. if (Config.ModifiedOnly && o.UIContainer != null) { o.UIContainer.IsExpanded = true; } // If this item didn't have a UIContainer is because it // is new, expand it. TODO: This line used to expand every // root node, but it makes the inspector really slow to appear. // This should be configurable. //o.Expand(); // item could be null if we're filtering the collection (there's an item but is not being show). if (InspectedObjects.Count > 2 && item != null) { if (o.AutoExpand) { ((TreeViewItem)o.UIContainer).IsExpanded = true; } item.IsSelected = true; item.BringIntoView(); } } } } }
public void TreeView1_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { TreeViewItem treeViewItem = VisualUpwardSearch <TreeViewItem>(e.OriginalSource as DependencyObject) as TreeViewItem; if (treeViewItem != null) { // If we're right-clicking on a Collection Marker, don't take the focus. bool takeFocus = true; InspectorNode node = treeViewItem.DataContext as InspectorNode; if (node != null) { if (node.VisualItem != null && node.VisualItem is CollectionMarkerItem) { takeFocus = false; } } if (takeFocus) { treeViewItem.Focus(); e.Handled = true; } } }
public bool FilterPredicate(Object o) { // If there's nothing filtering, accept everything. if (!Config.ModifiedOnly && String.IsNullOrWhiteSpace(Config.SearchText)) { return(true); } InspectorNode node = o as InspectorNode; if (node != null) { bool acceptedByModifiedOnly = (!Config.ModifiedOnly || node.UserModified); // HACK: The parent == null condition is to check if it's a root node, // this is a hack because a cleaner solution would be to use a different filter // predicate for child nodes. if (node.Parent == null && searchTerms != null) { for (int i = 0; i < searchTerms.Length; i++) { if (!(node.Name.ToUpper().Contains(searchTerms[i]) || node.Type.Name.ToUpper().Contains(searchTerms[i]))) { // Rejected by search return(false); } } } if (acceptedByModifiedOnly) { return(true); } } // Rejected by modifiedOnly return(false); }
/// <summary> /// Fills the list of Children with nodes. /// </summary> /// <param name="force">if set to <c>true</c> the children, if any, will be deleted and the node reexpanded.</param> public virtual void Expand(bool force, bool includePrivate) { Dictionary <MemberInfo, InspectorReflectionHelper.SetterGetterPair> setterGetterDict; // Root will never be null, so we check if a child is null // or unreadable before trying to expanding it if (IsExtraNode) { return; } if (Parent != null && (!CanRead || Property == null)) { return; } if (Children.Count != 0) { if (force) { Children.Clear(); } else// Already expanded? { return; } } ChildrenView = new CollectionViewSource(); ChildrenView.Source = Children; ChildrenView.Filter += new FilterEventHandler(CollectionViewSource_Filter); // If there's no UI container created for us yet then we can't expand if (UIContainer == null) { return; } try { setterGetterDict = InspectorReflectionHelper.GetSetterGetterDict3(this); } catch (CompileErrorException) { GearsetResources.Console.Log("Gearset", "A compiler error occured, try verifying that the class you're inspecting is private"); return; } List <FieldInfo> fields = new List <FieldInfo>(Type.GetInstanceFields(!includePrivate)); List <PropertyInfo> properties = new List <PropertyInfo>(Type.GetInstanceProperties(!includePrivate)); List <MethodInfo> methods = new List <MethodInfo>(Type.GetInstanceMethods()); List <InspectorNode> sortedChildren = new List <InspectorNode>(fields.Count + properties.Count); InspectorReflectionHelper.SetterGetterPair pair; foreach (var field in fields) { if (field.GetCustomAttributes(typeof(InspectorIgnoreAttribute), true).Length > 0) { continue; } if (field.FieldType.IsPointer) { continue; } try { pair = setterGetterDict[field]; } catch { GearsetResources.Console.Log("Gearset", "Field {0} could not be inspected.", field.Name); continue; } // Do we have a friendly name? String friendlyName = field.Name; bool hideCantWriteIcon = false; foreach (InspectorAttribute attribute in field.GetCustomAttributes(typeof(InspectorAttribute), true)) { if (attribute.FriendlyName != null) { friendlyName = attribute.FriendlyName; } hideCantWriteIcon = attribute.HideCantWriteIcon; } sortedChildren.Add(new InspectorNode(this, field.FieldType, field.Name, pair.Setter, pair.Getter, hideCantWriteIcon) { IsProperty = false, FriendlyName = friendlyName, IsPrivate = field.IsPrivate || field.IsFamilyOrAssembly || field.IsFamily || field.IsAssembly || field.IsFamilyAndAssembly, }); } foreach (var property in properties) { if (property.GetCustomAttributes(typeof(InspectorIgnoreAttribute), true).Length > 0) { continue; } if (property.PropertyType.IsPointer) { continue; } try { pair = setterGetterDict[property]; } catch { GearsetResources.Console.Log("Gearset", "Property {0} could not be inspected.", property.Name); continue; } // Do we have a friendly name? String friendlyName = property.Name; bool hideCantWriteIcon = false; foreach (InspectorAttribute attribute in property.GetCustomAttributes(typeof(InspectorAttribute), true)) { if (attribute.FriendlyName != null) { friendlyName = attribute.FriendlyName; } hideCantWriteIcon = attribute.HideCantWriteIcon; } MethodInfo getMethod = property.GetGetMethod(true); MethodInfo setMethod = property.GetSetMethod(true); bool privateGet = getMethod != null ? getMethod.IsPrivate || getMethod.IsFamilyOrAssembly || getMethod.IsFamily || getMethod.IsAssembly || getMethod.IsFamilyAndAssembly : false; bool privateSet = setMethod != null ? setMethod.IsPrivate || setMethod.IsFamilyOrAssembly || setMethod.IsFamily || setMethod.IsAssembly || setMethod.IsFamilyAndAssembly : false; // If there's one that's not private, add it in the public part. if ((!privateGet && getMethod != null) || (!privateSet && setMethod != null)) { sortedChildren.Add(new InspectorNode(this, property.PropertyType, property.Name, privateSet ? null : pair.Setter, privateGet ? null : pair.Getter, hideCantWriteIcon) { IsProperty = true, FriendlyName = friendlyName, IsPrivate = false, }); } // If on accessor is private, we have to add it again in the private part with full access. if (includePrivate && (privateGet || privateSet)) { sortedChildren.Add(new InspectorNode(this, property.PropertyType, property.Name, pair.Setter, pair.Getter, hideCantWriteIcon) { IsProperty = true, FriendlyName = friendlyName, IsPrivate = true, }); } } // HACK: this could be done in the UI layer using the ListView.View property. //sortedChildren.Sort(AlphabeticalComparison); foreach (InspectorNode child in sortedChildren) { Children.Add(child); } // Special markers to add children to special types // TODO: make this extensible. // EXTRAS: if (typeof(IEnumerable).IsAssignableFrom(Type)) { Children.Add(new InspectorNode(this, typeof(CollectionMarker), String.Empty, null, Getter != null ? Getter : (x) => { return(RootTarget); }, false) { IsExtraNode = true }); } if (typeof(Texture2D).IsAssignableFrom(Type)) { Children.Add(new InspectorNode(this, typeof(Texture2DMarker), String.Empty, null, Getter != null ? Getter : (x) => { return(RootTarget); }, false) { IsExtraNode = true }); } if (typeof(Vector2).IsAssignableFrom(Type)) { Children.Add(new InspectorNode(this, typeof(float), "Vector Length", null, // Setter (x) => ((Vector2)this.Property).Length(), true) // Getter { IsExtraNode = true }); } if (typeof(Vector3).IsAssignableFrom(Type)) { Children.Add(new InspectorNode(this, typeof(float), "Vector Length", null, // Setter (x) => ((Vector3)this.Property).Length(), true) // Getter { IsExtraNode = true }); } // Add methods that don't take any params Methods.Clear(); foreach (var method in methods) { if (method.GetParameters().Length != 0) { continue; } if (method.IsDefined(typeof(CompilerGeneratedAttribute), true)) { continue; } if (method.IsSpecialName) { continue; } if (method.DeclaringType == typeof(Object)) { continue; } // Do we have a friendly name? String friendlyName = method.Name; foreach (InspectorMethodAttribute attribute in method.GetCustomAttributes(typeof(InspectorMethodAttribute), true)) { if (attribute.FriendlyName != null) { friendlyName = attribute.FriendlyName; InspectorNode methodNodec = new InspectorNode(this, typeof(void), method.Name, null, null, false) { FriendlyName = friendlyName }; methodNodec.Method = method; Children.Add(methodNodec); } } InspectorNode methodNode = new InspectorNode(this, typeof(void), method.Name, null, null, false) { FriendlyName = friendlyName }; methodNode.Method = method; Methods.Add(methodNode); } // Add extension methods (if any) foreach (var t in ExtensionMethodTypes) { foreach (var method in t.GetStaticMethods()) { if (method.GetParameters().Length != 1) { continue; } else { // Do we have a friendly name for the method? String friendlyName = method.Name; foreach (InspectorMethodAttribute attribute in method.GetCustomAttributes(typeof(InspectorMethodAttribute), true)) { if (attribute.FriendlyName != null) { friendlyName = attribute.FriendlyName; InspectorNode methodNodec = new InspectorNode(this, typeof(void), method.Name, null, null, false) { FriendlyName = friendlyName }; methodNodec.Method = method; Children.Add(methodNodec); } } Type paramType = method.GetParameters()[0].ParameterType; if (paramType.IsAssignableFrom(this.Type)) { InspectorNode methodNode = new InspectorNode(this, typeof(void), method.Name, null, null, true) { FriendlyName = friendlyName }; methodNode.Method = method; Methods.Add(methodNode); } } } } }
/// <summary> /// Fills the list of Children with nodes. /// </summary> /// <param name="force">if set to <c>true</c> the children, if any, will be deleted and the node reexpanded.</param> public void Expand(bool force, bool includePrivate) { Dictionary<MemberInfo, InspectorReflectionHelper.SetterGetterPair> setterGetterDict; // Root will never be null, so we check if a child is null // or unreadable before trying to expanding it if (IsExtraNode) return; if (Parent != null && (!CanRead || Property == null)) return; if (Children.Count != 0) if (force) Children.Clear(); else // Already expanded? return; ChildrenView = new CollectionViewSource(); ChildrenView.Source = Children; ChildrenView.Filter += CollectionViewSource_Filter; // If there's no UI container created for us yet then we can't expand if (UiContainer == null) return; try { setterGetterDict = InspectorReflectionHelper.GetSetterGetterDict3(this); } catch (CompileErrorException) { GearsetResources.Console.Log("Gearset", "A compiler error occured, try verifying that the sealed class you're inspecting is private"); return; } var fields = new List<FieldInfo>(Type.GetInstanceFields(!includePrivate)); var properties = new List<PropertyInfo>(Type.GetInstanceProperties(!includePrivate)); var methods = new List<MethodInfo>(Type.GetInstanceMethods()); var sortedChildren = new List<InspectorNode>(fields.Count + properties.Count); InspectorReflectionHelper.SetterGetterPair pair; foreach (var field in fields) { if (field.GetCustomAttributes(typeof(InspectorIgnoreAttribute), true).Length > 0) continue; if (field.FieldType.IsPointer) continue; try { pair = setterGetterDict[field]; } catch { GearsetResources.Console.Log("Gearset", "Field {0} could not be inspected.", field.Name); continue; } // Do we have a friendly name? var friendlyName = field.Name; var hideCantWriteIcon = false; foreach (InspectorAttribute attribute in field.GetCustomAttributes(typeof(InspectorAttribute), true)) { if (attribute.FriendlyName != null) friendlyName = attribute.FriendlyName; hideCantWriteIcon = attribute.HideCantWriteIcon; } sortedChildren.Add(new InspectorNode(this, field.FieldType, field.Name, pair.Setter, pair.Getter, hideCantWriteIcon) { IsProperty = false, FriendlyName = friendlyName, IsPrivate = field.IsPrivate || field.IsFamilyOrAssembly || field.IsFamily || field.IsAssembly || field.IsFamilyAndAssembly }); } foreach (var property in properties) { if (property.GetCustomAttributes(typeof(InspectorIgnoreAttribute), true).Length > 0) continue; if (property.PropertyType.IsPointer) continue; try { pair = setterGetterDict[property]; } catch { GearsetResources.Console.Log("Gearset", "Property {0} could not be inspected.", property.Name); continue; } // Do we have a friendly name? var friendlyName = property.Name; var hideCantWriteIcon = false; foreach (InspectorAttribute attribute in property.GetCustomAttributes(typeof(InspectorAttribute), true)) { if (attribute.FriendlyName != null) friendlyName = attribute.FriendlyName; hideCantWriteIcon = attribute.HideCantWriteIcon; } var getMethod = property.GetGetMethod(true); var setMethod = property.GetSetMethod(true); var privateGet = getMethod != null ? getMethod.IsPrivate || getMethod.IsFamilyOrAssembly || getMethod.IsFamily || getMethod.IsAssembly || getMethod.IsFamilyAndAssembly : false; var privateSet = setMethod != null ? setMethod.IsPrivate || setMethod.IsFamilyOrAssembly || setMethod.IsFamily || setMethod.IsAssembly || setMethod.IsFamilyAndAssembly : false; // If there's one that's not private, add it in the public part. if ((!privateGet && getMethod != null) || (!privateSet && setMethod != null)) { sortedChildren.Add(new InspectorNode(this, property.PropertyType, property.Name, privateSet ? null : pair.Setter, privateGet ? null : pair.Getter, hideCantWriteIcon) { IsProperty = true, FriendlyName = friendlyName, IsPrivate = false }); } // If on accessor is private, we have to add it again in the private part with full access. if (includePrivate && (privateGet || privateSet)) { sortedChildren.Add(new InspectorNode(this, property.PropertyType, property.Name, pair.Setter, pair.Getter, hideCantWriteIcon) { IsProperty = true, FriendlyName = friendlyName, IsPrivate = true }); } } // HACK: this could be done in the UI layer using the ListView.View property. //sortedChildren.Sort(AlphabeticalComparison); foreach (var child in sortedChildren) Children.Add(child); // Special markers to add children to special types // TODO: make this extensible. // EXTRAS: if (typeof(IEnumerable).IsAssignableFrom(Type)) Children.Add(new InspectorNode(this, typeof(CollectionMarker), String.Empty, null, _getter != null ? _getter : x => { return RootTarget; }, false) { IsExtraNode = true }); if (typeof(Texture2D).IsAssignableFrom(Type)) Children.Add(new InspectorNode(this, typeof(Texture2DMarker), String.Empty, null, _getter != null ? _getter : x => { return RootTarget; }, false) { IsExtraNode = true }); if (typeof(Vector2).IsAssignableFrom(Type)) Children.Add(new InspectorNode(this, typeof(float), "Vector Length", null, // Setter x => ((Vector2)Property).Length(), true) // Getter { IsExtraNode = true }); if (typeof(Vector3).IsAssignableFrom(Type)) Children.Add(new InspectorNode(this, typeof(float), "Vector Length", null, // Setter x => ((Vector3)Property).Length(), true) // Getter { IsExtraNode = true }); // Add methods that don't take any params Methods.Clear(); foreach (var method in methods) { if (method.GetParameters().Length != 0) continue; if (method.IsDefined(typeof(CompilerGeneratedAttribute), true)) continue; if (method.IsSpecialName) continue; if (method.DeclaringType == typeof(Object)) continue; // Do we have a friendly name? var friendlyName = method.Name; foreach (InspectorMethodAttribute attribute in method.GetCustomAttributes(typeof(InspectorMethodAttribute), true)) { if (attribute.FriendlyName != null) { friendlyName = attribute.FriendlyName; var methodNodec = new InspectorNode(this, typeof(void), method.Name, null, null, false) { FriendlyName = friendlyName }; methodNodec.Method = method; Children.Add(methodNodec); } } var methodNode = new InspectorNode(this, typeof(void), method.Name, null, null, false) { FriendlyName = friendlyName }; methodNode.Method = method; Methods.Add(methodNode); } // Add extension methods (if any) foreach (var t in ExtensionMethodTypes) { foreach (var method in t.GetStaticMethods()) { if (method.GetParameters().Length != 1) continue; // Do we have a friendly name for the method? var friendlyName = method.Name; foreach (InspectorMethodAttribute attribute in method.GetCustomAttributes(typeof(InspectorMethodAttribute), true)) { if (attribute.FriendlyName != null) { friendlyName = attribute.FriendlyName; var methodNodec = new InspectorNode(this, typeof(void), method.Name, null, null, false) { FriendlyName = friendlyName }; methodNodec.Method = method; Children.Add(methodNodec); } } var paramType = method.GetParameters()[0].ParameterType; if (paramType.IsAssignableFrom(Type)) { var methodNode = new InspectorNode(this, typeof(void), method.Name, null, null, true) { FriendlyName = friendlyName }; methodNode.Method = method; Methods.Add(methodNode); } } } }
static int AlphabeticalComparison(InspectorNode a, InspectorNode b) { return String.Compare(a.Name, b.Name); }
/// <summary> /// Adds the object to the inspector logger so the user /// can inspect its fields, properties and methods. /// </summary> /// <param name="name">A friendly name to use in the Inspector Tree.</param> /// <param name="o">The object to inspect.</param> /// <param name="autoExpand">Determines whether the node should automatically expand when added to the Inspector Tree.</param> public void Inspect(String name, Object o, bool autoExpand) { if (String.IsNullOrEmpty(name)) { name = "(unnamed object)"; } if (o == null) { return; } Type t = o.GetType(); if (t.IsValueType) { //GearsetResources.Console.Log("Gearset", "ValueTypes cannot be directly inspected. Ignoring {0} ({1}).", name, t.Name); //return; t = Type.GetType("Gearset.Components.InspectorWPF.ValueTypeWrapper`1").MakeGenericType(t); Object wrapper = Activator.CreateInstance(t); Type wrapperType = wrapper.GetType(); wrapperType.GetProperty("Value").SetValue(wrapper, o, null); o = wrapper; } if (t == typeof(String)) { GearsetResources.Console.Log("Gearset", "Strings cannot be directly inspected. Ignoring {0} ({1}).", name, t.Name); return; } if (o == null) { GearsetResources.Console.Log("Gearset", "Object to inspect cannot be null. Ignoring {0} ({1}).", name, t.Name); return; } if (t.IsNestedPrivate) { GearsetResources.Console.Log("Gearset", "Cannot inspect inner (nested) types that are private. Ignoring {0} ({1}).", name, t.Name); return; } int insertPosition = Math.Min(2, InspectedObjects.Count); foreach (var currentObject in InspectedObjects) { InspectorNode currentNode = currentObject; if (currentNode.Name == name) { if (currentNode.Type != t) { InspectedObjects.Remove(currentNode); currentNode = new InspectorNode(o, name, autoExpand); InspectedObjects.Add(currentNode); } else { currentNode.RootTarget = o; } // This might be null if the window has not oppened yet. if (currentNode.UIContainer != null) { ((TreeViewItem)currentNode.UIContainer).IsSelected = true; ((TreeViewItem)currentNode.UIContainer).BringIntoView(); } return; } } InspectorNode root = new InspectorNode(o, name, autoExpand); InspectedObjects.Insert(insertPosition, root); }
/// <summary> /// Method that creates a Diccionary of methods to set/get the value of /// each member of an object of the specified type. But this object only /// reachable by the path specified. For example, to get the Position (Vector3) /// from a player, the parameters must be: path="Position.", t=Vector3. /// If the object being ispected is the sealed class World which contains a /// player then parameters must be: path="Player.Position.", t=Vector3. /// This method is ~10X faster than the previous one that creaated C# code. /// </summary> internal static Dictionary<MemberInfo, SetterGetterPair> GetSetterGetterDict2(InspectorNode node) { var nodeType = node.Type; var targetType = node.Target.GetType(); var expandingObjectTypeName = CreateCSharpTypeString(nodeType); var baseObjectTypeName = CreateCSharpTypeString(node.Target.GetType()); var dictionaryKey = node.Root.Name + node.GetPath(); // Check if we haven't already generated methods for this node. if (SetterGetterCache.ContainsKey(dictionaryKey)) { return SetterGetterCache[dictionaryKey]; } // Get all instance fields and properties. var members = nodeType.GetFieldsAndProperties(BindingFlags.Default | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); // Code and return types for the methods. var codes = new List<string>(); var types = new List<Type>(); // We haven't created code to set the fields/properties for this kind of node // we have to generated code now and compile it generating methods. var setterGetterDict = new Dictionary<MemberInfo, SetterGetterPair>(); // Defines wether a field or property can be set/get because of a parent being // read only. var iter = node; // Create the path to this node, path will always contain at least // two elements because the root is always there. var path = new List<InspectorNode>(5); while (iter != null) { path.Add(iter); iter = iter.Parent; } // Add the reference to the Type of the node, and the target type assemblies. ReflectionHelper.AddReferencedAssembly(nodeType.Assembly.Location); ReflectionHelper.AddReferencedAssembly(node.Target.GetType().Assembly.Location); AddReferencedAssemblies(nodeType); AddReferencedAssemblies(node.Target.GetType()); // Find out which is the last parent that we need to asign. // values must be reassigned on the path as long as the parent // is a read-only struct. // If there's no object or writable valuetype in the chain, // we can write to the field/property (if the field/property // is writable also. var breakIndex = 0; if (path.Count > 1) { // Assume we can write until we prove we can't for (breakIndex = 0; breakIndex < path.Count; ++breakIndex) { // if parent is a read-only value type, continue. if (path[breakIndex].Type.IsValueType) if (!path[breakIndex].CanWrite) { // Sorry, we can't write. } else continue; break; } //breakIndex--; } else { breakIndex = 0; } // Create an assembly. // TODO: Reuse assembly, possible? var myAssemblyName = new AssemblyName(); myAssemblyName.Name = "Inspector"; var myAssembly = Thread.GetDomain().DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.Run, "c:\\"); // Create a module. For a single-file assembly the module // name is usually the same as the assembly name. var myModule = myAssembly.DefineDynamicModule(myAssemblyName.Name, true); // Define a public sealed class 'Example'. var myTypeBuilder = myModule.DefineType("Example", TypeAttributes.Public); // Create GET methods for every field foreach (var memberInfo in members) { var propertyInfo = memberInfo as PropertyInfo; var fieldInfo = memberInfo as FieldInfo; var memberType = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; setterGetterDict.Add(memberInfo, new SetterGetterPair(null, null)); // Create the 'Function1' public method, which takes an integer // and returns a string. var myMethod = myTypeBuilder.DefineMethod("XdtkGet_" + memberInfo.Name, MethodAttributes.Public | MethodAttributes.Static, typeof(Object), new[] { typeof(Object[]) }); var ilGenerator = myMethod.GetILGenerator(); // Load the target object ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Ldelem_Ref); ilGenerator.Emit(OpCodes.Castclass, targetType); for (var i = path.Count - 2; i >= 0; --i) { var parent = path[i]; // Local variable (aka v#) to store this section of the path. if (parent.IsProperty) { ilGenerator.Emit(OpCodes.Callvirt, path[i + 1].Type.GetProperty(parent.Name).GetGetMethod(true)); if (parent.Type.IsValueType) { var tempLocal = ilGenerator.DeclareLocal(parent.Type); ilGenerator.Emit(OpCodes.Stloc_S, tempLocal); ilGenerator.Emit(OpCodes.Ldloca_S, tempLocal); } } else { if (parent.Type.IsValueType) ilGenerator.Emit(OpCodes.Ldflda, path[i + 1].Type.GetField(parent.Name)); else ilGenerator.Emit(OpCodes.Ldfld, path[i + 1].Type.GetField(parent.Name)); } } // Get the value now! if (propertyInfo != null) { var getMethod = propertyInfo.GetGetMethod(); if (getMethod == null) continue; ilGenerator.Emit(OpCodes.Callvirt, getMethod); } else ilGenerator.Emit(OpCodes.Ldfld, fieldInfo); if (memberType.IsValueType) ilGenerator.Emit(OpCodes.Box, memberType); // Return ilGenerator.Emit(OpCodes.Ret); } // Create SET methods for every field foreach (var memberInfo in members) { var propertyInfo = memberInfo as PropertyInfo; var fieldInfo = memberInfo as FieldInfo; // If it's a read-only property, continue. if (propertyInfo != null && (propertyInfo.GetSetMethod() == null || !propertyInfo.CanWrite)) continue; // Create the 'Function1' public method, which takes an integer // and returns a string. var myMethod = myTypeBuilder.DefineMethod("XdtkSet_" + memberInfo.Name, MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(Object[]) }); var ilGenerator = myMethod.GetILGenerator(); // This boolean used to be how we controlled the licensing of Gearset, but now // is hard-wired to true. var willGenerateSetter = true; if (node.Type.Assembly == typeof(GearConsole).Assembly || (node.Parent != null && node.Parent.Type.Assembly == typeof(GearConsole).Assembly)) willGenerateSetter = true; if (!willGenerateSetter) { ilGenerator.Emit(OpCodes.Ldc_R4, 4f); ilGenerator.Emit(OpCodes.Stsfld, typeof(GearConsole).GetField("LiteVersionNoticeAlpha", BindingFlags.Public | BindingFlags.Static)); } else { var locals = new Stack<LocalBuilder>(); // Load the target object into local 0. var targetLocal = ilGenerator.DeclareLocal(targetType); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Ldelem_Ref); ilGenerator.Emit(OpCodes.Castclass, targetType); ilGenerator.Emit(OpCodes.Stloc_S, targetLocal); locals.Push(targetLocal); for (var i = path.Count - 2; i >= 0; --i) { var parent = path[i]; // Load a reference to the previous variable. if (path[i + 1].Type.IsValueType) ilGenerator.Emit(OpCodes.Ldloca, locals.Peek()); else ilGenerator.Emit(OpCodes.Ldloc, locals.Peek()); // Read the new variable. if (parent.IsProperty) ilGenerator.Emit(OpCodes.Callvirt, path[i + 1].Type.GetProperty(parent.Name).GetGetMethod(true)); else ilGenerator.Emit(OpCodes.Ldfld, path[i + 1].Type.GetField(parent.Name)); // Store it in a new local. var l = ilGenerator.DeclareLocal(parent.Type); locals.Push(l); ilGenerator.Emit(OpCodes.Stloc_S, l); } var memberType = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; // Load the object or struct to set the property to. if (path[0].Type.IsValueType) ilGenerator.Emit(OpCodes.Ldloca, locals.Peek()); else ilGenerator.Emit(OpCodes.Ldloc, locals.Peek()); // Load the value to be set (as object) and cast/unbox it. ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldc_I4_1); ilGenerator.Emit(OpCodes.Ldelem_Ref); if (memberType.IsValueType) ilGenerator.Emit(OpCodes.Unbox_Any, memberType); else ilGenerator.Emit(OpCodes.Castclass, memberType); // Set the value now! if (propertyInfo != null) ilGenerator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod()); else ilGenerator.Emit(OpCodes.Stfld, fieldInfo); // Now set all fields/properties in reverse order for (var i = 0; i < path.Count - 1; i++) { var parent = path[i]; // Push to object to set the value to. var valueToSet = locals.Pop(); if (locals.Peek().LocalType.IsValueType) ilGenerator.Emit(OpCodes.Ldloca_S, locals.Peek()); else ilGenerator.Emit(OpCodes.Ldloc_S, locals.Peek()); // Push the value to set ilGenerator.Emit(OpCodes.Ldloc, valueToSet); //ilGenerator.Emit(OpCodes.Ldloc, local); // Local variable (aka v#) to store this section of the path. if (parent.IsProperty) { var methodInfo = path[i + 1].Type.GetProperty(parent.Name).GetSetMethod(false); if (methodInfo == null) { ilGenerator.Emit(OpCodes.Pop); ilGenerator.Emit(OpCodes.Pop); break; } ilGenerator.Emit(OpCodes.Callvirt, methodInfo); } else { ilGenerator.Emit(OpCodes.Stfld, path[i + 1].Type.GetField(parent.Name)); } } } // Return ilGenerator.Emit(OpCodes.Ret); } var finalType = myTypeBuilder.CreateType(); //myAssembly.Save("SetterGetterMethods.dll"); // Build the dictionary foreach (var memberInfo in members) { var propertyInfo = memberInfo as PropertyInfo; if (propertyInfo != null && propertyInfo.GetIndexParameters().Length > 0) continue; var finalMethods = finalType.GetMethods(); // HACK: If there are two methods with the same name (i.e. new'd in a derived class) var setterInfo = finalMethods.FirstOrDefault(m => m.Name == "XdtkSet_" + memberInfo.Name); var getterInfo = finalMethods.FirstOrDefault(m => m.Name == "XdtkGet_" + memberInfo.Name); if (setterInfo != null) setterGetterDict[memberInfo].Setter = (Setter)Delegate.CreateDelegate(typeof(Setter), setterInfo); if (getterInfo != null) setterGetterDict[memberInfo].Getter = (Getter)Delegate.CreateDelegate(typeof(Getter), getterInfo); ; } return setterGetterDict; }
/// <summary> /// Adds the object to the inspector logger so the user can inspect its fields, properties and methods. /// </summary> /// <param name="node"></param> internal void Watch(InspectorNode node) { _userInterface.Watch(node); }
/// <summary> /// Adds the object to the inspector logger so the user /// can inspect its fields, properties and methods. /// </summary> /// <param name="name">A friendly name to use in the Inspector Tree.</param> /// <param name="o">The object to inspect.</param> /// <param name="autoExpand">Determines whether the node should automatically expand when added to the Inspector Tree.</param> public void Inspect(String name, Object o, bool autoExpand) { if (String.IsNullOrEmpty(name)) name = "(unnamed object)"; if (o == null) return; var t = o.GetType(); if (t.IsValueType) { //GearsetResources.Console.Log("Gearset", "ValueTypes cannot be directly inspected. Ignoring {0} ({1}).", name, t.Name); //return; t = Type.GetType("Gearset.Components.InspectorWPF.ValueTypeWrapper`1").MakeGenericType(t); var wrapper = Activator.CreateInstance(t); var wrapperType = wrapper.GetType(); wrapperType.GetProperty("Value").SetValue(wrapper, o, null); o = wrapper; } if (t == typeof(String)) { GearsetResources.Console.Log("Gearset", "Strings cannot be directly inspected. Ignoring {0} ({1}).", name, t.Name); return; } if (o == null) { GearsetResources.Console.Log("Gearset", "Object to inspect cannot be null. Ignoring {0} ({1}).", name, t.Name); return; } if (t.IsNestedPrivate) { GearsetResources.Console.Log("Gearset", "Cannot inspect inner (nested) types that are private. Ignoring {0} ({1}).", name, t.Name); return; } var insertPosition = Math.Min(2, _inspectedObjects.Count); foreach (var currentObject in _inspectedObjects) { var currentNode = currentObject; if (currentNode.Name == name) { if (currentNode.Type != t) { _inspectedObjects.Remove(currentNode); currentNode = new InspectorNode(o, name, autoExpand); _inspectedObjects.Add(currentNode); } else { currentNode.RootTarget = o; } // This might be null if the window has not oppened yet. if (currentNode.UiContainer != null) { currentNode.UiContainer.IsSelected = true; currentNode.UiContainer.BringIntoView(); } return; } } var root = new InspectorNode(o, name, autoExpand); _inspectedObjects.Insert(insertPosition, root); }
/// <summary> /// Adds the object to the inspector logger so the user /// can inspect its fields, properties and methods. /// </summary> /// <param name="name">A friendly name to use in the Inspector Tree.</param> /// <param name="o">The object to inspect.</param> /// <param name="autoExpand">Determines whether the node should automatically expand when added to the Inspector Tree.</param> internal void Watch(InspectorNode node) { if (node == null) return; _watchedNodes.Add(node); }
static void UpdateFilterRecursively(InspectorNode node) { if (node.ChildrenView != null) { foreach (var child in node.Children) { UpdateFilterRecursively(child); } node.ChildrenView.View.Refresh(); if (node.UserModified && node.UiContainer != null) node.UiContainer.IsExpanded = true; } }
private static int AlphabeticalComparison(InspectorNode a, InspectorNode b) { return(String.Compare(a.Name, b.Name)); }
/// <summary> /// Updates each component on the inspector TreeView. /// </summary> public override void Update(Microsoft.Xna.Framework.GameTime gameTime) { foreach (var obj in Window.TreeView1.Items) { InspectorNode o = (InspectorNode)obj; o.Update(); } foreach (var o in MethodCallers) { o.Update(); } if (locationJustChanged) { locationJustChanged = false; Config.Top = Window.Top; Config.Left = Window.Left; Config.Width = Window.Width; Config.Height = Window.Height; } if (updateSearchFilteringDelay > 0) { float dt = (float)gameTime.ElapsedGameTime.TotalSeconds; updateSearchFilteringDelay -= dt; if (updateSearchFilteringDelay <= 0) { updateSearchFilteringDelay = 0; // There's a chance that the worker is busy. Wait. while (filterWorker.IsBusy) { } filterWorker.DoWork -= new DoWorkEventHandler(filterWorker_DoWork); filterWorker.DoWork += new DoWorkEventHandler(filterWorker_DoWork); filterWorker.RunWorkerAsync(); } } // If the node expansion was generated because the currently selected node // dissapeared (because we're adding private fields, for example) then this // would generate a conflict with the expansion. if (Window.nodeToExpandAfterUpdate != null) { Window.nodeToExpandAfterUpdate.Expand(); Window.nodeToExpandAfterUpdate = null; } //series.AddPoints(new SeriesPoint[] { new SeriesPoint() { X = updateCount, Y = (float)Math.Sin(updateCount / 20f) } }, false); //float offset = updateCount / 20f; //for (int i = 0; i < 60; i++) //{ // series.Points[i] = new SeriesPoint() { X = i, Y = Math.Sin(offset + i / 10f) * 10f }; //} //series.InvalidateData(); //testSource.AppendAsync(System.Windows.Threading.Dispatcher.CurrentDispatcher, new Vector2((float)gameTime.TotalGameTime.TotalSeconds, (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds))); updateCount++; //if (updateCount % 5 == 0 || true) // XdtkResources.Console.DataSamplerManager.AddSample("testSampler1", (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds * 10), 30); //if (updateCount % 5 == 1 || true) // XdtkResources.Console.DataSamplerManager.AddSample("testSampler2", (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds * 11), 30); //if (updateCount % 5 == 2 || true) // XdtkResources.Console.DataSamplerManager.AddSample("testSampler3", (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds * 12), 30); //if (updateCount % 5 == 3 || true) // XdtkResources.Console.DataSamplerManager.AddSample("testSampler4", (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds * 14), 30); //if (updateCount % 5 == 4 || true) // XdtkResources.Console.DataSamplerManager.AddSample("testSampler5", (float)Math.Sin(gameTime.TotalGameTime.TotalSeconds * 20), 30); }
/// <summary> /// Method that creates a Diccionary of methods to set/get the value of /// each member of an object of the specified type. But this object only /// reachable by the path specified. For example, to get the Position (Vector3) /// from a player, the parameters must be: path="Position.", t=Vector3. /// If the object being ispected is the sealed class World which contains a /// player then parameters must be: path="Player.Position.", t=Vector3. /// This method is ~10X faster than the previous one that creaated C# code. /// </summary> internal static Dictionary <MemberInfo, SetterGetterPair> GetSetterGetterDict2(InspectorNode node) { var nodeType = node.Type; var targetType = node.Target.GetType(); var expandingObjectTypeName = CreateCSharpTypeString(nodeType); var baseObjectTypeName = CreateCSharpTypeString(node.Target.GetType()); var dictionaryKey = node.Root.Name + node.GetPath(); // Check if we haven't already generated methods for this node. if (SetterGetterCache.ContainsKey(dictionaryKey)) { return(SetterGetterCache[dictionaryKey]); } // Get all instance fields and properties. var members = nodeType.GetFieldsAndProperties(BindingFlags.Default | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); // Code and return types for the methods. var codes = new List <string>(); var types = new List <Type>(); // We haven't created code to set the fields/properties for this kind of node // we have to generated code now and compile it generating methods. var setterGetterDict = new Dictionary <MemberInfo, SetterGetterPair>(); // Defines wether a field or property can be set/get because of a parent being // read only. var iter = node; // Create the path to this node, path will always contain at least // two elements because the root is always there. var path = new List <InspectorNode>(5); while (iter != null) { path.Add(iter); iter = iter.Parent; } // Add the reference to the Type of the node, and the target type assemblies. ReflectionHelper.AddReferencedAssembly(nodeType.Assembly.Location); ReflectionHelper.AddReferencedAssembly(node.Target.GetType().Assembly.Location); AddReferencedAssemblies(nodeType); AddReferencedAssemblies(node.Target.GetType()); // Find out which is the last parent that we need to asign. // values must be reassigned on the path as long as the parent // is a read-only struct. // If there's no object or writable valuetype in the chain, // we can write to the field/property (if the field/property // is writable also. var breakIndex = 0; if (path.Count > 1) { // Assume we can write until we prove we can't for (breakIndex = 0; breakIndex < path.Count; ++breakIndex) { // if parent is a read-only value type, continue. if (path[breakIndex].Type.IsValueType) { if (!path[breakIndex].CanWrite) { // Sorry, we can't write. } else { continue; } } break; } //breakIndex--; } else { breakIndex = 0; } // Create an assembly. // TODO: Reuse assembly, possible? var myAssemblyName = new AssemblyName(); myAssemblyName.Name = "Inspector"; var myAssembly = Thread.GetDomain().DefineDynamicAssembly(myAssemblyName, AssemblyBuilderAccess.Run, "c:\\"); // Create a module. For a single-file assembly the module // name is usually the same as the assembly name. var myModule = myAssembly.DefineDynamicModule(myAssemblyName.Name, true); // Define a public sealed class 'Example'. var myTypeBuilder = myModule.DefineType("Example", TypeAttributes.Public); // Create GET methods for every field foreach (var memberInfo in members) { var propertyInfo = memberInfo as PropertyInfo; var fieldInfo = memberInfo as FieldInfo; var memberType = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; setterGetterDict.Add(memberInfo, new SetterGetterPair(null, null)); // Create the 'Function1' public method, which takes an integer // and returns a string. var myMethod = myTypeBuilder.DefineMethod("XdtkGet_" + memberInfo.Name, MethodAttributes.Public | MethodAttributes.Static, typeof(Object), new[] { typeof(Object[]) }); var ilGenerator = myMethod.GetILGenerator(); // Load the target object ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Ldelem_Ref); ilGenerator.Emit(OpCodes.Castclass, targetType); for (var i = path.Count - 2; i >= 0; --i) { var parent = path[i]; // Local variable (aka v#) to store this section of the path. if (parent.IsProperty) { ilGenerator.Emit(OpCodes.Callvirt, path[i + 1].Type.GetProperty(parent.Name).GetGetMethod(true)); if (parent.Type.IsValueType) { var tempLocal = ilGenerator.DeclareLocal(parent.Type); ilGenerator.Emit(OpCodes.Stloc_S, tempLocal); ilGenerator.Emit(OpCodes.Ldloca_S, tempLocal); } } else { if (parent.Type.IsValueType) { ilGenerator.Emit(OpCodes.Ldflda, path[i + 1].Type.GetField(parent.Name)); } else { ilGenerator.Emit(OpCodes.Ldfld, path[i + 1].Type.GetField(parent.Name)); } } } // Get the value now! if (propertyInfo != null) { var getMethod = propertyInfo.GetGetMethod(); if (getMethod == null) { continue; } ilGenerator.Emit(OpCodes.Callvirt, getMethod); } else { ilGenerator.Emit(OpCodes.Ldfld, fieldInfo); } if (memberType.IsValueType) { ilGenerator.Emit(OpCodes.Box, memberType); } // Return ilGenerator.Emit(OpCodes.Ret); } // Create SET methods for every field foreach (var memberInfo in members) { var propertyInfo = memberInfo as PropertyInfo; var fieldInfo = memberInfo as FieldInfo; // If it's a read-only property, continue. if (propertyInfo != null && (propertyInfo.GetSetMethod() == null || !propertyInfo.CanWrite)) { continue; } // Create the 'Function1' public method, which takes an integer // and returns a string. var myMethod = myTypeBuilder.DefineMethod("XdtkSet_" + memberInfo.Name, MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(Object[]) }); var ilGenerator = myMethod.GetILGenerator(); // This boolean used to be how we controlled the licensing of Gearset, but now // is hard-wired to true. var willGenerateSetter = true; if (node.Type.Assembly == typeof(GearConsole).Assembly || (node.Parent != null && node.Parent.Type.Assembly == typeof(GearConsole).Assembly)) { willGenerateSetter = true; } if (!willGenerateSetter) { ilGenerator.Emit(OpCodes.Ldc_R4, 4f); ilGenerator.Emit(OpCodes.Stsfld, typeof(GearConsole).GetField("LiteVersionNoticeAlpha", BindingFlags.Public | BindingFlags.Static)); } else { var locals = new Stack <LocalBuilder>(); // Load the target object into local 0. var targetLocal = ilGenerator.DeclareLocal(targetType); ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldc_I4_0); ilGenerator.Emit(OpCodes.Ldelem_Ref); ilGenerator.Emit(OpCodes.Castclass, targetType); ilGenerator.Emit(OpCodes.Stloc_S, targetLocal); locals.Push(targetLocal); for (var i = path.Count - 2; i >= 0; --i) { var parent = path[i]; // Load a reference to the previous variable. if (path[i + 1].Type.IsValueType) { ilGenerator.Emit(OpCodes.Ldloca, locals.Peek()); } else { ilGenerator.Emit(OpCodes.Ldloc, locals.Peek()); } // Read the new variable. if (parent.IsProperty) { ilGenerator.Emit(OpCodes.Callvirt, path[i + 1].Type.GetProperty(parent.Name).GetGetMethod(true)); } else { ilGenerator.Emit(OpCodes.Ldfld, path[i + 1].Type.GetField(parent.Name)); } // Store it in a new local. var l = ilGenerator.DeclareLocal(parent.Type); locals.Push(l); ilGenerator.Emit(OpCodes.Stloc_S, l); } var memberType = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType; // Load the object or struct to set the property to. if (path[0].Type.IsValueType) { ilGenerator.Emit(OpCodes.Ldloca, locals.Peek()); } else { ilGenerator.Emit(OpCodes.Ldloc, locals.Peek()); } // Load the value to be set (as object) and cast/unbox it. ilGenerator.Emit(OpCodes.Ldarg_0); ilGenerator.Emit(OpCodes.Ldc_I4_1); ilGenerator.Emit(OpCodes.Ldelem_Ref); if (memberType.IsValueType) { ilGenerator.Emit(OpCodes.Unbox_Any, memberType); } else { ilGenerator.Emit(OpCodes.Castclass, memberType); } // Set the value now! if (propertyInfo != null) { ilGenerator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod()); } else { ilGenerator.Emit(OpCodes.Stfld, fieldInfo); } // Now set all fields/properties in reverse order for (var i = 0; i < path.Count - 1; i++) { var parent = path[i]; // Push to object to set the value to. var valueToSet = locals.Pop(); if (locals.Peek().LocalType.IsValueType) { ilGenerator.Emit(OpCodes.Ldloca_S, locals.Peek()); } else { ilGenerator.Emit(OpCodes.Ldloc_S, locals.Peek()); } // Push the value to set ilGenerator.Emit(OpCodes.Ldloc, valueToSet); //ilGenerator.Emit(OpCodes.Ldloc, local); // Local variable (aka v#) to store this section of the path. if (parent.IsProperty) { var methodInfo = path[i + 1].Type.GetProperty(parent.Name).GetSetMethod(false); if (methodInfo == null) { ilGenerator.Emit(OpCodes.Pop); ilGenerator.Emit(OpCodes.Pop); break; } ilGenerator.Emit(OpCodes.Callvirt, methodInfo); } else { ilGenerator.Emit(OpCodes.Stfld, path[i + 1].Type.GetField(parent.Name)); } } } // Return ilGenerator.Emit(OpCodes.Ret); } var finalType = myTypeBuilder.CreateType(); //myAssembly.Save("SetterGetterMethods.dll"); // Build the dictionary foreach (var memberInfo in members) { var propertyInfo = memberInfo as PropertyInfo; if (propertyInfo != null && propertyInfo.GetIndexParameters().Length > 0) { continue; } var finalMethods = finalType.GetMethods(); // HACK: If there are two methods with the same name (i.e. new'd in a derived class) var setterInfo = finalMethods.FirstOrDefault(m => m.Name == "XdtkSet_" + memberInfo.Name); var getterInfo = finalMethods.FirstOrDefault(m => m.Name == "XdtkGet_" + memberInfo.Name); if (setterInfo != null) { setterGetterDict[memberInfo].Setter = (Setter)Delegate.CreateDelegate(typeof(Setter), setterInfo); } if (getterInfo != null) { setterGetterDict[memberInfo].Getter = (Getter)Delegate.CreateDelegate(typeof(Getter), getterInfo); } ; } return(setterGetterDict); }
/// <summary> /// Method that creates a Diccionary of methods to set/get the value of /// each member of an object of the specified type. But this object only /// reachable by the path specified. For example, to get the Position (Vector3) /// from a player, the parameters must be: path="Position.", t=Vector3. /// If the object being ispected is the sealed class World which contains a /// player then parameters must be: path="Player.Position.", t=Vector3. /// </summary> /// <param name="path"> /// Path to get to object of type t, including the /// name of the object itself and a point at the end. /// </param> /// <param name="o">Type of the object to get methods for.</param> /// <returns></returns> internal static Dictionary <MemberInfo, SetterGetterPair> GetSetterGetterDict(InspectorNode node) { throw new Exception("This method is obsolete, use GetSetterGetterDict2 instead which is a lot faster."); }
/// <summary> /// Method that creates a Diccionary of methods to set/get the value of /// each member of an object of the specified type. But this object only /// reachable by the path specified. For example, to get the Position (Vector3) /// from a player, the parameters must be: path="Position.", t=Vector3. /// If the object being ispected is the sealed class World which contains a /// player then parameters must be: path="Player.Position.", t=Vector3. /// </summary> /// <param name="path"> /// Path to get to object of type t, including the /// name of the object itself and a point at the end. /// </param> /// <param name="o">Type of the object to get methods for.</param> /// <returns></returns> internal static Dictionary<MemberInfo, SetterGetterPair> GetSetterGetterDict(InspectorNode node) { throw new Exception("This method is obsolete, use GetSetterGetterDict2 instead which is a lot faster."); }