2009-03-19 11 views
6

मुझे लगता है कि प्रोजेक्ट 2007 में ऐसे फ़ंक्शन हैं जो ऑपरेशन को अनुमति देते हैं जिन्हें एकल स्टैक आइटम में रखा जा सकता है, या "पूर्ववत लेनदेन" किया जा सकता है। For example:क्या मैं वर्ड या एक्सेल में पूर्ववत लेनदेन कर सकता हूं? (वीएसटीओ)

Application.OpenUndoTransaction "Create 6 tasks" 
Dim i As Integer 
For i = 1 To 6 
    ActiveProject.Tasks.Add "UndoMe " & i 
Next 
Application.CloseUndoTransaction 

इसका मतलब क्या है कि उपयोगकर्ता 6 बार बजाय एक एकल पूर्ववत कार्रवाई में कार्यों के सभी पूर्ववत कर सकते हैं, है।

वर्ड और/या एक्सेल में लागू करना बहुत अच्छा होगा, क्योंकि मैं वीएसटीओ में कुछ चीजें कर रहा हूं जो एक साथ कई बदलाव करता है, और यदि उपयोगकर्ता को क्लिक करना है तो यह थोड़ा परेशान होगा अगर वे गलती करते हैं तो कई बार पूर्ववत करें। यद्यपि वे विशिष्ट कार्य मौजूद नहीं हैं, क्या किसी को पता है कि यह किसी तरीके से किया जा सकता है या नहीं?

उत्तर

7

आप वीबीए में अंडो और रेडो कमांड रूटीन को ओवरराइट करके वर्ड में लेनदेन संबंधी व्यवहार अनुकरण कर सकते हैं (मुझे नहीं लगता कि वर्ड कमांड्स ओवरराइटिंग अकेले वीएसटीओ का उपयोग कर संभव है)। एक लेनदेन की शुरुआत एक बुकमार्क जोड़कर चिह्नित की जाती है, अंत को बुकमार्क को हटाकर चिह्नित किया जाता है।

पूर्ववत कॉल करते समय, हम जांचते हैं कि लेनदेन चिह्न बुकमार्क मौजूद है या मार्कर समाप्त होने तक पूर्ववत दोहराएं। रेडो ​​एक ही तरीके से काम कर रहा है। यह तंत्र दस्तावेज़ सामग्री के लिए किए गए सभी संशोधनों के लेनदेन पूर्ववत/पुनः समर्थन का समर्थन करता है। हालांकि, दस्तावेज़ गुणों में संशोधनों को पूर्ववत/दोबारा करने की अनुमति देने के लिए SetCustomProp मैक्रो का उपयोग करके एक विशेष तंत्र को लागू करने की आवश्यकता है। दस्तावेज़ गुण सीधे सेट नहीं किया जाना चाहिए बल्कि केवल इस मैक्रो के माध्यम से।

अपडेट: मैं स्पष्ट रूप से उल्लेख करना भूल गया कि यह दृष्टिकोण केवल कीबोर्ड शॉर्टकट्स और मेनू कमांड के साथ काम करता है, टूलबार बटन पर क्लिक करने से अभी भी एक-चरण पूर्ववत होता है। इसलिए हमने कस्टमर के साथ टूलबार बटन को प्रतिस्थापित करने का निर्णय लिया। कोड Word 2003 के साथ काफी देर के लिए उपयोग में है (यह Word 2007 के साथ परीक्षण नहीं है, इसलिए आश्चर्य के लिए तैयार रहना;)

Option Explicit 

' string constants for Undo mechanism 
Public Const BM_IN_MACRO As String = "_InMacro_" 

Public Const BM_DOC_PROP_CHANGE As String = "_DocPropChange_" 
Public Const BM_DOC_PROP_NAME As String = "_DocPropName_" 
Public Const BM_DOC_PROP_OLD_VALUE As String = "_DocPropOldValue_" 
Public Const BM_DOC_PROP_NEW_VALUE As String = "_DocPropNewValue_" 

'----------------------------------------------------------------------------------- 
' Procedure : EditUndo 
' Purpose : Atomic undo of macros 
'    Note: This macro only catches the menu command and the keyboard shortcut, 
'     not the toolbar command 
'----------------------------------------------------------------------------------- 
Public Sub EditUndo() ' Catches Ctrl-Z 

    'On Error Resume Next 
    Dim bRefresh As Boolean 
    bRefresh = Application.ScreenUpdating 
    Application.ScreenUpdating = False 

    Do 
     If ActiveDocument.Bookmarks.Exists(BM_DOC_PROP_CHANGE) Then 
      Dim strPropName As String 
      Dim strOldValue As String 

      strPropName = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range.Text 
      strOldValue = ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Range.Text 
      ActiveDocument.CustomDocumentProperties(strPropName).Value = strOldValue 
     End If 

    Loop While (ActiveDocument.Undo = True) _ 
     And ActiveDocument.Bookmarks.Exists(BM_IN_MACRO) 

    Application.ScreenUpdating = bRefresh 
