2011-07-11 76 views
1

我想手動實現TextBox的基本撤銷系統(因爲my last question中提到的問題)。我一直試圖做幾個小時,但我找不到方法。有誰知道這是否可能?如何在TextBox中實現自定義撤消

看來,這樣做需要,例如,檢測到用戶已經改變了插入位置,但我無法弄清楚如何做到這一點。當然,我可以聽箭頭鍵,並檢測鼠標點擊,但似乎不可能 - 至少在箭頭鍵的情況下 - 實際上可以告訴SelectionStart是否已更改已更改

如果有人有任何想法,我會很感激。

湯姆

+0

看看http://stackoverflow.com/q/800940/157666,請。關於這個話題有很多討論。 – apros

+0

這些談論關於實現撤消一個TextBox的哪一個?我看不到它。我問了一個關於TextBox的非常具體的問題,而不是關於實現撤銷系統的一般問題。 – Tom

回答

0

這是有點老了,但聽起來完全像你需要: http://msmvps.com/blogs/peterritchie/archive/2006/09/10/Changing-TextBox-Text-as-an-Undo_2D00_able-Action.aspx

綜上所述,當你做你的標籤更換,只需在框中追加選擇的所有文本您的4個空格,然後將整個文本粘貼回框中。

這應該允許用戶按ctrl + z來撤消整個事情。現在,我不知道如果他們在完成空格之後繼續打字會發生什麼......我假設它將全部從ctrl + z新聞中刪除。

+0

使用TextBox.Paste(string)無法正常工作;它會在添加文本之前在撤消歷史中創建一個新事件。替換文本框的整個文本不會突出顯示新文本,並且我認爲這對大文件來說會很慢。 – Tom

2

您是否可以處理TextChanged事件,並在每次更改時將文本框內容壓入堆棧,然後在每次用戶點擊Ctrl-Z時彈出並刷新TextBox

+0

這不會突出顯示新文本(例如,在記事本中鍵入內容並按幾次Ctrl + Z;新文本在出現時突出顯示),並且我認爲對於大文件來說會很慢。 – Tom

+0

在沒有銀彈解決方案的情況下,您採取的任何路線都可能需要優化和創新。我無法想象,編寫自己的算法來突出顯示在執行ctrl-z時發生更改的文本,或者在線查找並有效地返回兩個字符串的差異會很困難。 – alexD

3

這是我開發的解決方案,爲我工作得很好:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace INQ_adm.Forms.ControlsX 
{ 
    public class TextBoxX : TextBox 
    { 
     private static int UNDO_LIMIT = 0; 
     private List<Item> LastData = new List<Item>(); 
     private int undoCount = 0; 
     private Boolean undo = false; 

     public TextBoxX() 
     { 
      InitializeComponent(); 
     } 

     protected override bool ProcessCmdKey(ref Message msg, Keys keyData) 
     { 
      if (keyData == (Keys.Control | Keys.Z)) 
      { 
       undo = true; 
       try 
       { 
        ++undoCount; 
        this.Text = LastData[LastData.Count - undoCount - 1].text; 
        this.SelectionStart = LastData[LastData.Count - undoCount - 1].position; 
        this.PerformLayout(); 
       } 
       catch 
       { 
        --undoCount; 
       } 

       undo = false; 
       return true; 
      } 

      if (keyData == (Keys.Control | Keys.Y)) 
      { 
       undo = true; 
       try 
       { 
        --undoCount; 
        this.Text = LastData[LastData.Count - undoCount + 1].text; 
        this.SelectionStart = LastData[LastData.Count - undoCount + 1].position; 
        this.PerformLayout(); 
       } 
       catch 
       { 
        ++undoCount; 
       } 

       undo = false; 
       return true; 
      } 
      return base.ProcessCmdKey(ref msg, keyData); 
     } 

     private void textBoxX_TextChanged(object sender, EventArgs e) 
     { 
      if (!undo) 
      { 
       LastData.RemoveRange(LastData.Count - undoCount, undoCount); 
       LastData.Add(new Item(this.Text, this.SelectionStart)); 
       undoCount = 0; 
        if (UNDO_LIMIT != 0 && UNDO_LIMIT + 1 < LastData.Count) 
       { 
        LastData.RemoveAt(0); 
       } 
      } 
     } 

     private void InitializeComponent() 
     { 
      this.TextChanged += new System.EventHandler(this.textBoxX_TextChanged); 
     } 
    } 

    public class Item 
    { 
     public String text; 
     public int position; 

     public Item(String text, int position) 
     { 
      this.text = text; 
      this.position = position; 
     } 
    } 
} 
+0

工作得很好,讓我給予upvote。 – codah