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

 

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

Opening a form from within a thread

Îåêßíçóå áðü ôï ìÝëïò dgg. Τελευταία δημοσίευση από το μέλος dgg στις 29-03-2010, 10:12. Υπάρχουν 4 απαντήσεις.
Ταξινόμηση Δημοσιεύσεων: Προηγούμενο Επόμενο
  •  24-03-2010, 16:53 57852

    Opening a form from within a thread

    Γειά σας,

    Θέλω να κάνω το εξής: Σε μία φόρμα να έχω ένα thread το οποίο ελέγχει περιοδικά (καθε 1 sec , μέσω ενός web service) και αν επιστραφεί κάτι συγκεκριμένο να εμφανίζει ένα Message dialog και να ρωτάει τον χρήστη αν συμφωνεί. Αν ναι, να ανοίγει μία δεύτερη φόρμα και να γίνεται hide η πρώτη. Έχω κάνει κάτι, αλλά οταν πατήσω accept και μέσα στο thread κάνω show το δεύτερο form, σκάει. Γαμώτο κολάει όλο το PC και δε μπορώ να δώ το exception.



    Imports System.Threading
    Imports System.Collections

    Public Class GameRoomForm

        Private player As GameServiceReference.loggedusers
        Private game As GameServiceReference.game
        Private gameSelectionForm As GameSelectionForm
        Private gameServ As GameServiceReference.GamesWSClient
        Private updatePlListThread As Thread
        Private checkForInvitationsThread As Thread
        Private gameForm As TicTacToeGameForm


        Public Sub New(ByVal gameSelectionForm As GameSelectionForm, ByVal player As GameServiceReference.loggedusers)
            InitializeComponent()
            Try
                Me.gameSelectionForm = gameSelectionForm
                Me.player = player
                gameForm = New TicTacToeGameForm(Me.player, Me)
            Catch ex As Exception
                MessageBox.Show(ex.Message + " - " + ex.InnerException.ToString())
            End Try
        End Sub
        Private Sub inviteButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles inviteButton.Click
            If availablePlayersListBox.SelectedIndices.Count > 0 Then
                Dim invite As GameServiceReference.inviteResp
                invite = GameService.getGameWS.invite(Me.player.id, availablePlayersListBox.SelectedItem.ToString())

                If invite.success = True Then
                    Dim invForm As New InvitationForm(availablePlayersListBox.SelectedItem.ToString(), Me.player, invite)
                    invForm.ShowDialog()
                Else
                    MessageBox.Show("Could not invite player: " + invite.message, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                End If

            Else
                MessageBox.Show("Please select a game.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
            End If
            'Try
            'Dim game As New TicTacToeGameForm(Me.player, Me)
            'Me.Hide()
            'game.Show()
            'Catch ex As Exception
            'MessageBox.Show(ex.Message + " - " + ex.InnerException.ToString())
            'End Try
        End Sub

        Private Sub GameRoomForm_FormClosed(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosedEventArgs) Handles MyBase.FormClosed
            gameSelectionForm.Show()
        End Sub

        Private Sub cancelButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cancelButton.Click
            Dim exited As Boolean
            Try
                exited = GameService.getGameWS.exitGameRoom(Me.player)
            Catch ex As Exception
                MessageBox.Show("Cannot exit room: " + ex.Message + " " + ex.InnerException.ToString())
                exited = False
            End Try

            If exited = True Then
                Me.Close()
                gameSelectionForm.Show()
            Else
                Return
            End If
        End Sub

        Private Sub GameRoomForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Try
                gameServ = GameService.getGameWS()
                Me.game = gameServ.getUserGame(Me.player.id)
                Me.Text = Me.game.gameName + " " + " Room"
                Dim availPlayers() As String = gameServ.getAvailablePlayers(Me.game.gameID)

                For Each pl As String In availPlayers
                    If pl <> Me.player.userName Then
                        availablePlayersListBox.Items.Add(pl)
                    End If
                Next pl
            Catch ex As Exception
                MessageBox.Show(ex.Message + " - " + ex.InnerException.ToString())
            End Try

            updatePlListThread = New Thread(AddressOf UpdatePlayerList)
            updatePlListThread.IsBackground = True
            updatePlListThread.Start()

            checkForInvitationsThread = New Thread(AddressOf CheckForInvitations)
            checkForInvitationsThread.IsBackground = True
            checkForInvitationsThread.Start()
        End Sub

        Private Sub UpdatePlayerList()
            Dim availPlayers() As String
            Do
                availPlayers = gameServ.getAvailablePlayers(Me.game.gameID)

                For Each pl As String In availPlayers
                    If (pl <> Me.player.userName) And (Not availablePlayersListBox.Items.Contains(pl)) Then
                        availablePlayersListBox.Items.Add(pl)
                    End If
                Next pl


                Dim playersInList As System.Windows.Forms.ListBox.ObjectCollection = availablePlayersListBox.Items
                Dim playersToRemove(playersInList.Count) As String
                Dim playersToRemoveIndex As Integer = 0

                For index As Integer = 0 To playersInList.Count - 1
                    If Not (availPlayers.Contains(playersInList.Item(index))) Then
                        playersToRemove.SetValue(playersInList.Item(index), playersToRemoveIndex)
                        playersToRemoveIndex = playersToRemoveIndex + 1
                    End If
                Next index

                For Each plToRemove As String In playersToRemove
                    If playersToRemoveIndex > 0 Then
                        availablePlayersListBox.Items.Remove(plToRemove)
                    End If
                Next plToRemove

                availablePlayersListBox.Update()
                Thread.Sleep(1000)
            Loop
        End Sub

        Private Sub CheckForInvitations()
            Dim gameSrv As New GameServiceReference.GamesWSClient
            Dim checkForInvResp As New GameServiceReference.checkForInvitationResp
            Dim flag As Boolean = False
            Dim gameIsCompleted As Boolean = False

            Do Until (flag = True And gameIsCompleted = True)
                checkForInvResp = gameSrv.checkForInvitations(player.id)

                If (checkForInvResp.invited = True And flag = False) Then
                    Dim dlgResult As New DialogResult
                    dlgResult = MessageBox.Show("You have been invited from " + checkForInvResp.fromUserName + " to play.", "Invitation", MessageBoxButtons.YesNo, MessageBoxIcon.Question)

                    If dlgResult = Windows.Forms.DialogResult.Yes Then
                        Dim invitUpdated As Boolean
                        invitUpdated = gameSrv.acceptRejectInvitation(checkForInvResp.invitationID, True)

                        If invitUpdated = True Then
                            gameForm.setGameIsCompleted(gameIsCompleted)
                            gameForm.Show()
                            Me.Hide()
                        Else
                            MessageBox.Show("Could not accept/reject invitation", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                        End If

                    Else
                        Dim invitUpdated As Boolean
                        invitUpdated = gameSrv.acceptRejectInvitation(checkForInvResp.invitationID, False)
                        If invitUpdated = True Then

                        Else
                            MessageBox.Show("Could not accept/reject invitation", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                        End If
                    End If

                    flag = True
                End If
                Thread.Sleep(1000)
            Loop
        End Sub


    End Class
  •  26-03-2010, 12:39 57866 σε απάντηση της 57852

    Απ: Opening a form from within a thread

    Κατάφερα να το κάνω να μην σκάει. Μάλλον επειδή όταν άνοιγα την νέα φόρμα μέσα στο thread, μετά δεν έβγαινα απο αυτό, υπήρχε πρόβλημα. Οι αλλαγές είναι στο loop μέσα στο thread (CheckForInvitations, το οποίο και ανοίγει τη νέα φόρμα) αφαίρεσα τον έλεγχο του να έχει κλείσει η δεύτερη φόρμα:

    Do Until (flag = True) απο Do Until (flag = True And gameIsCompleted = True)

    και στο

    If invitUpdated = True Then
                     gameForm.setGameIsCompleted(gameIsCompleted)
                     gameForm.Show()
                      Me.Hide()
    Else

    διαγράφεται το gameForm.setGameIsCompleted(gameIsCompleted). (είχα δοκιμάσει να σετάρει η δεύτερη φόρμα αν πρέπει να βγεί απο το thread η πρώτη ή όχι αλλά μάλλον αυτό δε παίζει).


    Τώρα υπάρχει άλλο πρόβλημα: Η δεύτερη φόρμα που γίνεται show απο το thread, κλείνει αμέσως. Μήπως επειδή βγαίνει απο το Sub του thread (?) μετά την εμφάνισή της; Αφού είναι member variable στην κλάση γιατί να  μην την κρατάει; Αν την κάνω show σε button event τότε την εμφανίζει κανονικά.

    Καμμιά ιδέα;
     
  •  26-03-2010, 13:48 57870 σε απάντηση της 57866

    Απ: Opening a form from within a thread

    Απωρώ πως δεν σου χτύπισε με όλα αυτά κάποιο crossThreadreferenceException. Χωρίς να δω τον κώδικα σου αναλυτικά εκείνο που έχω να σου προτείνω είναι να μην ανακατεύεις το thread που ψάχνεις με την δουλειά που θα κάνεις με τον χρήστη. Όταν το thread που ψαχνει βρεί κάτι τότε ειδοποίησε την φόρμα να κάνει ότι δουλεία είναι να κάνει. Αυτό μπορείς να το κάνεις καλώντας με invoke της φόρμας μία συνάρτηση που θα κάνει όλα την δουλειά από το thread που εφτιαξε την φόρμα.

    Με μία δεύτερη ματία βλέπω ότι από τα διάφορα threads χρησιμοποιείς κοινοχρηστες μεταβλητές (πχ flag) χωρίς να προβλέπεις race conditions. Όταν γίνονται access μερικά πράγματα από πολλά threads πρέπει να κλειδώνουν αυτά για να μην τα αλλάζουν άλλα threads. Επίσης τα threads που φτιάχνεις δεν τα ορίζεις σαν background που σημαίνει ότι όταν θα θέλεις να κλείσει η εφαρμογή δεν θα κλείνουν αν δεν βγούν απο την λουπα τους. Προτείνω αντί για thread Να χρησιμοποιήσεις backgroundworker που λύνει όλα αυτά τα θέματα χωρίς να χρειάζεται να μπείς βαθειά στα threads, και θα απλοποιήσει και το κώδικά σου.

  •  26-03-2010, 13:49 57871 σε απάντηση της 57866

    Απ: Opening a form from within a thread

    Ψοφαει το thread και ετσι δε σου μενει τιποτα. Δεν εχω ιδεα απο vb code και ετσι δεν μπορω να σε βοηθησω. Εαν επιμενεις να κρατησεις μια φορμα μεσα στο thread, πρεπει να βρεις ενα λογικο τροπο να κρατησεις ζωντανο το Thread.
  •  29-03-2010, 10:12 57888 σε απάντηση της 57870

    Απ: Opening a form from within a thread

    Thanks για τις απαντήσεις,

    Όσον αφορά το crossThreadreferenceException δεν έχει χτυπήσει γιατί έχω βάλει στην αρχή του προγράμματος Control.CheckForIllegalCrossThreadCalls = False. Ξέρω δεν είναι σωστό αλλά ήθελα να κάνω κάτι γρήγορο. Απ'οτι βλέπω όμως πιο πολλά προβλήματα θα έχω τώρα. Τέλος πάντων, κατάφερα να ξεπεράσω το πρόβλημα. Έκανα αυτό με την invoke της caller form. Απλώς έκανα μία μέθοδο showform που εμφανίζει την νέα φόρμα που θέλω και με delegate την κάλεσα μέσα απο το thread. Δείχνει να δουλεύει.

    Στην κλάση:
    Private Delegate Sub showFormDelegateType()
    Private m_showFormDelegate As showFormDelegateType

    Public Sub ShowGameForm()
            gameForm.Show()
    End Sub


    Στο thread sub:
    If invitUpdated = True Then
            m_showFormDelegate = AddressOf Me.ShowGameForm
            Me.Invoke(m_showFormDelegate)
            Me.Hide()
    Else
    ...
Προβολή Τροφοδοσίας RSS με μορφή XML
Με χρήση του Community Server (Commercial Edition), από την Telligent Systems