Does CTreeCtrl::DeleteItem also delete all the node's sub-tree HTREEITEMs - visual-c++

Does CTreeCtrl::DeleteItem also delete all the node's sub-tree HTREEITEMs or must I recursively traverse the sub-tree myself and call DeleteItem on each one?

Looking at the MFC source code for CTreeCtrl::DeleteItem, it does this:
_AFXCMN_INLINE BOOL CTreeCtrl::DeleteItem(_In_ HTREEITEM hItem)
{
ASSERT(::IsWindow(m_hWnd));
return (BOOL)::SendMessage(m_hWnd, TVM_DELETEITEM, 0, (LPARAM)hItem);
}
Now looking at the documentation of TVM_DELETEITEM, it says the following (my emphasis):
Removes an item and all its children from a tree-view control
This would imply that recursively deleting is unnecessary, but I must admit that I've not tested it - the documentation may be misleading (as it sometimes is). One way to test is to note this line in the documentation:
The parent window receives a TVN_DELETEITEM notification code when
each item is removed.
So, by providing a handler for that message, you could verify that child items are deleted correctly.

From MSDN Docs on CTreeCtrl::DeleteItem where it says If hitem has the TVI_ROOT value, all items are deleted from the tree view control, I would infer that it will alo delete sub-nodes...

Related

Difference between different "resolve" functions in a custom NSMergePolicy

When implementing a custom NSMergePolicy, there are 3 functions available to overload:
final class MyMergePolicy: NSMergePolicy {
override func resolve(mergeConflicts list: [Any]) throws {
// ...
try super.resolve(mergeConflicts: list)
}
override func resolve(optimisticLockingConflicts list: [NSMergeConflict]) throws {
// ...
try super.resolve(optimisticLockingConflicts: list)
}
override func resolve(constraintConflicts list: [NSConstraintConflict]) throws {
// ...
try super.resolve(constraintConflicts: list)
}
}
Documentation for all 3 is exactly the same, it says: "Resolves the conflicts in a given list.", and I can't seem to find much information online.
What's the difference between these functions? What are the appropriate use cases for each of them?
The documentation kind of sucks here but you can get a partial explanation by looking at the arguments the functions receive.
resolve(optimisticLockingConflicts list: [NSMergeConflict]): Gets a list of one or more NSMergeConflict. This is what you'll usually hear about as a merge conflict, when the same underlying instance is modified on more than one managed object context.
resolve(constraintConflicts list: [NSConstraintConflict]): Gets a list of one or more NSConstraintConflict. This happens if you have uniqueness constraints on an entity but you try to insert an instance with a duplicate value.
The odd one out is resolve(mergeConflicts list: [Any]). This one is basically a leftover from the days before uniqueness constraints existed. It gets called for both types of conflict described above-- but only if you don't implement the more-specific function. So for example if you have a constraint conflict, resolve(constraintConflicts:...) gets called if you implemented it. If you didn't implement it, the context tries to fall back on resolve(mergeConflicts list: [Any]) instead. The same process applies for merge conflicts-- the context uses one function if it exists, and can fall back on the other. Don't implement this function, use one of the other two.
For both conflict types, the arguments give you details on the conflict, including the objects with the conflict and the details of the conflict. You can resolve them however you like.

NSFetchedResultsController + UICollectionViewDiffableDataSource + CoreData - How to diff on the entire object?

