Does 'XmlDocument.CreateElement();' ONLY create an element? - c#

It seems like someXml.CreateElement("abc"); does only one thing: create the element. It does not add it as a child as I expected, nor does it seem to do anything else.
But that doesn't make much sense. Why create an element with an instance method instead of with a static method? That would indicate that it does have some relationship to the instance. But I couldn't find anything and hence my question.

The remarks in Microsoft's Documentation mentions that default attributes are created on the returned object. Namespaces come to mind as they may be automatically applied to the new element based on the XmlDocument's schema/defaults.
It also states that it must be manually added to the desired parent node.
From https://msdn.microsoft.com/en-us/library/fw1ys7w6(v=vs.110).aspx
Note that the instance returned implements the XmlElement interface, so default attributes would be created directly on the returned object.
Although this method creates the new object in the context of the document, it does not automatically add the new object to the document tree. To add the new object, you must explicitly call one of the node insert methods.

I think the reason that the method doesn't automatically add the element as a child like you were expecting is because there would be no way to know where the element should be added. The document could have many children and there is nothing to specify which element the created element should be added to. It can't just add it by default to the root element, because there's a good chance that isn't always going to be the desired location.
As previously mentioned, the perks of having it be an instance method rather than a static method would be to automatically create the default attributes (such as namespace) on the newly created element. That way once it is created it should just need to be added to the proper location in the document.

Related

What is the best way to associate a Nested Content node to an Umbraco Member

My initial thought was to create an Umbraco Relation and associate the Umbraco Member to the Nested Content node. Sadly, I found this form post asking a similar question and as you can see in Matt Bailsford's first response:
Unfortunately nested content can't have an ID value as they don't truely exist
I did find the issue/feature that was discussed in the forum post; however, it just adds parent information to the DetachedPublishedContent object and doesn't solve my issue. After reading the form post and the conversations of Hendy Racher, Matt Bailsford and Lee Kelleher in the github pull request, I still don't understand why Nested Content doesn't create a node in Umbraco.
So basically I need the Nested Content nodes to be created as Umbraco nodes and then stored as a JSON string in the property field. There are a few ways that I see this could be accomplished:
Create a Custom Property Editor for Umbraco Backoffice - I would start with a copy of Nested Content and add code to create the node and attach it before saving the node as a JSON string.
Use the Umbraco Multinode Treepicker control - This control was suggested by Hendy and Jeavon in this forum post as a way to allow a user to select multiple content nodes. Unfortunately going this route would require the user to create the "nested content" nodes first. Then they could associate those "nested content" nodes with the original node. We really like the user experience of the Nested Content control where it allows you to create nodes dynamically in the property editor.
Find a way to associate the Member to the "Nested Content" node - This option would require that I store an association between the top node and it's respective "nested content" node to a Member in Umbraco. There are two issues that come to mind when trying to go this route:
How should I associate the "nested content" node to the Member in a standard Umbraco way? - I immediately think of creating a link table in the database but, in my understanding, that is not the standard Umbraco way. I am still fuzzy about the best way to do this inside Umbraco.
Is there a way to uniquely identify the "nested content" node? - I realize there is a sort order value being set according to the pull request I found above but if the user reorders the nested content items will it change the "nested content" node to member association?
At this point, I am leaning towards going with option 1, but I wonder if option 3 is a better direction. In reality, I don't believe this is a new problem that someone hasn't already solved, and I hate to create another custom property editor if there is one just like it out there already.
So if you know of a better way to solve this problem please let me know.
The problem is - as you mention it - that Nested Content nodes aren't really real nodes. I don't think the right way to solve your problem is to try hacking Nested Content into doing something it really wasn't created to do.
The problem about creating nodes and also having references to them on the Nested Content node is that essentially every node in Umbraco needs to "live" somewhere.
You could choose to say that a node lives under the parent it is nested into, but how would you then differentiate between nested nodes and actual child nodes - this would require another hack as it is really working around how nodes are meant to be structured and handled in the Umbraco core.
Even if you did manage to get this working, I suspect you would have a lot to deal with to actually make it work as good as Nested Content currently does:
You would have somehow wrap every single node in the Nested Content editor into a object to be able to store meta data like the node ID it is connected to and the sortOrder when reordering all of the nested content nodes you have on there.
(edit: I think it actually already stores some sort of wrapper object here, but you would have to change the logic in here to actually handle a reference to another node instead of just deserializing json stored here, as a node)
You would also have to manually hook into events making sure the actual edits you do while on the parent node actually ends up being persisted to the nested nodes.
Deleting a nested content node, or a parent that has any nested nodes - you would have to handle deleting any orphaned nodes.
There's most likely a lot of stuff I've missed but my point is - you will have a lot of trouble trying to do this.
I think you should consider another approach if you really need to do this:
It would be possible to create a picker similar to a normal node picker, that simply allows you to browse through nodes as a normal picker would do. When you pick a node, instead of just selecting it, it should then fetch the nested content nodes and show those in the UI.
There's however the little quirk that you could essentially be having multiple properties storing each their set of nested content nodes on one single content item - so you would need some nice way of handling this in the UI.
When you select one or multiple of the nested nodes, what your picker would store would be something similar to [guid-of-the-real-node]_[propertyAlias]_[guid-of-nested-content-item].
I am not certain if Nested Content ever got the GUID unique ID/key feature implemented - Matt and I discussed it some time last year and we tried adding it in, in a custom build I needed for a project. If it isn't there I would suggest you ask Matt if he can get that in. It was essentially just giving each nested content item a "fake" unique ID (GUID) that you could use to identify it from other nested content items stored in the property. (You would have to ask Matt about the status of this)
Doing this would allow you to (on your member) have a reference that you lets you find the actual content node, then the property where the content is stored, and lastly the actual nested content node you have picked.
You should however note that this is very prone to breaking and needs a lot of null handling:
If you change the property alias of the property you are storing nested content in on the parent, it will lose the reference.
If you delete the content item storing the nested items, the picked items no longer exist and you have a missing reference in the picker on your member (needs null handling)
If you delete a nested content item - same as above. You have a missing reference in your picker.
Apart from the solution above, I don't really see another way of doing this currently with the requirements you have.

