This project has moved and is read-only. For the latest updates, please go here.

How not dispose of child objects?

Sep 26, 2014 at 8:13 PM
Edited Sep 26, 2014 at 8:13 PM
I want to create my own custom collection of Word objects, but I don't know how to do this without have these objects disposed when the parent COM collection is disposed.

For example, something like this:


GenericCollection<NetOffice.WordApi.Bookmarks> customCollection = new GenericCollection<NetOffice.WordApi.Bookmarks>();

using (NetOffice.WordApi.Bookmarks bookmarks = application.ActiveDocument.Bookmarks)
{
// if bookmark meets some special criteria add to my own collection
foreach (NetOffice.WordApi.Bookmark bookmark in bookmarks) customCollection.Add(bookmark);
}



At the end of the using statement, all child bookmarks in my custom collection are automatically disposed.

How can I only dispose of the parent "bookmarks" collection object, but keep the children alive in my custom collection until I am done using them? (eventually I will call "customCollection.Dispose()" to dispose of my custom collection and bookmarks)

Thank you for any advice!
Sep 27, 2014 at 7:44 AM
Not sure i'm understand this. Your bookmark is still alive in Office, just the local proxy is destroyed.
Create a new proxy if you want. (application.ActiveDocument.Bookmarks[i]) (otherwise, may this is a scenario the NO proxy-wrapper class is just create local, aren't so?)

In NO 1.7 (available in the download section) you can disable the com proxy management (temporaily) if you want:

bool NetOffice.Settings.Default.EnableProxyManagement{get; set;}

Be careful with these option!
*Sebastian
Sep 28, 2014 at 10:37 PM
Edited Sep 28, 2014 at 10:38 PM
Thank you for the reply, Sebastian.

Let me try to explain this more clearly. Let's assume I want to create a method that returns collection of all bookmarks that start with a specified prefix. Using NetOffice, this method could like something like this:


private List<NetOffice.WordApi.Bookmark> GetBookmarksWithPrefix(NetOffice.WordApi.Document doc, string prefix)
{
List<NetOffice.WordApi.Bookmark> bookmarkList = new List<NetOffice.WordApi.Bookmark>();

using (NetOffice.WordApi.Bookmarks bookmarks = doc.Bookmarks)
    foreach (NetOffice.WordApi.Bookmark bookmark in bookmarks)
        if (bookmark.Name.StartsWith(prefix)) bookmarkList.Add(bookmark);

return bookmarkList;
}


Obviously, this won't work as expected, because when the "using" statement disposes "bookmarks", then all child bookmark objects in the bookmarkList collection will de disposed too.

So how do I either not dispose of child objects ("bookmark") when the parent is disposed ("bookmarks"), or how do I clone/copy a child object such that the clone/copy is not disposed when the original child object is disposed?
Create a new proxy if you want. (application.ActiveDocument.Bookmarks[i])
Although I understand this suggestion (create a new proxy) will work, for performance purposes this doesn't seem like the ideal solution. If I have a document with 10,000 bookmarks, I assume using this approach (re-fetching the bookmark just to create a new proxy) is not ideal. Rather, I would think either not disposing the original proxy or creating a clone/copy of the proxy would perform better.

Thank you for your ideas and your contributions to NetOffice.
Sep 30, 2014 at 1:03 PM
Edited Sep 30, 2014 at 3:32 PM
You have another option:
using (NetOffice.WordApi.Bookmarks bookmarks = doc.Bookmarks)
{
     foreach (NetOffice.WordApi.Bookmark bookmark in bookmarks)
     {
          if (bookmark.Name.StartsWith(prefix))
         {
               bookmarkList.Add(bookmark);
               
               // remove bookmark proxy from its parent
               bookmark.ParentObject.RemoveChildObject(bookmark);

              // now you have to make sure dispose is called for the bookmark at hand
              // otherwise you can re-add the bookmark (as child) to another proxy instance
              // in this case doc for example:
              doc.AddChildObject(bookmark);
         }
     }
}
*Sebastian
Oct 1, 2014 at 8:10 PM
Perfect! Thank you, Sebastian. RemoveChildObject() is what I was looking for.

In case anyone is interested, we created extension methods to simplify this:
public static COMObject RemoveFromParent(this COMObject value)
{
    if (value.ParentObject.IsNotNull()) value.ParentObject.RemoveChildObject(value);
    return value;
}

public static T RemoveFromParent<T>(this T value) where T : COMObject
{
    if (value.ParentObject.IsNotNull()) value.ParentObject.RemoveChildObject(value);
    return value;
}
Example usage:
List<NetOffice.WordApi.Bookmark> bookmarkList = new List<NetOffice.WordApi.Bookmark>();

using (NetOffice.WordApi.Bookmarks bookmarks = doc.Bookmarks)
{
    foreach (NetOffice.WordApi.Bookmark bookmark in bookmarks)
    {
        if (bookmark.Name.StartsWith(prefix))
        {           
           bookmarkList.Add(bookmark.RemoveFromParent<NetOffice.WordApi.Bookmark>());
        }
    }
}

return bookmarkList;
Obviously it is the responsibility of the caller to properly dispose of bookmarkList and its NetOffice.WordApi.Bookmark objects.

We've actually created a disposable GenericCOMObjectCollection class to help with this.
public abstract class GenericCOMObjectCollection<TItem> : Collection<TItem>, IDisposable where TItem : COMObject
{

    public virtual void Dispose()
    {
        foreach (TItem item in this) item.Dispose();
    }

}
Then create a strongly typed class that can be used and properly disposed of:
public class BookmarkCollection : GenericCOMObjectCollection<OfficeWord.Bookmark> { }