private void Initialize(bool isUpdating) { var path = ModelNodePath.GetPath(((ObservableModelNode)Root).sourceNode, targetNode); if (!path.IsValid) { throw new InvalidOperationException("Unable to retrieve the path of the given model node."); } foreach (var command in targetNode.Commands) { var commandWrapper = new ModelNodeCommandWrapper(ServiceProvider, command, Path, Owner.Identifier, path, Owner.ModelContainer, Owner.GetDirtiableViewModels(this)); AddCommand(commandWrapper); } if (!isPrimitive) { GenerateChildren(targetNode, isUpdating); } isInitialized = true; if (Owner.ObservableViewModelService != null) { var data = Owner.ObservableViewModelService.RequestAssociatedData(this, isUpdating); SetValue(ref associatedData, data, "AssociatedData"); } CheckDynamicMemberConsistency(); }
/// <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("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 if (index == null) { var memberDescriptor = GetMemberDescriptor() as MemberDescriptorBase; if (memberDescriptor != null) { var displayAttribute = TypeDescriptorFactory.Default.AttributeRegistry.GetAttribute <DisplayAttribute>(memberDescriptor.MemberInfo); if (displayAttribute != null && !string.IsNullOrEmpty(displayAttribute.Name)) { DisplayName = displayAttribute.Name; } } } }
internal void RegisterAction(string displayName, ModelNodePath nodePath, string observableNodePath, object index, IReadOnlyCollection <IDirtiableViewModel> dirtiables, object newValue, object previousValue) { singleNodeActionRegistered = true; var actionItem = new ValueChangedActionItem(displayName, observableViewModelService, nodePath, observableNodePath, Identifier, index, dirtiables, modelContainer, previousValue); ActionStack.Add(actionItem); NotifyNodeChanged(observableNodePath); }
protected override void FreezeMembers() { service = null; NodePath = null; ObservableNodePath = null; Index = null; PreviousValue = null; }
protected override void FreezeMembers() { service = null; modelContainer = null; nodePath = null; observableNodePath = null; index = null; }
private void GenerateChildren(IModelNode modelNode, ModelNodePath modelNodePath, bool isUpdating) { if (modelNode.Content.IsReference) { var referenceEnumerable = modelNode.Content.Reference as ReferenceEnumerable; if (referenceEnumerable != null) { foreach (var reference in referenceEnumerable) { // 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 = Create(Owner, null, false, this, modelNode, modelNodePath, type, reference.Index); observableNode.Initialize(isUpdating); AddChild(observableNode); } } } 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 = Create(Owner, null, true, this, modelNode, modelNodePath, dictionary.ValueType, key); observableChild.Initialize(isUpdating); AddChild(observableChild); } } 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 = Create(Owner, null, true, this, modelNode, modelNodePath, list.ElementType, i); observableChild.Initialize(isUpdating); AddChild(observableChild); } } else { // Single non-reference primitive object foreach (var child in modelNode.Children) { var childPath = ModelNodePath.GetChildPath(modelNodePath, modelNode, child); var observableChild = Create(Owner, child.Name, child.Content.IsPrimitive, this, child, childPath, child.Content.Type, null); observableChild.Initialize(isUpdating); AddChild(observableChild); } } } }
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, ObservableViewModelIdentifier identifier, ModelNodePath nodePath, ModelContainer modelContainer, IEnumerable <IDirtiableViewModel> dirtiables) : base(serviceProvider, dirtiables) { if (nodeCommand == null) { throw new ArgumentNullException("nodeCommand"); } if (modelContainer == null) { throw new ArgumentNullException("modelContainer"); } this.identifier = identifier; this.nodePath = nodePath; this.modelContainer = modelContainer; this.nodeCommand = nodeCommand; service = serviceProvider.Get <ObservableViewModelService>(); 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; }
/// <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="parentNode">The parent node of the new <see cref="ObservableModelNode"/>, or <c>null</c> if the node being created is the root node of the view model.</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, SingleObservableNode parentNode, IModelNode modelNode, ModelNodePath modelNodePath, object index = null) : base(ownerViewModel, baseName, parentNode, index) { if (modelNode == null) { throw new ArgumentNullException("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; }
/// <summary> /// Retrieves a <see cref="ModelNodePath"/> object corresponding to the path of the model node contained in this <see cref="ObservableModelNode"/>. /// </summary> /// <returns>A <see cref="ModelNodePath"/> object corresponding to the path of the model node contained in this <see cref="ObservableModelNode"/>.</returns> public ModelNodePath GetModelNodePath() { return(ModelNodePath.GetPath(((ObservableModelNode)Root).sourceNode, sourceNode)); }
/// <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) { foreach (var reference in referenceEnumerable) { // 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 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)); }