2009-02-02 17 views
99

मैंने एक कस्टम WPF उपयोगकर्ता नियंत्रण बनाया है जिसका उद्देश्य किसी तृतीय पक्ष द्वारा उपयोग किया जाना है। मेरे नियंत्रण में एक निजी सदस्य है जो डिस्पोजेबल है, और मैं यह सुनिश्चित करना चाहता हूं कि युक्त विंडो/एप्लिकेशन बंद होने के बाद इसकी निपटान विधि हमेशा कॉल की जाएगी। हालांकि, UserControl डिस्पोजेबल नहीं है। मैंने आईडीस्पोजेबल इंटरफ़ेस को कार्यान्वित करने और अनलोड किए गए ईवेंट की सदस्यता लेने का प्रयास किया लेकिन मेजबान एप्लिकेशन बंद होने पर न तो कॉल किया गया। यदि संभव हो, तो मैं एक विशिष्ट निपटान विधि को कॉल करने के लिए याद रखने के अपने नियंत्रण के उपभोक्ताओं पर भरोसा नहीं करना चाहता हूं।डब्ल्यूपीएफ उपयोगकर्ता नियंत्रण का निपटान

public partial class MyWpfControl : UserControl 
{ 
    SomeDisposableObject x; 

    // where does this code go? 
    void Somewhere() 
    { 
     if (x != null) 
     { 
      x.Dispose(); 
      x = null; 
     } 

    } 
} 

अब तक का एकमात्र समाधान डिस्पैचर के शट डाउनस्टार्ट ईवेंट की सदस्यता लेना है। क्या यह एक उचित दृष्टिकोण है?

this.Dispatcher.ShutdownStarted += Dispatcher_ShutdownStarted; 
+0

क्या उपयोगकर्ता नियंत्रण से उतार घटना के बारे में? – akjoshi

+2

@akjoshi: एमएसडीएन का कहना है कि: अनलोडेड घटना बिल्कुल नहीं उठाई जा सकती है।और यह एक से अधिक बार ट्रिगर भी हो सकता है, वह तब होता है जब उपयोगकर्ता विषय बदलता है। – Dudu

+0

जबकि आप अपने उपयोगकर्ता नियंत्रण पर आईडीस्पोजेबल इंटरफेस को कार्यान्वित कर सकते हैं, वहां कोई गारंटी नहीं है कि आपकी तीसरी पार्टी आपके निपटान पैटर्न कार्यान्वयन की निपटान विधि को कॉल करेगी। यदि आप मूल संसाधनों (जैसे एक फ़ाइल स्ट्रीम) पर हैं, तो आपको अंतिमकर्ता का उपयोग करने पर विचार करना चाहिए। – Philippe

उत्तर

51

दिलचस्प ब्लॉग यहाँ पोस्ट:

http://geekswithblogs.net/cskardon/archive/2008/06/23/dispose-of-a-wpf-usercontrol-ish.aspx

यह Dispatcher_ShutDownStarted की सदस्यता का उल्लेख अपने संसाधनों के निपटान के लिए।

+0

अच्छी तरह से मैं उम्मीद कर रहा था कि इससे क्लीनर तरीका होगा, लेकिन ऐसा लगता है कि यह करने के लिए यह सबसे अच्छा है। –

+28

लेकिन ऐप से पहले उपयोगकर्ता नियंत्रण मर जाता है तो क्या होगा? डिस्पैचर केवल ऐप करता है जब ऐप करता है, है ना? –

+0

पूरी तरह से सहमत हैं, लेकिन मुझे समझ में नहीं आता कि ओपी को नियंत्रणों का निपटान करने की आवश्यकता क्यों है। लगता है ... विषम –

-3

एक उपयोगकर्ता नियंत्रण में एक विनाशक है, आप इसका उपयोग क्यों नहीं करते?

~MyWpfControl() 
    { 
     // Dispose of any Disposable items here 
    } 
+0

यह काम नहीं प्रतीत होता है। मैंने बस उस दृष्टिकोण की कोशिश की और इसे कभी नहीं बुलाया जाता है। – JasonD

+8

यह एक विनाशक नहीं है, यह एक अंतिम रूप है। आप हमेशा एक जोड़ी को कार्यान्वित करते हैं और एक जोड़ी के रूप में निपटान करते हैं अन्यथा आप लीक को जोखिम देते हैं। –

+1

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

10

आपको विनाशक का उपयोग करके सावधान रहना होगा। इसे जीसी फाइनलाइज़र थ्रेड पर बुलाया जाएगा। कुछ मामलों में संसाधन जो आपके फ्रीिंग को एक अलग थ्रेड पर रिलीज़ नहीं किया जा सकता है, जिस पर वे बनाए गए थे।

+1

इस चेतावनी के लिए धन्यवाद। यह मेरा मामला बिल्कुल था! _ आवेदन: devenv.exe फ्रेमवर्क संस्करण: v4.0.30319 विवरण: प्रक्रिया को एक अनचाहे अपवाद के कारण समाप्त कर दिया गया था। अपवाद जानकारी: System.InvalidOperationException ढेर: MyControl.Finalize पर() _ मेरी समाधान ShutdownStarted – itsho

4

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

मुझे लगा कि उपयोगकर्ता नियंत्रण की लोड की गई घटना में, मैं अपने माता-पिता विंडो बंद करने की विधि को अपने माता-पिता विन्डो क्लोजिंग विधि को जोड़ सकता हूं। इस तरह मेरा उपयोगकर्ता नियंत्रण तब पता हो सकता है जब अभिभावक विंडो बंद हो रही है और तदनुसार कार्य करें!

26

Dispatcher.ShutdownStarted ईवेंट केवल एप्लिकेशन के अंत में निकाल दिया जाता है। जब नियंत्रण से बाहर हो जाता है तो बस निपटान तर्क को कॉल करना उचित होता है। विशेष रूप से यह संसाधनों को मुक्त करता है जब एप्लिकेशन रनटाइम के दौरान कई बार नियंत्रण का उपयोग किया जाता है। तो ioWint का समाधान बेहतर है।

public MyWpfControl() 
{ 
    InitializeComponent(); 
    Loaded += (s, e) => { // only at this point the control is ready 
     Window.GetWindow(this) // get the parent window 
       .Closing += (s1, e1) => Somewhere(); //disposing logic here 
    }; 
} 
+0

में finalizer से कोड स्थानांतरित करने के लिए एक Windows स्टोर ऐप में था, GetWindow() मौजूद नहीं है। –

+0

ब्रावो, सबसे बड़ा जवाब। – MDDDC

+4

Cœur: एक विंडोज स्टोर ऐप में, आप WPF –

8

मैं निम्नलिखित अन्तरक्रियाशीलता व्यवहार का उपयोग WPF UserControls के लिए एक उतराई घटना प्रदान करने के लिए: यहाँ कोड है। आप UserControls XAML में व्यवहार शामिल कर सकते हैं। तो आप प्रत्येक उपयोगकर्ता नियंत्रण में तर्क डाले बिना कार्यक्षमता प्राप्त कर सकते हैं।

XAML घोषणा:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 

<i:Interaction.Behaviors> 
    <behaviors:UserControlSupportsUnloadingEventBehavior UserControlClosing="UserControlClosingHandler" /> 
</i:Interaction.Behaviors> 

codebehind हैंडलर:

private void UserControlClosingHandler(object sender, EventArgs e) 
{ 
    // to unloading stuff here 
} 

व्यवहार कोड:

/// <summary> 
/// This behavior raises an event when the containing window of a <see cref="UserControl"/> is closing. 
/// </summary> 
public class UserControlSupportsUnloadingEventBehavior : System.Windows.Interactivity.Behavior<UserControl> 
{ 
    protected override void OnAttached() 
    { 
     AssociatedObject.Loaded += UserControlLoadedHandler; 
    } 

    protected override void OnDetaching() 
    { 
     AssociatedObject.Loaded -= UserControlLoadedHandler; 
     var window = Window.GetWindow(AssociatedObject); 
     if (window != null) 
      window.Closing -= WindowClosingHandler; 
    } 

    /// <summary> 
    /// Registers to the containing windows Closing event when the UserControl is loaded. 
    /// </summary> 
    private void UserControlLoadedHandler(object sender, RoutedEventArgs e) 
    { 
     var window = Window.GetWindow(AssociatedObject); 
     if (window == null) 
      throw new Exception(
       "The UserControl {0} is not contained within a Window. The UserControlSupportsUnloadingEventBehavior cannot be used." 
        .FormatWith(AssociatedObject.GetType().Name)); 

     window.Closing += WindowClosingHandler; 
    } 

    /// <summary> 
    /// The containing window is closing, raise the UserControlClosing event. 
    /// </summary> 
    private void WindowClosingHandler(object sender, CancelEventArgs e) 
    { 
     OnUserControlClosing(); 
    } 

    /// <summary> 
    /// This event will be raised when the containing window of the associated <see cref="UserControl"/> is closing. 
    /// </summary> 
    public event EventHandler UserControlClosing; 

    protected virtual void OnUserControlClosing() 
    { 
     var handler = UserControlClosing; 
     if (handler != null) 
      handler(this, EventArgs.Empty); 
    } 
} 
+3

मैं यहां एक झंडा उठाऊंगा ... क्या होगा अगर विंडो बंद होने से कुछ और रद्द हो जाए (शायद आपके नियंत्रण के बाद सदस्यता लें तो 'e.Cancel' अभी भी झूठा है जब यह आपके 'विंडोक्लोसिंग हैंडलर' प्रतिनिधि तक पहुंचता है)? आपका नियंत्रण "अनलोड" होगा और विंडो अभी भी खोली जाएगी। मैं निश्चित रूप से 'बंद' ईवेंट पर ऐसा करूँगा, न कि 'समापन' पर। – Jcl

+0

ओह हाँ, मैं इस बिंदु से चूक गया। धन्यवाद। –

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