WPF उपयोगकर्ता नियंत्रणों का निपटान


119

मैंने एक कस्टम 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;

उपयोगकर्ता नियंत्रण के अनलोड लोड घटना के बारे में क्या?
अक्जोशी

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

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

जवाबों:


57

रोचक ब्लॉग पोस्ट यहाँ:

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

इसमें Dispatcher.ShutdownStarted की सदस्यता लेने का उल्लेख है जो आपके संसाधनों का निपटान करता है।


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

35
लेकिन अगर ऐप के मरने से पहले UserControl मर जाए तो क्या होगा? डिस्पैचर केवल तभी बंद हो जाएगा जब ऐप सही करता है?
रॉबर्ट जेप्पेसेन

15
क्योंकि कई नियंत्रण COM घटकों या अन्य अप्रबंधित संसाधनों का पुन: उपयोग करते हैं जिन्हें अनिश्चित काल के आसपास लटकाए जाने के दृश्य के साथ कोडित नहीं किया गया था, या एक थ्रेड पूल थ्रेड पर अंतिम रूप दिया गया था, और नियतांक से निपटने की आवश्यकता होती है।
न्यूट्रिनो

1
विंडोज स्टोर ऐप में, शट डाउनस्टार्ट मौजूद नहीं है।
--œ जूल 15'13

7
या आपको घटना संचालकों को
हटाने की

40

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
     };
}

Windows स्टोर ऐप में, GetWindow () मौजूद नहीं है।
करूर

ब्रावो, सबसे बड़ा जवाब।
निक 16

8
Cur: विंडोज़ स्टोर ऐप में, आप WPF
एलन बलजू

3
क्या होगा अगर वहाँ अधिक खिड़कियां शामिल हों और मुख्य कभी बंद न हो? या आपके नियंत्रण को पृष्ठ में होस्ट किया जाता है जो कई बार लोड / अनलोड हो जाते हैं? देखें: stackoverflow.com/a/14074116/1345207
L.Trabacchin

1
खिड़की बहुत बार बंद नहीं हो सकती है। यदि नियंत्रण किसी सूची आइटम का हिस्सा है, तो कई को तब तक बनाया / नष्ट किया जाएगा जब तक कि इसकी मूल विंडो बंद न हो जाए।
LOST

15

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


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

10

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

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);
    }
}

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

6

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

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


0

मुझे लगता है कि अनलोड को सभी कहा जाता है, लेकिन 4.7 में मौजूद है। लेकिन, यदि आप .Net के पुराने संस्करणों के साथ खेल रहे हैं, तो अपनी लोडिंग विधि में ऐसा करने का प्रयास करें:

e.Handled = true;

मुझे नहीं लगता कि पुराने संस्करणों को तब तक अनलोड किया जाएगा जब तक लोडिंग को संभाला नहीं जाता। सिर्फ इसलिए पोस्ट कर रहा हूं क्योंकि मैं दूसरों को अभी भी यह प्रश्न पूछ रहा हूं, और इस प्रस्ताव को समाधान के रूप में नहीं देखा है। मैं केवल एक वर्ष में कुछ बार .Net को स्पर्श करता हूं, और कुछ साल पहले इसमें भाग गया। लेकिन, मुझे आश्चर्य है कि जब तक लोडिंग समाप्त न हो जाए, इसे अनलोड के रूप में सरल कहा जाता है। ऐसा लगता है कि यह मेरे लिए काम करता है, लेकिन फिर से नए .Net में यह हमेशा लगता है कि लोडिंग को कॉल करना है भले ही लोडिंग के रूप में चिह्नित नहीं किया गया हो।


-3

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

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

यह काम नहीं लगता है। मैंने सिर्फ उस दृष्टिकोण की कोशिश की और यह कभी नहीं कहा जाता है।
जेसन

9
यह एक विध्वंसक नहीं है, यह एक अंतिम रूप है। आप हमेशा एक फाइनल लागू करते हैं और एक जोड़ी के रूप में निपटान करते हैं अन्यथा आप लीक का जोखिम उठाते हैं।
माइक पोस्ट

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

2
joeduffyblog.com/2005/04/08/… फाइनल और डिस्पोज का सबसे अच्छा स्पष्टीकरण है जो मुझे मिला है। यह वास्तव में पढ़ने लायक है।
dss539
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.