/// <summary> /// Initializes a new instance of the <see cref="ObservableModelNode"/> class. /// </summary> /// <param name="ownerViewModel">The <see cref="ObservableViewModel"/> that owns the new <see cref="ObservableModelNode"/>.</param> /// <param name="baseName">The base name of this node. Can be null if <see cref="index"/> is not. If so a name will be automatically generated from the index.</param> /// <param name="isPrimitive">Indicate whether this node should be considered as a primitive node.</param> /// <param name="modelNode">The model node bound to the new <see cref="ObservableModelNode"/>.</param> /// <param name="modelNodePath">The <see cref="ModelNodePath"/> corresponding to the given <see cref="modelNode"/>.</param> /// <param name="index">The index of this content in the model node, when this node represent an item of a collection. <c>null</c> must be passed otherwise</param> protected ObservableModelNode(ObservableViewModel ownerViewModel, string baseName, bool isPrimitive, IModelNode modelNode, ModelNodePath modelNodePath, object index = null) : base(ownerViewModel, baseName, index) { if (modelNode == null) throw new ArgumentNullException(nameof(modelNode)); if (baseName == null && index == null) throw new ArgumentException("baseName and index can't be both null."); this.isPrimitive = isPrimitive; SourceNode = modelNode; // By default we will always combine items of list of primitive items. CombineMode = index != null && isPrimitive ? CombineMode.AlwaysCombine : CombineMode.CombineOnlyForAll; targetNode = GetTargetNode(modelNode, index); SourceNodePath = modelNodePath; // Override display name if available var memberDescriptor = GetMemberDescriptor() as MemberDescriptorBase; if (memberDescriptor != null) { if (index == null) { var displayAttribute = TypeDescriptorFactory.Default.AttributeRegistry.GetAttribute<DisplayAttribute>(memberDescriptor.MemberInfo); if (!string.IsNullOrEmpty(displayAttribute?.Name)) { DisplayName = displayAttribute.Name; } IsReadOnly = !memberDescriptor.HasSet; } } }
private ModelNodePath Clone(IModelNode newRoot, bool newTargetIsRootNode) { var clone = new ModelNodePath(newRoot, newTargetIsRootNode); clone.path.AddRange(path); return(clone); }
protected override void FreezeMembers() { service = null; NodePath = null; ObservableNodePath = null; Index = null; PreviousValue = null; }
private ModelNodePath Clone() { var clone = new ModelNodePath { RootNode = RootNode, targetIsRootNode = targetIsRootNode }; clone.path.AddRange(path); return(clone); }
/// <summary> /// Computes a <see cref="ModelNodePath"/> corresponding to the given <see cref="target"/> node, which must be a direct child or a direct reference of the <see cref="parentNode"/>. /// </summary> /// <param name="parentPath">The <see cref="ModelNodePath"/> corresponding to <see cref="parentNode"/>.</param> /// <param name="parentNode">The parent node which must be a direct child or a direct reference of the <see cref="parentNode"/>.</param> /// <param name="target">The target node for which to build a <see cref="ModelNodePath"/> instance.</param> /// <returns></returns> public static ModelNodePath GetChildPath(ModelNodePath parentPath, IModelNode parentNode, IModelNode target) { var result = GetNextPath(parentPath, parentNode, target); if (result != null) { result.targetIsRootNode = result.RootNode == target; } return(result); }
public ValueChangedActionItem(string name, ObservableViewModelService service, ModelNodePath nodePath, string observableNodePath, ObservableViewModelIdentifier identifier, object index, IEnumerable<IDirtiableViewModel> dirtiables, object previousValue) : base(name, dirtiables) { if (service == null) throw new ArgumentNullException("service"); if (!nodePath.IsValid) throw new InvalidOperationException("Unable to retrieve the path of the modified node."); this.service = service; this.identifier = identifier; this.PreviousValue = previousValue; NodePath = nodePath; Index = index; ObservableNodePath = observableNodePath; }
public ModelNodeCommandWrapper(IViewModelServiceProvider serviceProvider, INodeCommand nodeCommand, string observableNodePath, ObservableViewModel owner, ModelNodePath nodePath, IEnumerable<IDirtiableViewModel> dirtiables) : base(serviceProvider, dirtiables) { if (nodeCommand == null) throw new ArgumentNullException(nameof(nodeCommand)); if (owner == null) throw new ArgumentNullException(nameof(owner)); NodePath = nodePath; // Note: the owner should not be stored in the command because we want it to be garbage collectable Identifier = owner.Identifier; ModelContainer = owner.ModelContainer; NodeCommand = nodeCommand; Service = serviceProvider.Get<ObservableViewModelService>(); ObservableNodePath = observableNodePath; }
private static ObservableModelNode DefaultCreateNode(ObservableViewModel viewModel, string baseName, bool isPrimitive, IModelNode modelNode, ModelNodePath modelNodePath, Type contentType, object index) { return ObservableModelNode.Create(viewModel, baseName, isPrimitive, modelNode, modelNodePath, contentType, index); }
private static ModelNodePath GetPathRecursive(IModelNode modelNode, IModelNode target, ICollection <IModelNode> visitedNode) { var member = modelNode.Children.Where(x => !visitedNode.Contains(x)).FirstOrDefault(x => x == target); var objectReference = modelNode.Content.Reference as ObjectReference; var enumerableReference = modelNode.Content.Reference as ReferenceEnumerable; var result = new ModelNodePath(); visitedNode.Add(modelNode); if (member != null) { // The target is a direct member of the ModelNode result.path.Add(new NodePathItemMember { Name = member.Name }); } else if (objectReference != null && objectReference.TargetNode != null) { // The target is the TargetNode of the ObjectReference contained in the ModelNode if (objectReference.TargetNode != target) { result = GetPathRecursive(objectReference.TargetNode, target, visitedNode); } if (result.IsValid || target == objectReference.TargetNode) { result.Prepend(new NodePathItemTarget()); } } else if (enumerableReference != null) { foreach (ObjectReference reference in enumerableReference.Where(x => x.TargetNode != null)) { if (target != reference.TargetNode) { result = GetPathRecursive(reference.TargetNode, target, visitedNode); } if (result.IsValid || target == reference.TargetNode) { // The target is the TargetNode of an item of the ReferenceEnumerable contained in the ModelNode result.Prepend(new NodePathItemIndex { Value = reference.Index }); break; } } } else { // The target is not directly accessible. Let's invoke this method recursively on each of the child of the ModelNode foreach (var child in modelNode.Children.Where(x => !visitedNode.Contains(x))) { result = GetPathRecursive(child, target, visitedNode); if (result.IsValid) { result.Prepend(new NodePathItemMember { Name = child.Name }); break; } } } return(result); }
private static ModelNodePath GetNextPath(ModelNodePath parentPath, IModelNode parentNode, IModelNode target) { var result = parentPath.Clone(); if (parentNode == target) { return(result); } var member = parentNode.Children.FirstOrDefault(x => x == target); if (member != null) { // The target is a direct member of the ModelNode result.path.Add(new NodePathItemMember { Name = member.Name }); return(result); } var objectReference = parentNode.Content.Reference as ObjectReference; if (objectReference != null && objectReference.TargetNode == target) { result.path.Add(new NodePathItemTarget()); return(result); } member = parentNode.Children.FirstOrDefault(x => x.Content.Reference is ObjectReference && ((ObjectReference)x.Content.Reference).TargetNode == target); if (member != null) { result.path.Add(new NodePathItemMember { Name = member.Name }); result.path.Add(new NodePathItemTarget()); return(result); } var enumerableReference = parentNode.Content.Reference as ReferenceEnumerable; if (enumerableReference != null) { ObjectReference reference = enumerableReference.FirstOrDefault(x => x.TargetNode == target); if (reference != null) { result.path.Add(new NodePathItemIndex { Value = reference.Index }); return(result); } } foreach (var child in parentNode.Children) { enumerableReference = child.Content.Reference as ReferenceEnumerable; if (enumerableReference != null) { ObjectReference reference = enumerableReference.FirstOrDefault(x => x.TargetNode == target); if (reference != null) { result.path.Add(new NodePathItemMember { Name = child.Name }); result.path.Add(new NodePathItemIndex { Value = reference.Index }); return(result); } } } return(null); }
/// <summary> /// Create an <see cref="ObservableModelNode{T}"/> that matches the given content type. /// </summary> /// <param name="ownerViewModel">The <see cref="ObservableViewModel"/> that owns the new <see cref="ObservableModelNode"/>.</param> /// <param name="baseName">The base name of this node. Can be null if <see cref="index"/> is not. If so a name will be automatically generated from the index.</param> /// <param name="isPrimitive">Indicate whether this node should be considered as a primitive node.</param> /// <param name="modelNode">The model node bound to the new <see cref="ObservableModelNode"/>.</param> /// <param name="modelNodePath">The <see cref="ModelNodePath"/> corresponding to the given node.</param> /// <param name="contentType">The type of content contained by the new <see cref="ObservableModelNode"/>.</param> /// <param name="index">The index of this content in the model node, when this node represent an item of a collection. <c>null</c> must be passed otherwise</param> /// <returns>A new instance of <see cref="ObservableModelNode{T}"/> instanced with the given content type as generic argument.</returns> internal static ObservableModelNode Create(ObservableViewModel ownerViewModel, string baseName, bool isPrimitive, IModelNode modelNode, ModelNodePath modelNodePath, Type contentType, object index) { var node = (ObservableModelNode)Activator.CreateInstance(typeof(ObservableModelNode<>).MakeGenericType(contentType), ownerViewModel, baseName, isPrimitive, modelNode, modelNodePath, index); return node; }
private void GenerateChildren(IModelNode modelNode, ModelNodePath modelNodePath) { if (modelNode.Content.IsReference && modelNode.Content.ShouldProcessReference) { var referenceEnumerable = modelNode.Content.Reference as ReferenceEnumerable; if (referenceEnumerable != null) { // If the reference should not be processed, we still need to create an observable node for each entry of the enumerable. // These observable nodes will have the same source node that their parent so we use this information to prevent // the infinite recursion that could occur due to the fact that these child nodes will have the same model nodes (like primitive types) // while holding an enumerable reference. //if (modelNode.Content.ShouldProcessReference || ModelNodeParent.sourceNode != modelNode) { // Note: we are making a copy of the reference list because it can be updated from the Initialize method of the // observable node in the case of scene objects. Doing this is a hack, but parts of this framework will be redesigned later to improve this foreach (var reference in referenceEnumerable.ToList()) { // The type might be a boxed primitive type, such as float, if the collection has object as generic argument. // In this case, we must set the actual type to have type converter working, since they usually can't convert // a boxed float to double for example. Otherwise, we don't want to have a node type that is value-dependent. var type = reference.TargetNode != null && reference.TargetNode.Content.IsPrimitive ? reference.TargetNode.Content.Type : reference.Type; var observableNode = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, false, modelNode, modelNodePath, type, reference.Index); AddChild(observableNode); observableNode.Initialize(); } } } } else { var dictionary = modelNode.Content.Descriptor as DictionaryDescriptor; var list = modelNode.Content.Descriptor as CollectionDescriptor; if (dictionary != null && modelNode.Content.Value != null) { // Dictionary of primitive objects foreach (var key in dictionary.GetKeys(modelNode.Content.Value)) { var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, true, modelNode, modelNodePath, dictionary.ValueType, key); AddChild(observableChild); observableChild.Initialize(); } } else if (list != null && modelNode.Content.Value != null) { // List of primitive objects for (int i = 0; i < list.GetCollectionCount(modelNode.Content.Value); ++i) { var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, null, true, modelNode, modelNodePath, list.ElementType, i); AddChild(observableChild); observableChild.Initialize(); } } else { // Single non-reference primitive object foreach (var child in modelNode.Children) { var childPath = modelNodePath.GetChildPath(modelNode, child); var observableChild = Owner.ObservableViewModelService.ObservableNodeFactory(Owner, child.Name, child.Content.IsPrimitive, child, childPath, child.Content.Type, null); AddChild(observableChild); observableChild.Initialize(); } } } }
private ModelNodePath Clone(IModelNode newRoot, bool newTargetIsRootNode) { var clone = new ModelNodePath(newRoot, newTargetIsRootNode); clone.path.AddRange(path); return clone; }