none
Word exposes UndoRecord class for Undo operations but no RedoRecord? RRS feed

  • Question

  • I have the following code which inserts a macro button field into a Word document:

                    application.UndoRecord.StartCustomRecord();
                    WordNS.Range currentRange = application.Selection.Range;
    
                    WordNS.Field field = application.ActiveDocument.Fields.Add(currentRange, WordNS.WdFieldType.wdFieldMacroButton, "Field", false);
    
                    field.Locked = true;
                    field.Code.Borders.Enable = 1;
    
                    currentRange.Start = field.Code.End + 1;
                    currentRange.Select();
    
                    application.UndoRecord.EndCustomRecord();

    If I click Redo straight after inserting an item, a border is placed around the whole line:

    I've asked this question before but didn't get any helpful answers so I ended up using a different approach but now I'm required to implement this using macro buttons so I'd like to know if anyone could help.

    I know there is an UndoRecord class for various undo operations but is there anything similar for Redo?

    Is the Redo functionality exposed to the vsto developers?Is it possible to somehow clear the Redo?

    Edit:

    I've tried:

    application.ActiveDocument.UndoClear();

    But the border is still being set on the whole line when doing Redo(Ctrl+Y)

    Technologies:

    Microsoft Office Word 2010

    Application Level add-in

    VSTO 4

    .NET 4.0 C#



    • Edited by Denys W Monday, January 28, 2013 12:05 PM
    Monday, January 28, 2013 11:37 AM

Answers

  • Hi Denys

    <<But the action is embedded in:
    application.UndoRecord.StartCustomRecord();
    application.UndoRecord.EndCustomRecord();

    Which means the above only applies to Undo opeartions,am I right?

    So when you click Redo it will disregard that the applying of the border is inside a custom record and apply it to the whole line?>>

    The CustomRecord is, as far as Word is concerned, an artificial construct for the Undo list, alone. Redo doesn't "see" that, only the underlying list of actions that were "grouped" in order to create the single entry in the Undo list. In the background, Word is still maintaining the same list of actions that you'd see if you did not use a CustomRecord. And this is what Redo uses.

    It seems illogical that the border is applied to the entire line, but... I believe the reason is due to there being no selection when Redo is called, so the border formatting is being applied to the entire paragraph.


    Cindy Meister, VSTO/Word MVP, my blog

    • Marked as answer by Denys W Tuesday, January 29, 2013 12:53 PM
    Tuesday, January 29, 2013 8:22 AM
    Moderator

All replies

  • Hi Denys

    It's not clear what the problem is, and what the expected behavior should be?

    To answer your question literally, no, there is nothing similar for Redo as for UndoRecord. The only command for Redo is Document.Redo which would redo the last action.

    In the case of the code you show us, the last action is applying a border, so what you're getting is "expected behavior".


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, January 28, 2013 3:44 PM
    Moderator
  • Hello Cindy

    When I click Redo the border is applied to the whole line (as can be seen in the screen shot).

    The desired behavior would be to prevent that from happening.

    In the case of the code you show us, the last action is applying a border, so what you're getting is "expected behavior".

    But the action is embedded in:
    application.UndoRecord.StartCustomRecord();
    application.UndoRecord.EndCustomRecord();

    Which means the above only applies to Undo opeartions,am I right?

    So when you click Redo it will disregard that the applying of the border is inside a custom record and apply it to the whole line?


    • Edited by Denys W Tuesday, January 29, 2013 6:58 AM
    Tuesday, January 29, 2013 6:56 AM
  • Hi Denys

    <<But the action is embedded in:
    application.UndoRecord.StartCustomRecord();
    application.UndoRecord.EndCustomRecord();

    Which means the above only applies to Undo opeartions,am I right?

    So when you click Redo it will disregard that the applying of the border is inside a custom record and apply it to the whole line?>>

    The CustomRecord is, as far as Word is concerned, an artificial construct for the Undo list, alone. Redo doesn't "see" that, only the underlying list of actions that were "grouped" in order to create the single entry in the Undo list. In the background, Word is still maintaining the same list of actions that you'd see if you did not use a CustomRecord. And this is what Redo uses.

    It seems illogical that the border is applied to the entire line, but... I believe the reason is due to there being no selection when Redo is called, so the border formatting is being applied to the entire paragraph.


    Cindy Meister, VSTO/Word MVP, my blog

    • Marked as answer by Denys W Tuesday, January 29, 2013 12:53 PM
    Tuesday, January 29, 2013 8:22 AM
    Moderator
  • Couldn't you just perform another action?  If I insert a table in Word, and then hit CTRL+Z, and then I start typing something, the Redo goes to whatever the last thing I did was -- it no longer contains the insert table.

    Maybe as the last step in your UndoRecord you could just do something which has no real effect... like reapply the same paragraph style to the same paragraph, or something?

    Edit:
    I did some testing, and came up with the following code, this seems to work -- make sure to call it BEFORE your call to EndCustomRecord() -- When I do this, Word's Redo command is grayed out, and the hover text reads "Can't Repeat (Ctrl+Y)" so I think this is probably what you want. :-)

    try
    {
        if (app.UndoRecord.IsRecordingCustomRecord)
        {
            // Do something meaningless, such that the redo queue won't contain weirdness.
            try
            {
                // Attempt to set 1 character to itself -- if it fails, try again on the next paragraph -- until we hit one where this works.
                var paras = doc.Paragraphs;
                for (int i = 1; i <= paras.Count; i++)
                {
                    try
                    {
                        var r = paras[i].Range.Duplicate;
                        r.Collapse(WdCollapseDirection.wdCollapseStart);
                        while (string.IsNullOrEmpty(r.Text))
                        {
                            int _start = r.Start;
                            int _end = r.End;
    
                            r.Collapse(WdCollapseDirection.wdCollapseStart);
                            r.Move(WdUnits.wdCharacter, 1);
                            r.MoveEnd(WdUnits.wdCharacter, 1);
    
                            // If the the range stuck, abort the while loop.
                            if (r.Start == _start && r.End == _end) { break; }
                        }
    
                        // If the range is valid, perform our meaningless op, and exit the for loop
                        if (!string.IsNullOrEmpty(r.Text))
                        {
                            string old = r.Text;
                            r.Text = old;
                            break;
                        }
                    }
                    catch { /* do nothing */ }
                }
            }
            catch { /* do nothing */ }
        }
    }
    catch { /* do nothing */ }
    
    • Edited by Mikey Jensen Sunday, November 24, 2013 9:15 PM
    • Proposed as answer by Mikey Jensen Sunday, November 24, 2013 9:15 PM
    Wednesday, November 20, 2013 12:40 AM