I'm trying to use some of the new diffing classes built into iOS 13 along with Core Data. The problem I am running into is that controllerdidChangeContentWith doesn't work as expected. It passes me a snapshot reference, which is a reference to a
NSDiffableDataSourceSnapshot<Section, NSManagedObjectID>
meaning I get a list of sections/Object ID's that have changed.
This part works wonderfully. But the problem comes when you get to the diffing in the collection view. In the WWDC video they happily call
dataSource.apply(snapshot, animatingDifferences: true)
and everything works magically, but that is not the case in the actual API.
In my initial attempt, I tried this:
resolvedSnapshot.appendItems(snapshot.itemIdentifiersInSection(withIdentifier: section).map {
controller.managedObjectContext.object(with: $0 as! NSManagedObjectID) as! Activity
}, toSection: .all)
And this works for populating the cells, but if data is changed on a cell (IE. the cell title) the specific cell is never reloaded. I took a look at the snapshot and it appears the issue is simply that I have references to these activity objects, so they are both getting updated simultaneously (Meaning the activity in the old snapshot is equivalent to the one in the new snapshot, so the hashes are equal.)
My current solution is using a struct that contains all my Activity class variables, but that disconnects it from CoreData. So my data source became:
var dataSource: UICollectionViewDiffableDataSource<Section, ActivityStruct>
That way the snapshot actually gets two different values, because it has two different objects to compare. This works, but it seems far from elegant, is this how we were meant to use this? Or is it just in a broken state right now? The WWDC video seems to imply it shouldn't require all this extra boilerplate.
I ran into the same issue and I think I figured out what works:
There are two classes: UICollectionViewDiffableDataSource and UICollectionViewDiffableDataSourceReference
From what I can tell, when you use the first, you're taking ownership as the "Source of Truth" so you create an object that acts as the data source. When you use the second (the data source reference), you defer the "Source of Truth" to another data source (in this case, CoreData).
You would instantiate a ...DataSourceReference essentially the same way as a ...DataSource:
dataSourceReference = UICollectionViewDiffableDataSourceReference(collectionView: collectionView, cellProvider: { (collectionView, indexPath, object) -> UICollectionViewCell? in
let identifier = <#cell identifier#>
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: identifier, for: indexPath)
<#cell configuration#>
return cell
})
And then later when you implement the NSFetchedResultsControllerDelegate, you can use the following method:
func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChangeContentWith snapshot: NSDiffableDataSourceSnapshotReference)
{
dataSourceReference.applySnapshot(snapshot, animatingDifferences: true)
}
I watched the WWDC video as well and didn't see this referenced. Had to make a few mistakes to get here. I hope it works for you!

TagHelper ; how to modify dynamically added children

