2009-02-28 18 views
24

के लिए अच्छी और कुशल पूर्ववत/पुनः कार्यक्षमता को कैसे कार्यान्वित करें मेरे पास एक टेक्स्टबॉक्स है जिसे मैं पूर्ववत/पुनः कार्यक्षमता को कार्यान्वित करना चाहता हूं। मैं have read है कि इसमें पहले से ही कुछ मामूली पूर्ववत कार्यक्षमता हो सकती है, लेकिन यह छोटी है? वैसे भी, मैं यह जानने के लिए कि आप आगे कैसे बढ़ेंगे और ऐसा करेंगे, दोनों ही पूर्ववत और फिर से कार्यक्षमता को कार्यान्वित करना चाहते हैं।टेक्स्टबॉक्स

मैंने Memento Pattern के बारे में पढ़ा है और कुछ को कोडप्रोजेक्ट पर Generic Undo/Redo उदाहरण पर देखा है। और पैटर्न का अर्थ समझ में आता है। मैं अपने सिर को लपेटने के लिए प्रतीत नहीं कर सकता हूं कि इसे कैसे कार्यान्वित किया जाए। और TextBox की सामग्री के लिए इसे प्रभावी ढंग से कैसे करें।

बेशक मैं को TextChanges पर संग्रहीत कर सकता था, लेकिन इससे बहुत अधिक मेमोरी बहुत तेज हो जाएगी, खासकर अगर TextBox में बहुत सारे टेक्स्ट थे।

तो वैसे भी, मैं इस कार्यक्षमता को लागू करने के एक अच्छे, स्पष्ट और कुशल तरीके को कार्यान्वित करने के तरीके पर कुछ सलाह ढूंढ रहा हूं। दोनों सामान्य रूप में और विशेष रूप से किसी पाठ बॉक्स ग ",)

उत्तर

15

नेट System.ComponentModel नाम स्थान एक IEditableObject इंटरफेस के साथ आता है के लिए, आप भी INotifyPropertyChanging और INotifyPropertyChanged इस्तेमाल कर सकते हैं। MVC पैटर्न भी है कि अपने इंटरफेस मॉडल में परिवर्तन का जवाब यह होगा घटनाओं के माध्यम से इस प्रकार प्रभावी रूप से मेमेंटो पैटर्न अपडेट करने या आपका पाठ बॉक्स के मूल्य को बहाल।

आप इन? Here में एक देखो हुई है एक कैसे करने के लिए।

०१२३५१६४१०६१ है

टेक्स्टबॉक्स OnTextChanged की स्थिति को स्टोर करने के लिए एक सरल और तेज़ संस्करण होगा। प्रत्येक पूर्ववत एक ऐरे में अंतिम घटना वापस करेगा। सी # स्टैक प्रकार यहां आसान होगा। एक बार जब आप इंटरफ़ेस से बाहर हों या Apply के बाद आप राज्य को साफ़ कर सकें। (यह उस पर एक भी पाठ बॉक्स के साथ एक जीत फार्म के पीछे कोड है)

public partial class Form1 : Form 
{ 
    Stack<Func<object>> undoStack = new Stack<Func<object>>(); 
    public Form1() 
    { 
     InitializeComponent(); 
    } 
    private void textBox_KeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.KeyCode == Keys.U && Control.ModifierKeys == Keys.Control && undoStack.Count > 0) 
      undoStack.Pop()();    
    } 
    private void textBox_KeyPress(object sender, KeyPressEventArgs e) 
    {    
     if (e.KeyChar != 'u' || Control.ModifierKeys != Keys.Control) 
     { 
      var textBox = (TextBox)sender; 
      undoStack.Push(textBox.Text(textBox.Text)); 
     } 
    } 
} 
public static class Extensions 
{ 
    public static Func<TextBox> Text(this TextBox textBox, string text) 
    {    
     return() => { textBox.Text = text; return textBox; }; 
    } 
} 

अन्य इनपुट प्रकार के लिए एक विस्तार विधि को लागू करने undoStack द्वारा:

+0

हां, तो आप तो एक पाठ बॉक्स के विस्तारित रूप का होगा? इंटरफ़ेस को कार्यान्वित करना? – Svish

+0

पूर्ववत के कितने स्तर आपको एन स्तर या 1 की आवश्यकता होगी? पूर्ववत व्यवहार किसी ऑब्जेक्ट पर या पूरी तरह से टेक्स्टबॉक्स के डेटा पर होगा? –

3

यहाँ एक तरह से कम से कम कोड के साथ प्राप्त करने के लिए है क्रम में सभी यूआई क्रियाओं को पूर्ववत करते हुए, अपने पूरे यूआई की सेवा कर सकते हैं।

+1

स्ट्रिंग्स के ढेर के बजाय फ़ंक्शंस का ढेर क्यों उपयोग करें? – Jack

+2

@ जैक अंतिम वाक्य फिर से पढ़ें। इस कोड को विस्तारित किया जा सकता है ताकि आप किसी भी * नियंत्रण * किसी भी * नियंत्रण में, पूरे रूप में, विपरीत क्रम में पूर्ववत कर सकें। – Dan

0

मैं एक बदलाव की घटना सुनूंगा, और जब ऐसा होता है तो पिछले राज्य के diff को धक्का देता है और वर्तमान स्थिति एक स्टैक पर धक्का देती है। पूरे पाठ को संग्रहीत करने से भिन्नता बहुत छोटी होनी चाहिए। साथ ही, हो सकता है कि आप प्रत्येक संपादन पर स्टैक पर एक नया पूर्ववत राज्य धक्का नहीं देना चाहें ... उदाहरण के लिए, उपयोगकर्ता कर्सर की स्थिति को तब तक बदल देता है जब तक कि मैं कर्सर की स्थिति बदल नहीं लेता।

2

एक अच्छा समाधान यहां पाया जा सकता है:

Add Undo/Redo or Back/Forward Functionality to your Application

Undo/Redo Capable TextBox (winforms)

कोड VB.NET में है, लेकिन आप आसानी से बहुत प्रयास के बिना सी # करने के लिए इसे बदल सकते हैं। ऑनलाइन कन्वर्टर्स भी उपलब्ध हैं।

+0

धन्यवाद, इस सरल समाधान ने मुझे बहुत मदद की –

1

यह सबसे उपयोगी पृष्ठ है जो मैंने विषय पर पाया, अधिक सामान्य, पूर्ववत/फिर से स्टैक पर विभिन्न ऑब्जेक्ट प्रकारों के लिए उपयुक्त है।

Command Pattern

जब मैंने इसे लागू करने के लिए मिला है, मैं कैसे सरल और सुरुचिपूर्ण यह किया जा रहा समाप्त हो गया आश्चर्य हुआ। यह मेरे लिए एक जीत बनाता है।

1

सबसे तेज़ तरीका निरंतर निरंतर वस्तुओं के साथ है। किसी ऑब्जेक्ट में कभी भी बदलाव न करें, केवल नए ऑब्जेक्ट्स बनाएं जो पुराने संस्करण से थोड़ा बदल जाए। यह गर्म पथ पर केवल पेड़ के हिस्सों को क्लोन करके कुछ हद तक कुशलतापूर्वक किया जा सकता है।

मैं

[Fact] 
public void UndoStackSpec() 
{ 
    var stack = new UndoStack<A>(new A(10, null)); 

    stack.Current().B.Should().Be(null); 

    stack.Set(x => x.B, new B(20, null)); 

    stack.Current().B.Should().NotBe(null); 
    stack.Current().B.P.Should().Be(20); 

    stack.Undo(); 

    stack.Current().B.Should().Be(null); 

} 

private setters सभी गुण पर साथ ए और बी वर्ग के रूप में अर्थात् जहां immutable

class A : Immutable 
{ 
    public int P { get; private set; } 
    public B B { get; private set; } 
    public A(int p, B b) 
    { 
     P = p; 
     B = b; 
    } 
} 

class B : Immutable 
{ 
    public int P { get; private set; } 
    public C C { get; private set; } 
    public B(int p, C c) 
    { 
     P = p; 
     C = c; 
    } 
} 

