Feb 17
Word 2010 Retrieve and Set Properties
Posted by Wei in C#, SharePoint, VSTO on 02 17th, 2011| | No Comments »

There are 3 types of properties for Word Documents... that's right, 3. Not 2. Initially I thought there are the Built in properties and the custom properties. But then, there are also content type properties.

I'm not sure how to explain this, but I'll do my best. Content Type properties are set in SharePoint. A custom content type is created and this custom content type inherits columns which are also set in SharePoint. I won't go into detail about how that is set up but it requires you to Allow Management of Content Types for the document library.

Once that is done and the columns added for this content type, they will appear as Content Type properties in the Word document. This means that when the user opens the word document, they can see the custom content types available for them to fill in.

Whatever the user enters into these custom content type properties will be saved into the columns of the list when the user saves the document. Note that if the user saves the document as a PDF, the columns will not be populated with the properties.

Anyway, to go back on to my topic of how to retrieve all 3 types of properties, here is the code:

Microsoft.Office.Interop.Word.Document currentDocument = Globals.ThisAddIn.Application.ActiveDocument;

DocumentProperties builtInDocProperties = (DocumentProperties)currentDocument.BuiltInDocumentProperties;
DocumentProperties customDocProperties = (DocumentProperties)currentDocument.CustomDocumentProperties;
MetaProperties contentTypeProperties = (MetaProperties)currentDocument.ContentTypeProperties;

// for each of these properties, I placed them in a Hashtable for ease of querying later
Hashtable htProperties = new Hashtable();

try
{
    foreach (MetaProperty prop in contentTypeProperties)
    {
        try
        {
            htProperties.Add(prop.Name, prop.Value);
        }
        catch { } // some property names/values cause exceptions, which is why I have this here
    }
}
catch
{
    // no content type properties found in this document
}

foreach (DocumentProperty prop in builtInDocProperties)
{
    try
    {
        htProperties.Add(prop.Name, prop.Value);
    }
    catch { }
}

foreach (DocumentProperty prop in customDocProperties)
{
    try
    {
        htProperties.Add(prop.Name, prop.Value);
    }
    catch { }
}

Now all the properties can be queried from the Hashtable htProperties.

For example, to get the title, you would use htProperties["Title"].ToString(). To get a custom property named "Favourite Colour", you would use htProperties["Favourite Colour"].ToString(). These properties are objects and need to be cast to the right variable type. Such as (DateTime)htProperties["BirthDate"].

To set the value of a property via code, you would need to know the name of the property and the type of property, be it a BuiltInDocumentProperty, a CustomDocumentProperty or a MetaProperty (content type property).

MetaProperty mp = contentTypeProperties["Favourite Colour"];
mp.Value = "Blue";

Feb 17

Usually most of my code is run on the server, meaning that the DLLs sit on the server. This means that I can use the Microsoft.SharePoint DLL to query SP lists, SP document libraries, and so on.

My last project required me to code a Word Add-in. This is a client side application that required a connection to SharePoint to query a SP list. This means that I am no longer able to use Microsoft.SharePoint DLL to query the list as that is only for server side code. I was aware that I had to use the Microsoft.SharePoint.Client and Microsoft.SharePoint.Client.Runtime DLLs but they did not exist in the .NET references list, so I was not able to add them (the list is filtered based on the type of app you are writing).

I did notice that the filter was set to ".NET Framework 4 Client Profile". I modified that to ".NET Framework 4" (in the Project Properties) and was then able to add the required DLL references.

The code to query the list on the client side is also quite different to querying the list on the server side.

Here's the code to query a list on the client side:

using SP = Microsoft.SharePoint.Client; // Make sure you have added the reference to Microsoft.SharePoint.Client
string sharePointSite = "http://intranet";
string siteName = "/site/subsite";
string listName = "MyListName";

SP.ClientContext ctx = new SP.ClientContext(sharePointSite + siteName);
var web = ctx.Web;
SP.List oList = web.Lists.GetByTitle(listName);