The asp-items Razor "TagHelper" will add an <option> to a <select> for each value in the SelectList. I want to modify each of those children.
Specifically I want to disable some of them (i.e. add disabled="disabled").
Even more specifically I want to dynamically disable some of them; I'm using angular so I could ng-disabled="{dynamic_boolean_which_determines_disabled}". This means the option could be disabled at first, but after user makes a change, the option could be disabled (without page reload). Angular should take care of this; I think Angular and TagHelpers should work together in theory...
I expected:
I could somehow access an IEnumerable of the children <option> tags that would be created (i.e. one for each item in the SelectList), iterate the children tags, and SetAttribute("disabled") or SetAttribute("ng-disabled")...
I tried:
Creating my own TagHelper which targets the select[asp-items], and tries to GetChildContentAsync() and/or SetContent to reach an IEnumerable <option> tags and iterate them and process each, but I think this will only let me modify the entire InnerHtml as a string; feels hacky to do a String.replace, but I could do it if that's my only option? i.e. ChildrenContent.Replace("<option", "<option disabled=\"...\"")
Creating my own TagHelper which targets the option elements that are children of the select[asp-items], so I can individually process each. This works, but not on the dynamically-added <option> created by asp-items, it only works on "literal" <option> tags that I actually put into my cshtml markup.
I think this'll work but not ideal:
As I said above, I think I can get the result of TagHelper's dynamic asp-items <option></option> <option></option>, as a string, and do a string replace, but I prefer not to work with strings directly...
I suspect (I haven't tried it) that I could just do the work of asp-items myself; i.e. custom-items. But then I'm recreating the wheel by re-doing the work which asp-items could've done for me?
So I hadn't yet read the "AutoLinkHttpTagHelper" in the example which uses string replacement (specifically RegEx replace) to replace every occurrence of a URL, with an <a> pointed at that URL. The cases are slightly different*, but...
Anyway, here's my solution once I learned to stop worrying and love the string modification:
[HtmlTargetElement("select", Attributes = "asp-items")]
public class AspItemsNgDisabledTagHelper : SelectTagHelper
{
//Need it to process *after* the SelectTagHelper
public override int Order { get; } = int.MaxValue;
//https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring#ProcessAsync
public AspItemsNgDisabledTagHelper(IHtmlGenerator gen) : base(gen) {}
public override void Process(TagHelperContext context, TagHelperOutput output)
{
//Notice I'm getting the PostContent;
//SelectTagHelper leaves its literal content (i.e. in your CSHTML, if there is any) alone ; that's Content
//it only **appends** new options specified; that's PostContent
//Makes sense, but I still wasn't expecting it
var generated_options = output.PostContent.GetContent();
//Note you do NOT need to extend SelectTagHelper as I've done here
//I only did it to take advantage of the asp-for property, to get its Name, so I could pass that to the angular function
var select_for = this.For.Name;
//The heart of the processing is a Regex.Replace, just like
//their example https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring#inspecting-and-retrieving-child-content
var ng_disabled_generated_options = Regex.Replace(
generated_options,
"<option value=\"(\\w+)\">",
$"<option value=\"$1\" ng-disabled=\"is_disabled('{select_for}', '$1')\">");
//Finally, you Set your modified Content
output.PostContent.SetHtmlContent(ng_disabled_generated_options);
}
}
Few learning opportunities:
Was thinking I'd find AspForTagHelper and AspItemsTagHelper, (angular background suggested that the corresponding attributes; asp-for and asp-items, would be separate "directives" aka TagHelper).
In fact, TagHelper "matching" focuses on the element name (unlike angular which can match element name... attribute... class... CSS selector)
Therefore I found what I was looking for in SelectTagHelper, which has For and Items as properties. Makes sense.
As I said above, I extend SelectTagHelper, but that's not necessary to answer my original question. It's only necessary if you want access to the this.For.Name as I've done, but there may even be a way around that (i.e. re-bind its own For property here?)
I got on a distraction thinking I would need to override the SelectTagHelper's behavior to achieve my goals; i.e. Object-Oriented Thinking. In fact, even if I did extend SelectTagHelper, that doesn't stop a separate instance of the base SelectTagHelper from matching and processing the element. In other words, element processing happens in a pipeline.
This explains why extending and calling base.Process(), will result in Select doing its job twice; once when your instance matches, and again when the base instance matched.
(I suppose could've prevented SelectTagHelper from matching by creating a new element name like <asp-items-select>? But, not necessary... I just avoid calling base.Process(). So unless that's a bad practice...)
*Different in this way:
They want to create a tag where none exists, whereas I want to add an attribute a tag which is already there; i.e. the <option>
Though the <option> "tag" is generated by the SelectTagHelper in its PostContent (was expecting to find it in Content), and I don't think tags-generated-in-strings-by-content-mods can be matched with their corresponding TagHelper -- so maybe we really are the same in that we're just dealing with plain old strings
Their "data" aka "model" is implied in the text itself; they find a URL and that URL string becomes a unit of meaning they use. In my case, there is an explicit class for Modeling; the SelectList (<select>) which consists of some SelectListItem (<option>) -- but that class doesn't help me either.
That class only gives me attributes like public bool Disabled (remember, this isn't sufficient for me because the value of disabled could change to true or false within browser; i.e. client-side only), and public SelectListGroup Group -- certainly nothing as nonstandard as ng-disabled, nor a "catch-all" property like Attributes which could let me put arbitrary attributes (ng-disabled or anything else) in there.

NSManagedObject stops receiving merged changes after obtainPermanentIDsForObjects

I have a hierarchy of managed object contexts, like so:
A
/ \
B C
...where A's parent is the persistent store. A and C use a private queue, and B uses the main queue. I've found that doesn't seem to matter, but I'll note it anyway.
So, here is the best way to replicate the issue:
- Context B creates an object. Because I need to reference this same object multiple places, I obtain a permanent object ID via obtainPermanentIDsForObjects. I then save.
- Context A inherits the change, saves it out to the permanent store. Context C sees the change notification and merges the changes in. All is good so far.
- I grab the object from context C and change one of the properties. I then save. Context A inherits the change and saves it to disk.
This is where it gets weird. Context B never sees the change. There is a change notification I intercept like so:
-(void)contextDidSaveNotification:(NSNotification *)notification
{
NSManagedObjectContext *context = [notification object];
if(context!=_moc.parentContext)
return;
NSLog(#"Context %# did save, merging into %#, info:\n%#", context, _moc, [notification userInfo]);
[_moc mergeChangesFromContextDidSaveNotification:notification];
}
And I see the change go out, and seeing it merged in to context B. But the object I created in the first step never sees any changes.
I've traced this all back to one very specific thing. If I don't obtain a permanent object ID on the object in the very first step, the changes get merged back to the original object in context B just fine. But this leaves me without a reliable object ID to use in other contexts (as far as I know).
This seems like it could be a bug. I hope not. But for some reason when I obtain a permanent object ID it blocks changes from being merged back in from other contexts.
Has anyone else seen this behavior? Any solutions?
(I know changes from context C are making it in to A, and A is saving them to disk. If I relaunch the app the changes are there from disk.)

How to avoid returning a temporary object (C++)

The code below is showing a poor example of memory management; item is never de-allocated because a temporary copy of it is returned instead.
I've been scouring programming forums on and off for weeks but haven't found a clear explanation as to how to properly return a valid instance of type Item* while allowing item to be de-allocated.
In other words, what is a better alternative to this code that accomplishes the same return value and yet allows item to be de-allocated?
Item* Inventory::add(const string& name)
{
Item* item = new Item(name);
...(some other code here)...
return item;
}
Thanks!
You might think everything is destroyed once it goes outside the loop, but the pointer that is returned (and the memory that it points to) will stay. It is transferred to the object that calls this method, and no memory is leaked.

Resources