C#- Adding a new item to a collection<t>

I have a collection that populates a treeview, and I want to add functionality that allows a node to be added with custom properties. Would the best way to go about it to clone the selected node and then edit the properties from there, or to add a completely new blank node?
The following method is how I'm currently trying to add nodes.
public void add()
{
hClass clone = new hClass();
clone = SelectedNode;
Topics.Add(clone);
}
And then I call the method via a command.
It really depends on what you do with these nodes and which pieces of code an access them. Eric Lippert wrote a blog post focused on immutable collections which might shed more light on your problem.
The collection is a set of references (pointers) to the nodes. If you assign an existing instance of hClass to the collection, a change to the instance will be visible in every place that can access it. If you're using it in a WPF GUI, read about Responding to data source changes

Syntax rewriting

I need to transform all of the properties of a certain class using Roslyn.
What is the recommended way to apply more than one transformation to a syntax tree without invalidating references into it?
Here is what I've tried and where I'm stuck:
In the first pass a descendant of CSharpSyntaxWalker is visiting all PropertyDeclarationSyntax nodes, and storing them in a list.
In the second pass a CSharpSyntaxRewriter is transforming the nodes while checking that each visited node equals one in the list before transforming it.
The problem with my attempt is: When I transform a property I add new fields to the class which causes the class to mutate. All the references in the list to the other properties become invalid in the new tree for the class.
It seems to be inefficient to revisit the whole class, and either way I cannot detect the property nodes already handled due to the reference difference.
I would not recommend to reference nodes from a SyntaxTree you want to modify. In your case just using a CSharpSyntaxRewriter in a single pass (without keeping references from a pre-processing pass) would be sufficient, because its VisitPropertyDeclaration method will only be called once per property, so there is no need to keep track of the nodes you've already modified.
The CSharpSyntaxRewriter also visits the nodes bottom-up, so the overrides should always be called with a node from the original tree. Most likely you have modified the node through the call to base.VisitPropertyDeclaration() before comparing its reference to the stored one. So you could still keep and compare references if you really wanted to.
public class PropertyRewriter : CSharpSyntaxRewriter
{
public override SyntaxNode VisitPropertyDeclaration(PropertyDeclarationSyntax node)
{
// 'node' should be still from the original syntax tree here
node = (PropertyDeclarationSyntax)base.VisitPropertyDeclaration(node);
// 'node' might be replaced here
return node;
}
}
Instead of keeping references to the nodes you want to modify, you could annotate them. Annotations to a node will survive modifications of the containing SyntraxTree as long as the node itself isn't replaced. You can add them like this:
node = node.WithAdditionalAnnotations(
new SyntaxAnnotation("propertyToChange", "todo"));
To retrieve the annotation again either use node.GetAnnotations("propertyToChange") or use GetAnnotatedNodesOrTokens("propertyToChange") to retrieve all nodes or tokens with an annotation of the given kind ("propertyToChange").

Omitting elements using custom XmlTextWriter

I'm implementing a custom XmlTextWriter and I'd like to omit any elements with a particular name that contain no attributes. I've gotten as far as being able to prevent the element from being written by overriding WriteStartElement and WriteEndElement, but is there a way to know at WriteStartElement or at any other useful point whether or not the element has any attributes?
No. However you can postpone writing of the element and attributes (put them in a field) until you get to the next element/comment/etc. Then decide whether you want to write them or not.

No reference to project item created through AddFromTemplate() returned

In a Visual Studio Add-In that successfully creates a form, but gives me no reference back to the EnvDTE's prjItem instance.
Here's the piece of code that adds the form to the project:
string templatePath = solution.GetProjectItemTemplate("Form.zip", "csproj");
ProjectItem prjItem = project.ProjectItems.AddFromTemplate(templatePath, "myForm.cs");
Obs.: 'solution' is an EnvDTE80.Solution2 object.
Of cource I can get the reference by other ways, like proj.ProjectItems.Item([index]) (doing a loop and checking for names), but that's not how I want to do it, and I need this reference in orther to add controls to this form.
Am I doing something wrong?
Just found a comment on MSDN:
AddFromTemplate always returns a NULL
value
At one time, this was true. But
with later versions of Visual Studio,
which included the ability to add
multiple items from a single template,
the return value for this method could
not return multiple items. So it now
returns a NULL value in all instances.
This is due to the contraint that the
COM signature for this particular
method cannot be changed without
breaking a lot of code already in use.
Consequently, if you need the
ProjectItem interface of the item just
added via the AddFromTemplate call,
you can either iterate through the
ProjectItems collection, or you can
create a ProjectItemsEvents.ItemAdded
event just before calling
AddFromTemplate, and store away the
ProjectItem passed to your OnItemAdded
handler.
http://msdn.microsoft.com/en-us/library/envdte.projectitems.addfromtemplate(v=vs.80).aspx#1

Categories

Resources