SP.CamlQuery oQuery = new SP.CamlQuery();
// the following query queries everything in the list ordered by ID and limited to 100 results
oQuery.ViewXml = "<View><Query><OrderBy><FieldRef Name='ID' Ascending='TRUE'/></OrderBy></Query><RowLimit>100</RowLimit></View>";
SP.ListItemCollection oListItems = oList.GetItems(oQuery);

ctx.Load(oListItems);

ctx.ExecuteQuery();

for (int i = 0; i < oListItems.Count; i++)
{
    SP.ListItem oListItem = oListItems[i];

    // do what you want with oListItem as it now contains the values in the list item.
}

Dec 11

I found that when I created a custom outlook add-in to run on the Send event, that it doesn't run when I deploy it on another machine (works fine on my own). After much research, I found that a requirement on the other machine is not included in the deployment files. We needed Extensibility.dll to be installed on the target machine. For some reason, this is not included in VS 2008, despite there being a KB article for this file for VS2005. Research shows that the majority of people had to downgrade back to VS2005 to get Extensibility.dll installed on target machines, but that is not necessary.

First you need to have Visual Studio 2005 installed somewhere so you can download the kb article from here and install it: http://support.microsoft.com/kb/908002. Without VS 2005, you won't be able to install this kb (which I find silly because you need it for VS2008).

After installing, you can then do one of the following 2 ways.

The hard way...

1.    Navigate to C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages, locate KB908002 folder.
2.    Log on to the machine which has Visual Studio 2008 installed and copy KB908002 folder to C:\Program Files\Microsoft SDKs\Windows\v6.0A\Bootstrapper\Packages

Now if you go to the pre-requisites list on VS 2008 (right click on the Setup and view properties, then click prerequisites), you'll see a new prerequisite, Shared Add-in Support Update for Microsoft .NET Framework 2.0. Check that and select "Download prerequisites from the same location as my application. This way, when you build it, a new folder is created with the required MSI in your deployment folder.

Or the easier way...

Navigate to C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\BootStrapper\Packages on the PC with VS2005 on it, locate KB908002 folder. Copy the extensibilityMSM.msi file to the target machine and install it there.

Which method you choose will depend on your own personal requirements.

Note that depending on what you need, you may need to right click on "Office.dll" in the Detected Dependencies folder and include it. I had to include Office.dll in my project too for the add-in to function.

Dec 11

In Visual Studio, create a new Project > Other Project Types > Extensibility > Shared Add-in and select the application or applications you are writing the add-in for. In my case, the add in is written for Outlook, so I unchecked everything and selected Outlook only. Hit next, give it a name and description. Then next again and check both boxes. Then Finish.

Since I'm writing code for the Send event, I need to have a new method:

    void OutlookApplication_ItemSend(object Item, ref bool Cancel)
    {
        MessageBox.Show("Item sent");
    }

That's it, now you need to package it into an MSI to install it on another machine. If all goes well, it will work on the new machine and you will have no problems, however that is not the case on most machines as I will be discussing in my next article.

Off topic

When you see the properties of the Setup file, set the Manufacturer to the name of the folder where you want this installed by default and also set the InstallAllUsers to True. On installation, the user has the option of changing it anyway, but it's good to have these set as default.

Sep 17

Here's a small snippet of code to upload a file from the filesystem into a SharePoint document library:

    Stream fStream = File.OpenRead("C:\\Temp\\Filename.pdf");
    byte[] contents = new byte[fStream.Length];

    fStream.Read(contents, 0, (int)fStream.Length);
    fStream.Close();

    SPList list = web.Lists[DocumentLibraryListName];
    Hashtable properties = new Hashtable();
    properties.Add("Title", "This is the title");
    properties.Add("Other_x0020_Properties", "Some other property");

    SPFile destFile = list.RootFolder.Files.Add("Filename.pdf", contents, properties, true);

    if (destFile == null)
    {
        lblError.Text = "<p>Error in adding file. Waiting to re-try.</p>";
    }

There is a free class available named DocLibHelper (search Google to download it) that would help you in uploading files among other things, but if all you need is to upload a document into a SharePoint library, then the above code will do.

« Previous Entries Next Entries »