The DocumentParts activity encapsulates an Office Open XML document. A DocumentParts activity only allows an activity that inherits from ContentPart as set by the AllowedItemType XAML attribute.

Note The current implementation targets an Excel spreadsheet document; however, future versions will further abstract DocumentParts to support any Open XML content part.

[Designer(typeof(MyData.Activities.OfficeXml.DocumentPartsDesigner))]
  public sealed class DocumentParts : SharePointBaseActivity
  {
    [Browsable(false)]
    public Collection<Activity> Activities { get; set; }
    public InArgument<string> LibraryTitle { get; set; }
    public InArgument<string> DocumentName { get; set; }

    //SharePoint MetaData that other activities might be interested in
    public OutArgument<Dictionary<string, object>> ArgFileMetaData { get; set; }
    public OutArgument<FileInformation> ArgFileInformation { get; set; }

    //Content parts in this document. Content parts refer to Word ContentControls and Excel Ranges
    public OutArgument<Dictionary<string, string>> ContentParts { get; set; }
    
    //Activity variable for composite
    private Variable<Int32> activityIndex =  new Variable<int>("ActivityIndex", 0);

    //Office Xml document, stream and parts
    private SpreadsheetDocument document;
    private Stream fileStream = null;
    private Dictionary<string, string> contentParts = null;


    public DocumentParts()
    {
      Activities = new Collection<Activity>();
    }

    //Cache composite activity metadata
    protected override void CacheMetadata(NativeActivityMetadata metadata)
    {
      metadata.SetChildrenCollection(Activities);
      metadata.AddImplementationVariable(activityIndex);

      base.CacheMetadata(metadata);
    }

    protected override void Execute(NativeActivityContext context)
    {
      string url = base.Url.Expression.ToString();
      string libraryTitle = this.LibraryTitle.Expression.ToString();
      string documentName = this.DocumentName.Expression.ToString();

      Dictionary<string, object> fileMetadata = new Dictionary<string, object>();
      FileInformation fileInformation = null;

      //Use the passed credentials
      if (this.NetworkCredential != null)
      {
        using(ClientContext clientContext = new ClientContext(url))
        {
          clientContext.Credentials = NetworkCredential.Get(context);

          Microsoft.SharePoint.Client.List sharedDocumentsList = clientContext.Web.Lists.GetByTitle(libraryTitle);

          CamlQuery camlQuery = new CamlQuery();
          camlQuery.ViewXml =
              @"<View>
                  <Query>
                    <Where>
                      <Eq>
                        <FieldRef Name='FileLeafRef'/>
                        <Value Type='Text'>" + documentName + @"</Value>
                      </Eq>
                    </Where>
                    <RowLimit>1</RowLimit>
                  </Query>
                </View>";
          Microsoft.SharePoint.Client.ListItemCollection listItems = sharedDocumentsList.GetItems(camlQuery);
          clientContext.Load(sharedDocumentsList);
          clientContext.Load(listItems);
          clientContext.ExecuteQuery();

          if (listItems.Count == 1)
          {
            ClientOM.ListItem item = listItems[0];

            fileMetadata.Add("FileRef", item["FileRef"]);
            fileMetadata.Add("FileType", item["File_x0020_Type"]);
            fileInformation = ClientOM.File.OpenBinaryDirect(clientContext, (string)item["FileRef"]);

            //Get the document stream if this Activity has ContentPart activities
            if (this.Activities.Count > 0)
            {
              fileStream = fileInformation.Stream;
            }
          }

          if (this.Activities.Count > 0)
          {
            this.FillParts();
          }

          //Set OutArguments
          context.SetValue(this.ArgFileInformation, fileInformation);
          context.SetValue(this.ArgFileMetaData, fileMetadata);
          context.SetValue(this.ContentParts, contentParts);
      }
      }
      else
      {
        //NOTE: Throw exception in production application
      }

    }

    //This version only allows Activities that inherit from ContentPart
    private void FillParts()
    {
      string reference = string.Empty;
      string viewName = string.Empty;
      string value = string.Empty;
      contentParts = new Dictionary<string, string>();

      if (fileStream != null)
      {
        using (MemoryStream memoryStream = new MemoryStream())
        {
          //Copy Xml Stream. This version is tightly coupled with Excel. Future versions will decouple to support
          //Word content parts
          Common.CopyStream(fileStream, memoryStream);
          using (document = SpreadsheetDocument.Open(memoryStream, false))
          {         
            //Add ContentParts dropped onto DocumentParts
            foreach (Activity a in this.Activities)
            {
              ContentPart part = (ContentPart)a;

              reference = part.Reference.Expression.ToString();
              viewName = part.ViewName.Expression.ToString();

              // Find the sheet with the supplied name, and then use that Sheet object to retrieve a reference to the appropriate worksheet.
              Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == viewName).FirstOrDefault();

              if (sheet == null)
              {
                throw new ArgumentException("sheetName");
              }
              contentParts.Add(part.Reference.Expression.ToString(), GetCellValue(sheet.Id, reference));
            }
          }
        }
      }
    }

    private string GetCellValue(StringValue sheetid, string reference)
    {

      string value = string.Empty;

      // Retrieve a reference to the worksheet part, and then use its Worksheet property to get a cell reference
      WorksheetPart wsPart = (WorksheetPart)(document.WorkbookPart.GetPartById(sheetid));
      Cell cell = wsPart.Worksheet.Descendants<Cell>().Where(c => c.CellReference == reference).FirstOrDefault();

      // If the cell does not exist, return an empty string
      if (cell != null)
      {
        value = cell.InnerText;

        // If the cell represents a numeric value, you are done. For dates, this code returns the serialized value that 
        // represents the date. The code handles strings and Booleans individually. For shared strings, the code looks up the 
        // corresponding value in the shared string table. For Booleans, the code converts the value into the words TRUE or FALSE.
        if (cell.DataType != null)
        {
          switch (cell.DataType.Value)
          {
            case CellValues.SharedString:
              // For shared strings, look up the value in the shared strings table.
              var stringTable = document.WorkbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
              // If the shared string table is missing, something is wrong. Return the index that you found in the cell.
              // Otherwise, look up the correct text in the table.
              if (stringTable != null)
              {
                value = stringTable.SharedStringTable.
                  ElementAt(int.Parse(value)).InnerText;
              }
              break;

            case CellValues.Boolean:
              switch (value)
              {
                case "0":
                  value = "FALSE";
                  break;
                default:
                  value = "TRUE";
                  break;
              }
              break;
          }
        }
      }

      return value;
    }
  }

Last edited Oct 10, 2011 at 4:51 AM by dvana, version 5

Comments

No comments yet.