End Sub 

'----------------------------------------------------------------------------------- 
' Procedure : EditRedo 
' Purpose : Atomic redo of macros 
'    Note: This macro only catches the menu command and the keyboard shortcut, 
'     not the toolbar command 
'----------------------------------------------------------------------------------- 
Public Sub EditRedo() ' Catches Ctrl-Y 

    Dim bRefresh As Boolean 
    bRefresh = Application.ScreenUpdating 
    Application.ScreenUpdating = False 

    Do 
     If ActiveDocument.Bookmarks.Exists(BM_DOC_PROP_CHANGE) Then 
      Dim strPropName As String 
      Dim strNewValue As String 

      strPropName = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range.Text 
      strNewValue = ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Range.Text 
      ActiveDocument.CustomDocumentProperties(strPropName).Value = strNewValue 
     End If 

    Loop While (ActiveDocument.Redo = True) _ 
     And ActiveDocument.Bookmarks.Exists(BM_IN_MACRO) 

    Application.ScreenUpdating = bRefresh 

End Sub 

'----------------------------------------------------------------------------------- 
' Procedure : SetCustomProp 
' Purpose : Sets a custom document property 
'----------------------------------------------------------------------------------- 
Public Function SetCustomProp(oDoc As Document, strName As String, strValue As String) 

    Dim strOldValue As String 

    On Error GoTo existsAlready 
    strOldValue = "" 
    oDoc.CustomDocumentProperties.Add _ 
     Name:=strName, LinkToContent:=False, Value:=Trim(strValue), _ 
     Type:=msoPropertyTypeString 
    GoTo exitHere 

existsAlready: 
    strOldValue = oDoc.CustomDocumentProperties(strName).Value 
    oDoc.CustomDocumentProperties(strName).Value = strValue 

exitHere: 
    ' support undo/redo of changes to the document properties 
    'On Error Resume Next 
    Dim bCalledWithoutUndoSupport As Boolean 

    If Not ActiveDocument.Bookmarks.Exists(BM_IN_MACRO) Then 
     ActiveDocument.Range.Bookmarks.Add BM_IN_MACRO, ActiveDocument.Range 
     bCalledWithoutUndoSupport = True 
    End If 

    Dim oRange As Range 
    Set oRange = ActiveDocument.Range 

    oRange.Collapse wdCollapseEnd 
    oRange.Text = " " 
    oRange.Bookmarks.Add "DocPropDummy_", oRange 

    oRange.Collapse wdCollapseEnd 
    oRange.Text = strName 
    oRange.Bookmarks.Add BM_DOC_PROP_NAME, oRange 

    oRange.Collapse wdCollapseEnd 
    oRange.Text = strOldValue 
    oRange.Bookmarks.Add BM_DOC_PROP_OLD_VALUE, oRange 

    oRange.Collapse wdCollapseEnd 
    oRange.Text = strValue 
    oRange.Bookmarks.Add BM_DOC_PROP_NEW_VALUE, oRange 

    oRange.Bookmarks.Add BM_DOC_PROP_CHANGE 
    ActiveDocument.Bookmarks(BM_DOC_PROP_CHANGE).Delete 

    Set oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Range 
    ActiveDocument.Bookmarks(BM_DOC_PROP_NEW_VALUE).Delete 
    If Len(oRange.Text) > 0 Then oRange.Delete 

    Set oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Range 
    ActiveDocument.Bookmarks(BM_DOC_PROP_OLD_VALUE).Delete 
    If Len(oRange.Text) > 0 Then oRange.Delete 

    Set oRange = ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Range 
    ActiveDocument.Bookmarks(BM_DOC_PROP_NAME).Delete 
    If Len(oRange.Text) > 0 Then oRange.Delete 

    Set oRange = ActiveDocument.Bookmarks("DocPropDummy_").Range 
    ActiveDocument.Bookmarks("DocPropDummy_").Delete 
    If Len(oRange.Text) > 0 Then oRange.Delete 

    If bCalledWithoutUndoSupport And ActiveDocument.Bookmarks.Exists(BM_IN_MACRO) Then 
     ActiveDocument.Bookmarks(BM_IN_MACRO).Delete 
    End If 

End Function 

'----------------------------------------------------------------------------------- 
' Procedure : SampleUsage 
' Purpose : Demonstrates a transaction 
'----------------------------------------------------------------------------------- 
Private Sub SampleUsage() 

    On Error Resume Next 

    ' mark begin of transaction 
    ActiveDocument.Range.Bookmarks.Add BM_IN_MACRO 

    Selection.Text = "Hello World" 
    ' do other stuff 

    ' mark end of transaction 
    ActiveDocument.Bookmarks(BM_IN_MACRO).Delete 

End Sub 
+0

वाह! मुझे लगता है कि मैं वह जवाब ले जाऊंगा "हाँ, लेकिन यह सुंदर नहीं है"! मुझे लगता है कि मैं इसे केवल तभी बनाएगा जब मुझे जरूरत है, अब के लिए बहुत ज्यादा गड़बड़ नहीं करना चाहते हैं। हालांकि दिलचस्प सामान। – Gavin

+0

क्या किसी ने वर्ड 2007 में काम करने के लिए इसे प्राप्त किया है? मैं बस सरल शुरू करने की कोशिश कर रहा हूँ; मैं जोड़ने का प्रयास करता हूं: "सब एडिट एंडो()/मैगबॉक्स (" हैलो ")/ActiveDocument.Undo/End Sub" या तो खुले दस्तावेज़ (मैंने इसे डॉकम के रूप में भी सहेजने की कोशिश की) या Normal.dotm पर।जब मैं दस्तावेज़ दस्तावेज़ में नियंत्रण-जेड दबाता हूं तो इनमें से कोई भी प्रयास मैक्रो का आह्वान नहीं करता है। मदद? –

+0

@DGGenuine: 'EditUndo' कमांड को ओवरराइट करना Word 2007 और 2010 में भी काम करना चाहिए। वर्तमान दस्तावेज़ या संलग्न टेम्पलेट में मैक्रो को मॉड्यूल के अंदर होना चाहिए। क्या आप वाकई अपने कीबोर्ड शॉर्टकट को फिर से कॉन्फ़िगर नहीं किया है? क्या कोई अन्य ऐड-इन्स सक्रिय है जो अंतर्निहित वर्ड कमांड के साथ गड़बड़ है? –

1

एक्सेल में इसके वीबीए आर्किटेक्चर के हिस्से के रूप में पूर्ववत और फिर से करने के लिए कुछ (सीमित) अंतर्निहित समर्थन है।

मैं VSTO से परिचित नहीं हूँ, इसलिए मैं अगर यह तुम बाहर में मदद मिलेगी पता नहीं है, लेकिन आप अधिक जानकारी के लिए this SO question पर एक नज़र ले जा सकते हैं।

+0

धन्यवाद, यह प्रश्न भी देखा, वास्तव में खुद को पूर्ववत करने के विचार को कल्पना नहीं किया, हालांकि, खतरे से भरा हुआ दिखता है। इसके अलावा वीएसटीओ मूल रूप से वीबीए ++ है (इस तरह मैं इसे किसी भी तरह से सोचना पसंद करता हूं), लेकिन इस विशेष संबंध में मुझे नहीं लगता कि इसमें कोई अतिरिक्त क्षमता है। – Gavin

2

मैं थोड़ी देर के लिए इस पर चबाने किया गया है। यहां एक छिपी हुई दस्तावेज़ का उपयोग करने का मेरा प्रयास है, फिर छुपे हुए दस्तावेज़ से WordOpenXML को पकड़ना और वास्तविक दस्तावेज़ में इसे रखने के लिए जब किसी भी प्रकार की VSTO क्रियाओं को एक पूर्ववत करना आवश्यक है।

//Usage from ThisDocument VSTO Document level project 
public partial class ThisDocument 
{ 
    //Used to buffer writing text & formatting to document (to save undo stack) 
    public static DocBuffer buffer; 

    //Attached Template 
    public static Word.Template template; 

    private void ThisDocument_Startup(object sender, System.EventArgs e) 
    {   
     //Ignore changes to template (removes prompt to save changes to template) 
     template = (Word.Template)this.Application.ActiveDocument.get_AttachedTemplate(); 
     template.Saved = true;    

     //Document buffer 
     buffer = new DocBuffer(); 

     //Start buffer 
     ThisDocument.buffer.Start(); 

     //This becomes one "undo" 
     Word.Selection curSel = Globals.ThisDocument.Application.Selection; 
     curSel.TypeText(" "); 
     curSel.TypeBackspace(); 
     curSel.Font.Bold = 1; 
     curSel.TypeText("Hello, world!"); 
     curSel.Font.Bold = 0; 
     curSel.TypeText(" "); 

     //end buffer, print out text 
     ThisDocument.buffer.End(); 
    } 

