Καλώς ορίσατε στο dotNETZone.gr - Σύνδεση | Εγγραφή | Βοήθεια
σε

 

Αρχική σελίδα Ιστολόγια Συζητήσεις Εκθέσεις Φωτογραφιών Αρχειοθήκες

Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

Îåêßíçóå áðü ôï ìÝëïò pontifikas. Τελευταία δημοσίευση από το μέλος George Parissis στις 04-11-2011, 02:12. Υπάρχουν 12 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  02-11-2011, 19:01 68005

    Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Έχω το ακόλουθο πρόβλημα.

    Στην εφαρμογή μου έχω Φόρμες, αλλά και κλάσεις που κάνουν Facade κάποιες άλλες φόρμες που δεν ανήκουν στην εφαρμογή μου.
    Εχω μια MainForm η οποία είναι MDI Control και ότι φόρμα ανοίγω θέλω να την έχω σαν MDI child. 
    Επίσης, έχω ένα Δέντρο σε ένα DockPanel της DevExpress όπου αναφέρεται κάθε φόρμα που αυτή τη στιγμή είναι ανοικτή.

    Για να πραγματοποιήσω το παραπάνω σενάριο έχω φτοιάξει έναν provider που κρατάει όλες τις ανοικτές φόρμες σε ενα collection
    και επιστρέφει Singleton Instances των φορμών αυτών. Η συνάρτηση που επιστρέφει τα instances είναι:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
     
     /// <summary>
            /// Checks if already exists an opened form of the specified type in the 
            /// collection of opened forms. If not creates and registers one.
            /// </summary>
            /// <typeparam name="T"> The type of Form to search for or create.</typeparam>
            /// <param name="args"> Additional Form contstruction parameters. The order must
            /// be the same with the order of appearance in each form's constructor.</param>
            /// <returns> A singleton instance of a form of the requested type. </returns>
            public static T GetFormInstance<T>(params object[] args) where T:IMdiChildForm
            {
                // If the form is not registered.
                if (!m_openedFormsCollection.ContainsKey( typeof(T) ))
                {
    
                    // Create it.
                    IMdiChildForm nForm = (IMdiChildForm)Activator.CreateInstance( typeof(T), args );
                    
                    nForm.MdiParent = GmdMainForm.SingletonInstance;
    
                    // Register it.
                    m_openedFormsCollection.Add( nForm.GetType(), nForm );
                    
                    if (MdiChildFormRegistered != null)
                    {
                        MdiChildFormRegistered( nForm );
                    }
                    
                    // If the form is the first to open, or it opens in maximized environment
                    // then it is also Maximized.
                    nForm.WindowState = m_openedFormsCollection.Count == 1 ||
                        GmdMainForm.SingletonInstance.MdiChildren.Where( w => w.WindowState == FormWindowState.Maximized ).
                            Count() > 0
                            ? FormWindowState.Maximized
                            : FormWindowState.Normal;
    
                    // Set the closed event to finalize the form instance.
                    nForm.OnMdiChildFormClosed += Form_FormClosed;
                }
    
                T result = (T)m_openedFormsCollection[typeof(T)];
                
                return result;
            }

    Τι IMdiChildForm είναι ένα interface που το υλοποιούν τόσο οι φόρμες μου όσο και τα Facades. Ο λόγος που το εισήγαγα είναι ακριβώς το ότι έχω κλάσεις 
    facdes, αλλιώς απλά θα έβαζα Form.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
     
    /// <summary>
        /// An interface used to expose necessery Properties of Forms and Form facades and
        /// facilitate the access to all form related objects of this program.
        /// </summary>
        public interface IMdiChildForm
        {         
            /// <summary>
            /// Exposes the OnFormClose event of an MdiForm.
            /// </summary>
            event OpenedFormsProvider.OnMdiChildFormClosed OnMdiChildFormClosed;
            
            /// <summary>
            /// Exposes the MdiParent of an MdiForm.
            /// </summary>
            Form MdiParent { get; set; }
    
            /// <summary>
            /// Exposes the Window state of an MdiForm.
            /// </summary>
            FormWindowState WindowState { get; set; }
    
            /// <summary>
            /// Exposes the Window Title of an MdiForm.
            /// </summary>
            string Text { get; }
           
            IntPtr Handle { get; }
    
            /// <summary>
            /// Exposes the function that brings an MdiForm to the Front of the visibility
            /// Z-Buffer.
            /// </summary>
            void BringToFront();
    
            void ShowMdiForm();
        }

    Επιπλέον, για να μην επαναλαμβάνω τον ίδιο κώδικα έχω και μια Extension Function για να ανοίγω τις φόρμες:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    public static void ShowMdiChildForm(this IMdiChildForm referencedForm)
            {
                //(referencedForm as Form).Show();
                referencedForm.ShowMdiForm();
                
                // Each time a form is Shown, it is brought to the front of the Z-buffer.
                referencedForm.BringToFront();
    
                // If a form remains minimized after the BringToFront event, it means that
                // the collection of minimized forms is visible, accesible by the mouse and 
                // thus the global state of forms in the MDI container is NOT maximized. We 
                // assume that the user normalized the front form, and to maintain the Normal
                // state as the global one, we bring the window at Normal state.
                if (referencedForm.WindowState == FormWindowState.Minimized)
                {
                    referencedForm.WindowState = FormWindowState.Normal;
                }
            }


    Το παραπάνω σενάριο δουλεύει κανονικά εκτός από μια περίπτωση. Υπάρχη μια φόρμα που αφού την ανοίξω, 
    μόλις πάω να ανοίξω (το implementation της κλάσης για την συνάρτηση στην γραμμή 4 του 3ου snippet) μετά μια άλλη, τρώω 
    OutOfMemory Exception και μου λέει το σύστημα ότι δεν μπόρεσε να φτοιάξει handle για την φόρμα που 
    πάω να ανοίξω. Αυτό το έχω παρατηρήσει ΜΟΝΟ μετά από αυτή την φόρμα. Όλοι οι άλλοι συνδυασμοί δουλεύουν κανονικά.
    To implementation της ShowMdiForm δεν είναι τίποτα άλλο από την Show() της εκάστοτε φόρμας.

    Ψάχνοντας να βρώ τι παίζει παρατήρησα το εξής:
    Στην γραμμή 16 του πρώτου snippet, μόλις δημιουργείται η φόρμα παίρνει ένα Handle.
    Στην γραμμή 18 τώρα, μόλις αναθέσω το MDI parent, αυτός ο Handler χάνεται! 

    Αν βάλω Break Point εκεί:
    α) Στις περιπτώσεις που δεν έχω πρόβλημα, παρατηρώ ότι απλά αλλάζει, και ούτε γάτα ούτε ζημιά.
    β) Στην περίπτωση που η φόρμα είναι μετά από αυτήν που αναφέρω, τότε προπαθώντας από το watch (με το mouse) να δώ τον Handle, βλέπω 
    ότι το property ρίχνει OutOfMemory Exception.
    - Αν πατήσω F5 τρώω και εγώ το Exception. 
    - Αν ξανακάνω watch τότε παρατηρώ ότι ο Handle πήρε τιμή και αν πατήσω F5 δουλεύει κανονικά.

    Είναι σαν να γίνεται lazy ανάθεση του Handle από το  MDIParent. Δοκίμασα να βάλω ένα "τζούφιο" while loop στην γραμμη 17, με συνθήκη Handle!=null, 
    και παραδόξως δεν παίρνω πια exception αλλά οι φόρμες μου ανοίγουν σε WindowState=Normal αντί για το τρέχω του MDI container.

    Όσο για την "κακιά" φόρμα, δεν είναι Facade και η μόνη ιδιαιτερότητα που έχει είναι ότι δεν καλείται από την Main Form, και ότι χρησιμοποιεί ένα αντικείμενο το οποίο έχει φτοιαχτεί από 
    άλλο thread (BackGround worker).

    Έχει κανείς καμοιά ιδέα? 
    Ευχαριστώ.


  •  02-11-2011, 20:00 68007 σε απάντηση της 68005

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Αυτό το κάτι που δημιουργείς σε άλλο Thread το κάνεις Bind στην προβληματική φόρμα; Μπορείς να δώσεις περισσότερες λεπτομέρειες;

    Πριν το κάνεις όμως αυτό για δοκίμασε να κάνεις σχόλιο τον κώδικα που χρησιμοποιεί αυτό το κάτι από το άλλο Thread και τρέξε την εφαρμογή να δεις αν θα συνεχίσει να σου χτυπάει.

    Νομίζω πως η αιτία του προβλήματος δεν είναι το handle απλά λαμβάνεις εκεί το λάθος μίας διαδικασίας που έχει ξεκινήσει νωρίτερα. Το τζούφιο Loop που έβαλες απλά έδωσε χρόνο στην φόρμα να περιμένει να τελειώσει το άλλο Thread για να εμφανιστεί. Κάνε όμως αυτή την μικρή δοκιμή και αν δεν σου χτυπήσει τότε θα πρέπει να δώσεις περισσότερες πληροφορίες για αυτό το αντικείμενο όπως επίσης το πως και με τι σκοπό χρησιμοποιείται στην φόρμα.

  •  02-11-2011, 20:35 68008 σε απάντηση της 68005

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Δε ξέρω αν θα βοηθούσε να καλέσεις την CreateHandle Method της φόρμας. Επίσης, ρίξε μια ματιά όσον αφορά στο πότε δημιουργείται το handle.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  03-11-2011, 10:39 68011 σε απάντηση της 68007

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Η create handle δούλεψε αλλά έκανε ότι κάνει το loop που είχα φτοιάξει. Και δεν μου φαίνεται για καλή λύση εκτός αν απελπιστώ.

    Πράγματι όμως αν δεν χρησιμοποιήσω το αντικείμενο που δημιουργείται στον Background Worker, τότε η φόρμα ανοίγει κανονικά.
    Το αντικείμενο αυτό είναι απλά ένα report data container. Ένα σύνολο από int properties και 2 collections που περιέχουν objects. 
    Τίποτα όμως από αυτά δεν κληρονομεί από την Control και δεν έχει να κάνει με gui.
    Μάλιστα δοκίμασα να κάνω τα πάντα Clone και πάλι πήρα το ίδιο αποτέλεσμα.

    Στην "κακή" φόρμα το μόνο που κάνω είναι display σε Grids (DevEx xtraGrid) τα property values και κάποια αριθμητικά δεδομένα που προκύπτουν από τα collections, 
    χωρίς όμως να κάνω edit κάτι.
    Για να το κάνω αυτό δημιουργώ ένα xml αρχείο το οποίο σώζω και ξαναφορτώνω σε ένα DataSet.
  •  03-11-2011, 11:35 68012 σε απάντηση της 68011

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Τότε το μόνο που μπορώ να σκεφτώ, για να μην χαλάσεις το generic, είναι να καλείς τον BackgroundWorker (BW) πριν καλέσεις τη φόρμα. Τη φόρμα να τη δημιουργείς όταν ο BW τελειώσει ό,τι κάνει και στη συνέχεια να δημιουργήσεις τη φόρμα περνώντας σαν παραμέτρους τα αποτελέσματα της επεξεργασίας του BW.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  03-11-2011, 11:56 68013 σε απάντηση της 68012

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Μα αυτό κάνω και τώρα. Παίρνω το αντικείμενο από τον BW, και κάνω create την φόρμα περνώντας το σαν παράμετρο.
  •  03-11-2011, 12:03 68014 σε απάντηση της 68013

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Δικό μου λάθος. Νόμιζα ότι καλείς τον BW στο Load event της φόρμας.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  03-11-2011, 16:16 68019 σε απάντηση της 68005

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Νομίζω ότι δεν είναι outofmemory exception αλλά δυστυχώς δεν έχω κάτι σίγουρο να σας προτείνω. Αυτό το link περιγράφει μία παρόμοια περίπτωση και στο More Information section αναφέρει ότι πρόκειται γιά null reference http://support.microsoft.com/kb/949458 . Δοκιμάστε αν θέλετε και IntelliTrace μήπως δείξει κάποιο exception.

     

  •  03-11-2011, 16:17 68020 σε απάντηση της 68013

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Μήπως το πρόβλημα υπάρχει στο binding; Ένα workaround θα ήταν να κάνεις instantiate το reporting control  (EDIT) τα grids έξω από τη φόρμα, να κάνεις το binding και στη συνέχεια να το περάσεις όλο μαζί σαν παράμετρο στον constructor της φόρμας. Long shot, αλλά για την ώρα δεν έχω σκεφτεί κάτι άλλο.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  03-11-2011, 16:28 68021 σε απάντηση της 68019

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Με βάση το link που έδωσε ο Libra Storm, θα έλεγα να δοκιμάσεις να περάσεις τα grids σαν παράμετρο όταν γίνει fire το HandleCreated event. Οτιδήποτε κληρονομεί από το Control class έχει αυτό το event.

    Ακόμα κι ένας άνθρωπος μπορεί ν' αλλάξει τον κόσμο. Μη θέλεις να κυβερνήσεις. Απλά δείξε το μονοπάτι κι ο κόσμος θ' ακολουθήσει!!
  •  03-11-2011, 20:01 68024 σε απάντηση της 68013

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Κάνε κάτι ακόμα σε παρακαλώ.

    Ενεργοποίησε τον κώδικα που χρησιμοποιείς αυτό το άλλο αντικείμενο από το BackgroundWorker αλλά κάνε σχόλιο τον κώδικα που αποδίδει τιμές στα controls της φόρμας. Δηλαδή να τρέξει το BackgroundWorker να εμφανιστεί η προβληματική φόρμα αλλά να μην έχουν τιμές τα controls της φόρμας.

    Αν σου περάσει αυτό τότε το πρόβλημά σου είναι cross thread exception. Το Grid της DevExpress έχει την δυνατότητα να μην κάνει catch τα cross thread exceptions και ίσως να το έχεις ενεργοποιήσει ή στο build που δουλεύεις να είναι ήδη ενεργοποιημένο οπότε μετά αναλαμβάνει το framework να σου βγάλει το handle error.

    Αν για δοκιμαστικούς λόγους δεν είχες τον BackgroundWorker αλλά έγραφες τον κώδικά σου σε ένα Thread τότε δεν θα είχες πρόβλημα.

    Το θέμα, εκεί που το βλέπω εγώ με τις λίγες πληροφορίες που έχω είναι cross thread exception. Πως πέρνεις το αντικείμενο από τον BackgroundWorker και το περνάς σαν παράμετρο στον Constructor? Με το report changed event ή με το Work completed event.?

    Κάτι έχεις αφήσει ανοικτό και τρέχει σε άλλο Thread. Για αυτό και το τζούφιο loop έπαιξε.

    Από την άλλη αυτό με το XML και dataset που κάνεις εκεί με μπέρδεψε λιγάκι, δεν έχω εμπειρία σε αυτού του είδους της διαδικασίες.

     

  •  04-11-2011, 00:01 68029 σε απάντηση της 68024

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Λοιπόν η λύση βρέθηκε. Δεν μπορώ να εξηγήσω γιατί δουλεύει αλλά τελικά μοιάζει να είναι συνδυασμός της λειτουργίας
    Grid της DevExpress, και το πως γίνεται το Handle creation στο .Net.

    Προσπαθώντας να καταλάβω γιατί όταν περνάω κενό το αντικείμενο στην φόρμα τότε η επόμενη δεν κρασάρει, έφτασα μέχρι το σημείο που, 
    αφού φορτώσω τα Data στο Grid και επειδή πρόκειται για Grid Με Master-Detail δομή, κάνω expand όλα τα Detail GridViews Που έχω δημιουργήσει.
    Παρατήρησα ότι αν δεν κάνω expand τα Master Views, η επόμενη φόρμα, ΔΕΝ κρασάρει. Για αυτό όταν δεν περνούσα αντικείμενο σαν παράμετρο δεν δημιουργούταν 
    πρόβλημα, διότι το Grid δεν είχε data για να φτιάξει τα Detail Views και κατ'επέκταση να κάνε τα Master Views Expand.

    Επίσης παρατήρησα ότι όλη η διαδικασία του εμπλουτισμού του Grid και του GridView expansion, γίνεται ... στον Constructor. Έχοντας διαβάσει
    στο Link του Μάρκου για το πότε δημιουργείται το Handle, μετέφερα τον κώδικα αυτόν στο OnFormLoad event, και... δούλεψε.

    Επαναλαμβάνω ότι δεν καταλαβαίνω γιατί. Ο συνειρμός ήταν μηχανικός :"Έχω πρόβλημα με handles, στον constructor δεν δημιουργούνται τα Handles, άρα 
    μπορεί για αυτό να έχω πρόβλημα.". Τώρα πώς μπορεί να επηρεάζεται η επόμενη φόρμα από τους handles που δημιουργήθηκαν ή δεν δημιουργήθηκαν στην προηγούμενη
    αυτό δεν μπορώ να το καταλάβω.

    Και για να απενοχοποιήσω το προϊόν της εργασίας του BW, δοκίμασα με ένα αντικείμενο που δεν είχε δημιουργηθεί στον BW και πάλι η φόρμα κράσαρε.

    Αν κάποιος μπορεί να σκεφτεί μια εξήγηση, θα ήθελα πολύ να την ακούσω. 

    Όπως και να έχει σας ευχαριστώ για τον χρόνο σας.Smile
  •  04-11-2011, 02:12 68031 σε απάντηση της 68029

    Απ: Πρόβλημα με ανάθεση Handle από MDI parent σε MDI Child.

    Και εγώ δεν καταλαβαίνω πως μπορεί να γίνεται αυτό όπως λες, αλλά αφού έλυσες το πρόβλημα δεν έχω να πω τίποτα.

    Συνήθως το να φορτώνουμε δεδομένα στον constructor και να εμπλέκεται handle πρόβλημα για το αν έχει ή όχι εμφανιστεί το control σπάνια θα δω. Δηλαδή θα αρχίσω να αμφιβάλω για τον κώδικα που έχω γράψει όταν φορτώνω δεδομένα σε φόρμες.

    Από την άλλη ίσως η χρήση του MDI να δημιουργεί πρόβλημα. Επειδή χρησιμοποιώ και εγώ DevExpress και αφού βγάλαμε το θέμα το cross reference exception από την μέση τότε ρίξε μία ματιά σε αυτό το link. Ίσως ο τύπος να περιγράφει το πρόβλημα που έχεις. http://www.devexpress.com/Support/Center/p/Q294913.aspx

Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems