2009-07-07 7 views
18

मैं एमवीवीएम का उपयोग कर किसी ऑब्जेक्ट को संपादित करने के रद्द को कैसे कार्यान्वित कर सकता हूं।एमवीवीएम का उपयोग कर किसी ऑब्जेक्ट में संपादन को कैसे रद्द करें?

उदाहरण के लिए: मेरे पास ग्राहकों की एक सूची है। मैं एक ग्राहक को "एडिट" बटन पर क्लिक करता हूं, एक संवाद विंडो (DataContext ग्राहक व्यूमोडेल से जुड़ा हुआ है) खुलता है और मैं ग्राहक के फ़ील्ड को संपादित करना शुरू करता हूं। और फिर मैं संपादन रद्द करने का निर्णय लेता हूं, लेकिन ग्राहक के क्षेत्र पहले से ही बदल दिए गए हैं, तो मैं एमवीवीएम में अपने पिछले राज्य में ग्राहक कैसे वापस कर सकता हूं?

उत्तर

11

IEditableObject इंटरफ़ेस देखें। आपके Customer वर्ग को इसे कार्यान्वित करना चाहिए, और आपके आदेश BeginEdit/CancelEdit/EndEdit निष्पादित कर सकते हैं।

+0

IEditableObject आपकी ऑब्जेक्ट्स के लिए बहुत अधिक ओवरहेड बनाता है, खासकर यदि आपकी मॉडल ऑब्जेक्ट्स क्लास हैं और स्ट्रक्चर नहीं है, तो आपको इसका समर्थन करने के लिए अपने मॉडल ऑब्जेक्ट्स को फिर से लिखना होगा। – Agies

+6

@ एजीज: डाउनवोट क्यों? चाहे IEDitableObject एक "बहुत अधिक ओवरहेड" है या नहीं, पूरी तरह से आपके आधारभूत संरचना पर निर्भर करता है या आप इसे कैसे कार्यान्वित करना चाहते हैं। यह सिर्फ एक इंटरफेस है कि डब्ल्यूपीएफ समझता है। आप इसे कैसे लागू करते हैं आप पर निर्भर है। –

+0

+1, हाँ, मैं इसे IEDitableObject के साथ कार्यान्वित करना चाहता हूं, लेकिन मेरे पास एक ViewModelBase है जो एक संपत्ति का खुलासा करता है टाइप प्रकार टीएमओडेल और मैं सीधे खुला मॉडल के गुणों पर दृश्य को बांधता हूं। अब मैं अभी भी 'संपादन रद्द करें' का उपयोग कैसे कर सकता हूं, अब भी, कि आप मेरे परिदृश्य को जानते हैं, कहें कि मेरा टीएमडेल एक पता इकाई है। व्यू मोड में यह सिर्फ फुलएड्रेस लाइन से जुड़ा हुआ है और एड्रेसडाटा टेम्पलेट (जीमैप्स के लिए लिंक बनाना) का उपयोग करता है, लेकिन मैं चाहता हूं कि जब उपयोगकर्ता एड्रेस व्यू पर एडिट बटन पर क्लिक करता है, तो उसे एक चाइल्डविंडो (एसएल, या डब्ल्यूपीएफ में जो भी विंडो खोलनी चाहिए) जारी रखने के लिए ... – Shimmy

3

this article में, राउल बस डीबी से ऑब्जेक्ट को पुनः लोड करें। मुझे लगता है कि समाधान केंट प्रस्तावों की तुलना में यह कम परेशानी है।

internal void Cancel(CustomerWorkspaceViewModel cvm) 
    { 
     Mainardi.Model.ObjectMapping.Individual dc = cvm.DataContext 
           as Mainardi.Model.ObjectMapping.Individual; 

     int index = 0; 

     if (dc.ContactID > 0 && dc.CustomerID > 0) 
     { 
      index = _customerCollectionViewModel.List.IndexOf(dc); 
      _customerCollectionViewModel.List[index] = 
            _customerBAL.GetCustomerById(dc.CustomerID); 
     } 

     Collection.Remove(cvm); 
    } 
+0

मुझे लगता है कि डीबी से पुनः लोड करना एमआर बूगार्ट्स सुझाव के आईईडीएबल ओब्जेक्ट के दायित्वों को पूरा करने का एक तरीका है, जरूरी नहीं कि इसका विकल्प भी हो। – Guge

0

आप भी अपनी ViewModel आंतरिक क्षेत्रों के लिए मॉडल के राज्य कॉपी, और फिर इन बेनकाब कर सकता है और उसके बाद ही, मॉडल पर उन्हें सेट यदि उपयोगकर्ता परिवर्तन करता है।

समस्या हो सकती है, अगर वैधता इकाई को अद्यतन करने पर निर्भर करती है तो ऑन-द-फ्लाई सत्यापन अधिक परेशानी होगी - यदि यह एक आवश्यकता है तो आप काम करने के लिए मॉडल का एक क्लोन बना सकते हैं और उसके बाद क्लोन विलय कर सकते हैं वास्तविक इकाई जब इसे सहेजा जाता है।

4

यदि आपका ऑब्जेक्ट पहले से ही क्रमबद्ध है, तो एक सुपर आसान तरीका, जैसे कि आप डब्ल्यूसीएफ का उपयोग कर रहे हैं। आप अपनी मूल वस्तु को आंतरिक क्षेत्र में क्रमबद्ध कर सकते हैं। यदि, आपकी ऑब्जेक्ट serializable नहीं है, तो कोड की एक पंक्ति के साथ अपनी ऑब्जेक्ट की एक प्रति बनाने के लिए बस AutoMapper का उपयोग करें।

Order backup = Mapper.Map<Order, Order>(order); 

जब आप अपना CancelCommand संभालते हैं, तो बस ऑटोमैपर को रिवर्स में कॉल करें। चूंकि आपकी संपत्तियों में पहले से ही एक बदलाव अधिसूचना है, सबकुछ बस काम करता है। यदि आप की जरूरत है और अतिरिक्त कोड लिखना चाहते हैं, तो यह संभव है कि आप इन तकनीकों को IEDitableObject के साथ जोड़ सकें।

+0

ऑटोमैपर के लिए नीचे की ओर यह है कि यह केवल उस स्थिति को कैप्चर करता है जो गुणों के माध्यम से दिखाई देता है। तो अन्य समाधानों की तरह यह मानते हैं कि प्रत्येक संपादन योग्य वर्ग के लिए राज्य के प्रत्येक टुकड़े को पढ़ने/लिखने के गुणों के माध्यम से उजागर किया जाता है, यह उन परिस्थितियों के लिए ठीक काम करना चाहिए जो डीटीओ या अन्य समान एनीमिक वस्तुओं का उपयोग करते हैं, लेकिन ऐसे मामले में जहां वे समृद्ध डोमेन ऑब्जेक्ट्स हैं बिल्कुल कोई संपत्ति नहीं हो। बाइनरी क्रमबद्धता और NetDataContractSerialization में यह समस्या नहीं है क्योंकि वे फ़ील्ड के साथ काम करते हैं। बीटीडब्लू, यह मुश्किल है जब घटनाएं और प्रतिनिधि खेलते हैं। – jpierson

0

आप UpdateSourceTrigger = Explicit के साथ बाध्यकारी का उपयोग कर सकते हैं। Here आप अधिक जानकारी प्राप्त कर सकते हैं कि इसे कैसे कार्यान्वित किया जा सकता है।

+2

अच्छा उत्तर अधिक विशिष्ट होना चाहिए, सर्वोत्तम अगर इसमें कोड उदाहरण शामिल है। –

+1

हालांकि इस उत्तर में विस्तार की कमी है, मुझे लगता है कि यह सबसे साफ समाधान है। UpdateSourceTrigger = स्पष्ट रूप से स्पष्ट किया जाता है कि टेर्क्री क्या करने की कोशिश कर रहा है। अन्य समाधान, जबकि वे काम कर सकते हैं, वास्तव में सिर्फ हैक्स हैं। – user2780436

+0

यदि आपका सत्यापन ट्रैकिंग स्रोत परिवर्तनों पर निर्भर करता है (उदाहरण के लिए 'IDataErrorInfo' के माध्यम से) तो आपको स्रोत अपडेट नहीं होने तक सत्यापन प्राप्त नहीं होगा (यदि बिलकुल नहीं, मुझे यकीन नहीं है), जिस बिंदु पर आप अभी भी बनना चाहते हैं सभी परिवर्तनों को वापस रोल करने में सक्षम है लेकिन आपका मॉडल पहले ही अपडेट हो चुका है। – Dan

0

पर Камен Великов's answer आधार पर:

आप अपने बाइंडिंग के रूप में अपने दृश्य (XAML) में

<TextBox Name="yourTextBox" Text="{BindingPath=YourBinding, UpdateSourceTrigger=Explicit}" />

को परिभाषित करते हुए मैन्युअल रूप से अद्यतन किया जाना चिह्नित कर सकते हैं। फिर, आपको

yourTextBox.GetBindingExpression(TextBox.TextProperty).UpdateSource();
पर क्लिक करके व्यूमोडेल में अपने यूआई से किए गए परिवर्तनों को लिखना होगा।

कृपया ध्यान दें, अगर किसी अन्य चीज़ से ट्रिगर किए गए बाध्यकारी स्रोत में अपडेट किया गया है, तो वे अभी भी यूआई में सीधे दिखाए जाते हैं।

1

मुझे यह समस्या भी थी। मैंने इसे "द ममेन्टो पैटर्न डिजाइन" का उपयोग करके हल किया। इस पैटर्न के साथ आप अपने मूल ऑब्जेक्ट की एक प्रति और selectedIndexChange (नियंत्रण के) या रद्द बटन में आसानी से सहेज सकते हैं, आप अपने ऑब्जेक्ट के पहले संस्करण को आसान बना सकते हैं।

हम गुणों के साथ एक वर्ग उपयोगकर्ता है, तो पासवर्ड उपयोगकर्ता नाम और NombrePersona हम तरीकों CreateMemento और SetMemento जोड़ने की जरूरत:

इस पद्धति के उपयोग का एक उदाहरण How is the Memento Pattern implemented in C#4?

कोड का एक उदाहरण पर उपलब्ध है

:
public class Usuario : INotifyPropertyChanged 
{ 
    #region "Implementación InotifyPropertyChanged" 

    internal void RaisePropertyChanged(string prop) 
    { 
     if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } 
    } 
    public event PropertyChangedEventHandler PropertyChanged; 

    #endregion 

    private String _UserName = "Capture su UserName"; 

    public String UserName 
    { 
     get { return _UserName; } 
     set { _UserName = value; RaisePropertyChanged("UserName"); } 
    } 

    private String _Password = "Capture su contraseña"; 

    public String Password 
    { 
     get { return _Password; } 
     set { _Password = value; RaisePropertyChanged("Password"); } 
    } 

    private String _NombrePersona = "Capture su nombre"; 

    public String NombrePersona 
    { 
     get { return _NombrePersona; } 
     set { _NombrePersona = value; RaisePropertyChanged("NombrePersona"); } 
    } 

    // Creates memento 
    public Memento CreateMemento() 
    { 
     return (new Memento(this)); 
    } 

    // Restores original state 
    public void SetMemento(Memento memento) 
    { 
     this.UserName memento.State.UserName ; 
     this.Password = memento.State.Password ; 
     this.NombrePersona = memento.State.NombrePersona; 
    } 

फिर, हम एक वर्ग मेमेंटो है कि इस तरह हमारे वस्तु की "कॉपी" में शामिल होंगे की जरूरत है

/// <summary> 
/// The 'Caretaker' class 
/// </summary> 
class Caretaker 
{ 
    private Memento _memento; 

    // Gets or sets memento 
    public Memento Memento 
    { 
     set { _memento = value; } 
     get { return _memento; } 
    } 

} 

तब के लिए इस पैटर्न लागू हम Caretaker वर्ग का एक उदाहरण

Caretaker creadorMemento = new Caretaker(); 

बना सकते हैं और बनाने के लिए:

और हम एक वर्ग है कि पैदा करते हैं और हमारे स्मृति चिन्ह वस्तु शामिल होगा की जरूरत है जब हमारे द्वारा चयनित उपयोगकर्ता को प्रारंभ करने के बाद selectedIndexChange में उदाहरण के लिए चुना गया था, तो हमारी स्मृति वस्तु ऑब्जेक्ट का चयन किया गया था, उदाहरण के लिए मैं RaisPropertyChanged ईवेंट के लिए विधि का उपयोग करता हूं:

internal void RaisePropertyChanged(string prop) 
    { 
     if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(prop)); } 
     if (prop == "RowIndexSelected") // This is my property assigned to SelectedIndex property of my DataGrid 
     { 
      if ((this.UserSelected != null) && (creadorMemento .Memento != null)) 
      { 
       this.UserSelected.SetMemento(creadorMemento .Memento); 
      } 
     } 
     if (prop == "UserSelected") // Property UserSelected changed and if not is null we create the Memento Object 
     { 
      if (this.UserSelected != null) 
       creadorMemento .Memento = new Memento(this.UserSelected); 
     } 
    } 

इस के लिए एक व्याख्या है, जब selectedIndexChanged परिवर्तन मूल्य हम जाँच अगर UserSelected और our memento object अशक्त नहीं हैं इसका मतलब है कि संपादन मोड में हमारी वास्तविक मद तो बदल गया है हम विधि SetMemento के साथ हमारे वस्तु पुनर्स्थापित करने के लिए है। और यदि हमारे UserSelected संपत्ति में परिवर्तन और शून्य नहीं है तो हम "हमारे Memento ऑब्जेक्ट बनाएं" का उपयोग करेंगे जब हम संपादन रद्द कर देंगे।

खत्म के लिए, हम हर विधि है कि हम संस्करण को रद्द करने की जरूरत है SetMemento विधि का उपयोग किया है, और हम इस this.creadorMemento = null तरह अशक्त हमारे स्मृति चिन्ह वस्तु निर्धारित कर सकते हैं जब संपादित SaveCommand में तरह प्रतिबद्ध है।

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

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