class C : Immutable 
{ 
    public int P { get; private set; } 
    public C(int p) 
    { 
     P = p; 
    } 
} 

आप पूर्ण स्रोत मिल सकता है एक पूर्ववत् ढेर न्यूनतम कोड के साथ लिखा का एक उदाहरण है यहां https://gist.github.com/bradphelan/5395652

+0

क्या यह obfuscated संस्करण है? शायद आप सिंगल-लेटर वैरिएबल नामों की तुलना में थोड़ा अधिक वर्बोज़ के साथ उदाहरण प्रदान करने के लिए अपना उत्तर अपडेट कर सकते हैं? – Dan

+1

परिवर्तनीय नाम अप्रासंगिक हैं। उनके सेट के अलावा उनके पास कोई अर्थ नहीं है और फिर पूर्ववत कहा जाता है और यह दिखाया जाता है कि वे अनसेट हैं। कार्यान्वयन गिस्ट में है और यह आपको पूरा करने के लिए आवश्यक सभी स्रोत कोड देता है। – bradgonesurfing

+3

एकमात्र समय परिवर्तनीय नाम अप्रासंगिक हैं जब चर स्वयं अप्रासंगिक होते हैं, इस स्थिति में उन्हें पूरी तरह से हटा दिया जाना चाहिए। यदि चर किसी भी उद्देश्य को पूरा करते हैं, भले ही वह उद्देश्य मनमाना उदाहरण वर्ग तक सीमित है, तो उन्हें कोड द्वारा प्रस्तुत किए गए वास्तविक विचारों के पाठक की खपत को कम करने के लिए कुछ मूर्त रूप देने के लिए इस तरह से नामित किया जाना चाहिए। कारण उदाहरण कोड अक्सर उदाहरण शामिल है उदा। "क्लास कार" या "क्लास बैंक अकाउंट" इसलिए नहीं है क्योंकि ये चीजें महत्वपूर्ण हैं, लेकिन क्योंकि वे पाठक को अंतर्निहित अवधारणाओं को समझने में मदद करते हैं। – Dan

1

मुझे चयन को अपने मूल pos में भी रीसेट करने की आवश्यकता है पूर्ववत/redoing जब Iions। , देखो "वर्ग एक्सटेंशन" मेरी सिर्फ बुनियादी और अच्छी तरह से काम कर कोड के निचले भाग में, सिर्फ एक पाठ बॉक्स "textBox1" के साथ एक फार्म की कोशिश करने के लिए:

public partial class Form1 : Form 
{ 
    Stack<Func<object>> undoStack = new Stack<Func<object>>(); 
    Stack<Func<object>> redoStack = new Stack<Func<object>>(); 

    public Form1() 
    { 
     InitializeComponent(); 
     textBox1.KeyDown += TextBox1_KeyDown; 
    } 

    private void TextBox1_KeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.KeyCode == Keys.ControlKey && ModifierKeys == Keys.Control) { } 
     else if (e.KeyCode == Keys.U && ModifierKeys == Keys.Control) 
     { 
      if(undoStack.Count > 0) 
      { 
       StackPush(sender, redoStack); 
       undoStack.Pop()(); 
      } 
     } 
     else if (e.KeyCode == Keys.R && ModifierKeys == Keys.Control) 
     { 
      if(redoStack.Count > 0) 
      { 
       StackPush(sender, undoStack); 
       redoStack.Pop()(); 
      } 
     } 
     else 
     { 
      redoStack.Clear(); 
      StackPush(sender, undoStack); 
     } 
    } 

    private void StackPush(object sender, Stack<Func<object>> stack) 
    { 
     TextBox textBox = (TextBox)sender; 
     var tBT = textBox.Text(textBox.Text, textBox.SelectionStart); 
     stack.Push(tBT); 
    } 
} 

public static class Extensions 
{ 
    public static Func<TextBox> Text(this TextBox textBox, string text, int sel) 
    { 
     return() => 
     { 
      textBox.Text = text; 
      textBox.SelectionStart = sel; 
      return textBox; 
     }; 
    } 
} 
संबंधित मुद्दे