    void Application_DocumentBeforeClose(Microsoft.Office.Interop.Word.Document Doc, ref bool Cancel) 
    { 
     buffer.Close(); 
    } 

    private void ThisDocument_Shutdown(object sender, System.EventArgs e) 
    { 
     buffer.Close();   
    } 
} 

यहाँ DocBuffer क्लास है:

public class DocBuffer 
{ 
    //Word API Objects 
    Word._Document HiddenDoc; 
    Word.Selection curSel; 
    Word.Template template; 

    //ref parameters 
    object missing = System.Type.Missing; 
    object FalseObj = false; //flip this for docbuffer troubleshooting 
    object templateObj; 

    //Is docbuffer running? 
    public Boolean started{ get; private set; } 

    //Open document on new object 
    public DocBuffer() 
    { 
     //Clear out unused buffer bookmarks 
     Word.Bookmarks bookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; 
     bookmarks.ShowHidden = true; 

     foreach (Word.Bookmark mark in bookmarks) 
     { 
      if (mark.Name.Contains("_buf")) 
      { 
       mark.Delete(); 
      } 
     } 

     //Remove trail of undo's for clearing out the bookmarks 
     Globals.ThisDocument.UndoClear(); 

     //Set up template 
     template = ThisDocument.template; 
     templateObj = template; 

     //Open Blank document, then attach styles *and update 
     HiddenDoc = Globals.ThisDocument.Application.Documents.Add(ref missing, ref missing, ref missing, ref FalseObj); 
     HiddenDoc.set_AttachedTemplate(ref templateObj); 
     HiddenDoc.UpdateStyles(); 

     //Tell hidden document it has been saved to remove rare prompt to save document 
     HiddenDoc.Saved = true; 

     //Make primary document active 
     Globals.ThisDocument.Activate(); 

    } 

    ~DocBuffer() 
    { 
     try 
     { 
      HiddenDoc.Close(ref FalseObj, ref missing, ref missing); 
     } 
     catch { } 
    } 

    public void Close() 
    { 
     try 
     { 
      HiddenDoc.Close(ref FalseObj, ref missing, ref missing); 
     } 
     catch { } 
    } 

    public void Start() 
    { 
     try 
     { 
      //Make hidden document active to receive selection 
      HiddenDoc.Activate(); //results in a slight application focus loss 
     } 
     catch (System.Runtime.InteropServices.COMException ex) 
     { 
      if (ex.Message == "Object has been deleted.") 
      { 
       //Open Blank document, then attach styles *and update 
       HiddenDoc = Globals.ThisDocument.Application.Documents.Add(ref missing, ref missing, ref missing, ref FalseObj); 
       HiddenDoc.set_AttachedTemplate(ref templateObj); 
       HiddenDoc.UpdateStyles(); 
       HiddenDoc.Activate(); 
      } 
      else 
       throw; 
     } 

     //Remove Continue Bookmark, if exists 
     Word.Bookmarks hiddenDocBookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; 
     if (hiddenDocBookmarks.Exists("Continue")) 
     { 
      object deleteMarkObj = "Continue"; 
      Word.Bookmark deleteMark = hiddenDocBookmarks.get_Item(ref deleteMarkObj); 
      deleteMark.Select(); 
      deleteMark.Delete(); 
     } 

     //Tell hidden document it has been saved to remove rare prompt to save document 
     HiddenDoc.Saved = true; 

     //Keep track when started 
     started = true; 
    } 

    //Used for non-modal dialogs to bring active document back up between text insertion 
    public void Continue() 
    { 
     //Exit quietly if buffer hasn't started 
     if (!started) return; 

     //Verify hidden document is active 
     if ((HiddenDoc as Word.Document) != Globals.ThisDocument.Application.ActiveDocument) 
     { 
      HiddenDoc.Activate(); 
     } 

     //Hidden doc selection 
     curSel = Globals.ThisDocument.Application.Selection; 

     //Hidden doc range 
     Word.Range bufDocRange; 

     //Select entire doc, save range 
     curSel.WholeStory(); 
     bufDocRange = curSel.Range; 

     //Find end, put a bookmark there 
     bufDocRange.SetRange(curSel.End, curSel.End); 
     object bookmarkObj = bufDocRange; 

     //Generate "Continue" hidden bookmark 
     Word.Bookmark mark = Globals.ThisDocument.Application.ActiveDocument.Bookmarks.Add("Continue", ref bookmarkObj); 
     mark.Select(); 

     //Tell hidden document it has been saved to remove rare prompt to save document 
     HiddenDoc.Saved = true; 

     //Make primary document active 
     Globals.ThisDocument.Activate(); 
    } 

