Does any one know if C# has an equivalent of ObjPtr from VB6, or equivalent functionality (see more info below)? Here are a couple of links to info on ObjPtr devx , thevbzone.
Basically I have a third party treeview that I need to walk thru to get specific nodes but the only (relevant) info the nodes have is name ... but the node names don't need to be unique. So I need to get a unique value for each node as I walk thru it the first time so when I walk thru it again I know which is which. In the old school VB6 days I would use ObjPtr.
The closest direct equivalent I can think of would be to use a GCHandle to get an IntPtr for your object reference.
You would need to allocate a GCHandle for your object (GCHandle.Alloc), then use GCHandle.ToIntPtr to convert to an IntPtr. The linked documentation shows the process.
If they're objects, why not just store the object references directly? These will be unique.
You can use Object.ReferenceEquals(x, y) to determine if a reference you have stored is referring to the same object you just retrieved from the tree.
If the treenode has FullPath property, you can use it to uniquely identify a node in the treeview (Winforms Treeview has the FullPath property). This won't be unique if 2 siblings have same text in it.
OR
You could use Handle property of the TreeNode.
GetHashCode should work well for testing unique values unless the third-party has overriden the Object implementation with something that doesn't make sense in your scenario.
I would assume that nodes in the tree would define equality/hashcode by more than just the value string, but you would need to check.
Related
I have a (not quite valid) CSV file that contains rows of multiple types. Any record could be one of about 6 different types and each type has a different number of properties. The first part of any row contains the timestamp and the type of record, followed by a standard CSV of the data.
Example
1456057920 PERSON, Ted Danson, 123 Fake Street, 555-123-3214, blah
1476195120 PLACE, Detroit, Michigan, 12345
1440581532 THING, Bucket, Has holes, Not a good bucket
And to make matters more complex, I need to be able to do different things with the records depending on certain criteria. So a PERSON type can be automatically inserted into a DB without user input, but a THING type would be displayed on screen for the user to review and approve before adding to DB and continuing the parse, etc.
Normally, I would use a library like CsvHelper to map the records to a type, but in this case since the types could be different, and the first part uses a space instead of comma, I dont know how to do that with a standard CSV library. So currently how I am doing it each loop is:
String split based off comma.
Split the first array item by the space.
Use a switch statement to determine the type and create the object.
Put that object into a List of type object.
Get confused as to where to go now because i now have a list of various types and will have to use yet another switch or if to determine the next parts.
I don't really know for sure if I will actually need that List but I have a feeling the user will want the ability to manually flip through records in the file.
By this point, this is starting to make for very long, confusing code, and my gut feeling tells me there has to be a cleaner way to do this. I thought maybe using Type.GetType(string) would help simplify the code some, but this seems like it might be terribly inefficient in a loop with 10k+ records and might make things even more confusing. I then thought maybe making some interfaces might help, but I'm not the greatest at using interfaces in this context and I seem to end up in about this same situation.
So what would be a more manageable way to parse this file? Are there any C# parsing libraries out there that would be able to handle something like this?
You can implement an IRecord interface that has a Timestamp property and a Process method (perhaps others as well).
Then, implement concrete types for each type of record.
Use a switch statement to determine the type and create and populate the correct concrete type.
Place each object in a List
After that you can do whatever you need. Some examples:
Loop through each item and call Process() to handle it.
Use linq .OfType<{concrete type}> to segment the list. (Warning with 10k
records, this would be slow since it would traverse the entire list for each concrete type.)
Use an overridden ToString method to give a single text representation of the IRecord
If using WPF, you can define a datatype template for each concrete type, bind an ItemsControl derivative to a collection of IRecords and your "detail" display (e.g. ListItem or separate ContentControl) will automagically display the item using the correct DataTemplate
Continuing in my comment - well that depends. What u described is actually pretty good for starters, u can of course expand it to a series of factories one for each object type - so that you move from explicit switch into searching for first factory that can parse a line. Might prove useful if u are looking to adding more object types in the future - you just add then another factory for new kind of object. Up to you if these objects should share a common interface. Interface is used generally to define a a behavior, so it doesn't seem so. Maybe you should rather just a Dictionary? You need to ask urself if you actually need strongly typed objects here? Maybe what you need is a simple class with ObjectType property and Dictionary of properties with some helper methods for easy typed properties access like GetBool, GetInt or generic Get?
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.
I want to show the DOM as it is on the web browser with all comments and html, head, body, etc.. preserve its structure. Currently, I can only start from node html. Document.All didnt help.
The only way I can see is webBrowser1.Document.Body but I would miss the commentss, head etc.. Then if I go with Document.All then that gives me all the nodes.
I think the only choice with the WebBrowser control to get what you want is to use Document.All. Although this gives all elements not just top-level, each element has a .Parent element property so you can loop through them (or use Linq) and get only the ones that have <body> or <head> as the parent element.
Try using HTMLAgilityPack, it support Xpath so you can get any node as you want.
As suggested by hienvd_csuit, I think HTML Agility Pack is your best option. If you still want to use the WebBrowser, a possible solution is to access the unmanaged DOM directly, using dynamic (requires .NET 4+). For instance you can do something like this:
dynamic dom = wb.Document.DomDocument;
foreach (dynamic node in dom.childNodes)
{
Console.WriteLine ("{0} - {1} - {2}", node.nodeType, node.nodeName, node.nodeValue);
}
Of course, you need to know the structure of the DOM, since intellisense doesn't work on dynamic objects; you can find some information about it here.
You should be able to query (there is a property somewhere) if a particular item has a child node or not, also, you can query if it is a parent node or if a particular item has a parent or not, and if it does, discard, and you can keep querying for parent such as item.parent.parent (pls check intellisense for exact object/property names) and if it returns nothing, it means there is only one parent (assuming item.parent doesnt return nothing), and you can organize how many levels deep the nodes can/must be. So based on the child or parent checking method (or both) you can choose to either include it in your collection or discard it.
Of course, you might get many "P" tags or DIV/SPAN tag's as your top level nodes/items. So, i'm assuming there is a chance you will not want these, so feel free to discard them and query their children.
I like Microsoft's Windows Forms tree-view object model. It has the tree, nodes, children collection, parent, prev, next (sibling), etc. and search function. However I'm looking for the same object model with no UI - simply tree object model.
Does C# have this kind of model or do I have to implement it myself?
C# is a programming language. It does not have object models.
You may be asking whether the .NET Framework has a built-in "tree" class. It does not. You can build your own using the generic collection classes like LinkedList<T> and List<T>.
You could always use XML and the XML namespaces. It's got all the things you requested. Start with and XMLDocument and keep added XMLNodes and adding XMLNodes to the XMLNodes for children. Then you can use xpath queries to retrieve nodes.
An XmlDocument object is the closest match I can think of to your requirements. It supports parent, child, previous, next, sibling, etc. You can also use XPath to query the tree and return a specific node or sets of nodes. Also, because it's Xml you can easily import and export the data to/from a text file.
I suggest you read about binary trees on MSDN. It will teach you how to model tree data structures in code.
Good luck.
I know i can use LogicalTreeHelper class to find children node for every element searching it by name. But is there a possibility to find a child node by Type? For example, what if i would like to find a ListBox element in my Window without knowing its Name property??
I don't think that there is a built in way of doing this. Probably the best approach would be to recursively call LogicalTreeHelper.GetChildren() until a child control of the specified type is found.
Note that descending the Logical tree cleanly is actually a little tricky, here's a nice article on the intricacies of both the visual and logical trees.
I don't think any helper code exists to do this for you so implementing a recursive walk over the tree is required.