C# .NET Code to Add Comma as Thousands Separator to Currency Amounts in Word Document

Hi team,

I’m facing the below error while trying to edit the document. I’m trying to edit a open document (Active Document) via Word Add-in,

Unable to cast COM object of type ‘Microsoft.Office.Interop.Word.DocumentClass’ to class type ‘Aspose.Words.Document’. Instances of types that represent COM components cannot be cast to types that do not represent COM components; however they can be cast to interfaces as long as the underlying COM component supports QueryInterface calls for the IID of the interface.

Do you have solution for comma separation in docx, in thousand places ,i,e., for example if I entered values like 100000, it has to be displayed like $100,000.
We get the number value (like 100000) from dynamic XML keys.

@Amirtha,

You cannot typecast Microsoft.Office.Interop.Word.DocumentClass object to Aspose.Words.Document object. Secondly, please see these sample input & output Word documents (Docs 230905.zip (18.5 KB)) and try running the following C# code of Aspose.Words for .NET. The code will add thousands separator (comma) to the amounts starting with $ sign.

Document doc = new Document("C:\\Temp\\source.docx");

Regex regExpression = new Regex(@"\$\d+");
FindReplaceOptions findReplaceOptions = new FindReplaceOptions();
findReplaceOptions.Direction = FindReplaceDirection.Backward;
findReplaceOptions.ReplacingCallback = new MyReplaceEvaluator();

doc.Range.Replace(regExpression, "", findReplaceOptions);

doc.Save("C:\\Temp\\word.docx");

private class MyReplaceEvaluator : IReplacingCallback
{
    ///
    /// This is called during a replace operation each time a match is found.
    /// This method appends a number to the match string and returns it as a replacement string.
    ///
    ReplaceAction IReplacingCallback.Replacing(ReplacingArgs e)
    {
        // This is a Run node that contains either the beginning or the complete match.
        Node currentNode = e.MatchNode;

        // The first (and may be the only) run can contain text before the match,
        // in this case it is necessary to split the run.
        if (e.MatchOffset > 0)
            currentNode = SplitRun((Run)currentNode, e.MatchOffset);

        // This array is used to store all nodes of the match for further highlighting.
        ArrayList runs = new ArrayList();

        // Find all runs that contain parts of the match string.
        int remainingLength = e.Match.Value.Length;
        while (
            (remainingLength > 0) &&
            (currentNode != null) &&
            (currentNode.GetText().Length <= remainingLength))
        {
            runs.Add(currentNode);
            remainingLength = remainingLength - currentNode.GetText().Length;

            // Select the next Run node.
            // Have to loop because there could be other nodes such as BookmarkStart etc.
            do
            {
                currentNode = currentNode.NextSibling;
            }
            while ((currentNode != null) && (currentNode.NodeType != NodeType.Run));
        }

        // Split the last run that contains the match if there is any text left.
        if ((currentNode != null) && (remainingLength > 0))
        {
            SplitRun((Run)currentNode, remainingLength);
            runs.Add(currentNode);
        }

        DocumentBuilder builder = new DocumentBuilder((Document)e.MatchNode.Document);
        builder.MoveTo((Run)runs[runs.Count - 1]);

        builder.Font.Color = Color.Red;

        builder.Write("$" + Convert.ToDouble(e.Match.Value.Replace("$", "")).ToString("N").Replace(".00", ""));

        foreach (Run run in runs)
            run.Remove();

        return ReplaceAction.Skip;
    }

    ///
    /// Splits text of the specified run into two runs.
    /// Inserts the new run just after the specified run.
    ///
    private static Run SplitRun(Run run, int position)
    {
        Run afterRun = (Run)run.Clone(true);
        afterRun.Text = run.Text.Substring(position);
        run.Text = run.Text.Substring(0, position);
        run.ParentNode.InsertAfter(afterRun, run);
        return afterRun;
    }
}