    public void End() 
    { 
     //Exit quietly if buffer hasn't started 
     if (!started) return; 

     //Turn off buffer started flag 
     started = false; 

     //Verify hidden document is active 
     if ((HiddenDoc as Word.Document) != Globals.ThisDocument.Application.ActiveDocument) 
     { 
      HiddenDoc.Activate(); 
     } 

     //Remove Continue Bookmark, if exists 
     Word.Bookmarks hiddenDocBookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; 
     hiddenDocBookmarks.ShowHidden = true; 
     if (hiddenDocBookmarks.Exists("Continue")) 
     { 
      object deleteMarkObj = "Continue"; 
      Word.Bookmark deleteMark = hiddenDocBookmarks.get_Item(ref deleteMarkObj); 
      deleteMark.Delete(); 
     } 

     //Hidden doc selection 
     curSel = Globals.ThisDocument.Application.Selection; 

     //Hidden doc range 
     Word.Range hiddenDocRange; 
     Word.Range bufDocRange; 

     //Select entire doc, save range 
     curSel.WholeStory(); 
     bufDocRange = curSel.Range; 

     //If cursor bookmark placed in, move there, else find end of text, put a bookmark there 
     Boolean cursorFound = false; 
     if (hiddenDocBookmarks.Exists("_cursor")) 
     { 
      object cursorBookmarkObj = "_cursor"; 
      Word.Bookmark cursorBookmark = hiddenDocBookmarks.get_Item(ref cursorBookmarkObj); 
      bufDocRange.SetRange(cursorBookmark.Range.End, cursorBookmark.Range.End); 
      cursorBookmark.Delete(); 
      cursorFound = true; 
     } 
     else 
     { 
      //The -2 is done because [range object].WordOpenXML likes to drop bookmarks at the end of the range 
      bufDocRange.SetRange(curSel.End - 2, curSel.End - 2); 
     } 

     object bookmarkObj = bufDocRange; 

     //Generate GUID for hidden bookmark 
     System.Guid guid = System.Guid.NewGuid(); 
     String id = "_buf" + guid.ToString().Replace("-", string.Empty); 
     Word.Bookmark mark = Globals.ThisDocument.Application.ActiveDocument.Bookmarks.Add(id, ref bookmarkObj); 

     //Get OpenXML Text (Text with formatting) 
     curSel.WholeStory(); 
     hiddenDocRange = curSel.Range; 
     string XMLText = hiddenDocRange.WordOpenXML; 

     //Clear out contents of buffer 
     hiddenDocRange.Delete(ref missing, ref missing); //comment this for docbuffer troubleshooting 

     //Tell hidden document it has been saved to remove rare prompt to save document 
     HiddenDoc.Saved = true; 

     //Make primary document active 
     Globals.ThisDocument.Activate(); 

     //Get selection from new active document 
     curSel = Globals.ThisDocument.Application.Selection; 

     //insert buffered formatted text into main document 
     curSel.InsertXML(XMLText, ref missing); 

     //Place cursor at bookmark+1 (this is done due to WordOpenXML ignoring bookmarks at the end of the selection) 
     Word.Bookmarks bookmarks = Globals.ThisDocument.Application.ActiveDocument.Bookmarks; 
     bookmarks.ShowHidden = true; 

     object stringObj = id; 
     Word.Bookmark get_mark = bookmarks.get_Item(ref stringObj); 
     bufDocRange = get_mark.Range; 

     if (cursorFound) //Canned language actively placed cursor 
      bufDocRange.SetRange(get_mark.Range.End, get_mark.Range.End); 
     else //default cursor at the end of text 
      bufDocRange.SetRange(get_mark.Range.End + 1, get_mark.Range.End + 1); 
     bufDocRange.Select(); 
} 
4

Word 2010 Application.UndoRecord वस्तु के माध्यम से ऐसा करने की क्षमता प्रदान करता है। देखें http://msdn.microsoft.com/en-us/library/hh128816.aspx

+0

हालांकि यह एक वास्तविक "लेनदेन" नहीं है - यह सिर्फ एक सिंगल जैसा दिखने के लिए चीनी है पूर्ववत स्टैक में पूर्ववत ऑपरेशन - यदि आप कॉल करते हैं। किसी भी स्तर पर * नेस्टेड अंडो रिकॉर्ड्स के सभी * पूर्ववत और निरस्त हो जाते हैं, यह बहुत लंगड़ा है। – BrainSlugs83

संबंधित मुद्दे