Использование делегатов для передачи информации обратно в пользовательский интерфейс из пользовательского класса сокета - PullRequest
0 голосов
/ 06 октября 2010

По сути, у меня есть серверное приложение и связанный процесс агента для передачи данных сердцебиения на сервер.Серверное приложение реализует класс сокетов TCP (TCPDevice), который вызывается из WinForm.Мне известно об ограничении обновления пользовательского интерфейса из процессов, запущенных в отдельных потоках, и о том, что предпочтительным способом достижения этого является использование Delegates в сочетании с методом Invoke.Раньше у меня была очень маленькая потребность в использовании Делегатов (кроме, конечно, событий стандартного окна и элемента управления BackGroundWorker), я в растерянности относительно того, как сделать это в контексте моего приложения, и был бы признателен за некоторую помощь, хотя этоМне пришло в голову, что я могу использовать фонового работника для упорядочения обновлений пользовательского интерфейса.

В конечном итоге приложению потребуется обновить сетку устройств с помощью каналов от определенных агентов, однако для целей этого упражнения просто обновитьСтрока состояния на интерфейсе будет достаточно.Раздел кода, который, как я считаю, имеет отношение к распространению кода в форме, содержится в методе OnDataReceived.

Ниже приведен фрагмент кода из приложения прототипа, который должен поместить приведенное выше в соответствующий контекст:

Код из формы:

Private _device As TcpDevice

Private Sub btnListen_Click(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles btnListen.Click
        _device = New TcpDevice(uxIPaddress.Text, uxHost.Text, CInt(uxPort.Text))
        _device.Listen()
        Me.btnListen.Enabled = False
End Sub

Код из класса TCPDevice

Public Class TcpDevice : Implements CNIMonitor.Core.Domain.IDevice

    Private _ipAddress As String
    Private _hostName As String
    Private _port As Integer
    Private _status As Integer
    Private _previousStatus As Integer
    Private _listener As TcpListener
    Private _localAdd As System.Net.IPAddress


    Private _activeConnection As TcpClient
    Private _receiveBuffer(0) As Byte
    Private _sendBuffer As Byte
    Private _message As String
    Private _dataRead As Integer 'The value returned from the getstream.endread method


    Public Sub New(ByVal ipAddress As String, ByVal HostName As String, ByVal port As String)
        _ipAddress = ipAddress
        _hostName = HostName
        _port = port
    End Sub

    Public Sub Connect() Implements CNIMonitor.Core.Domain.IDevice.Connect

    End Sub

    Public Sub Disconnect() Implements CNIMonitor.Core.Domain.IDevice.Disconnect

        _activeConnection.Close()
        _listener.Stop()

        _activeConnection = Nothing

    End Sub

    Public Property HostName() As String Implements CNIMonitor.Core.Domain.IDevice.HostName
        Get
            HostName = _hostName
        End Get
        Set(ByVal value As String)
            _hostName = value
        End Set
    End Property

    Public Property IPAddress() As String Implements CNIMonitor.Core.Domain.IDevice.IPAddress
        Get
            IPAddress = _ipAddress
        End Get
        Set(ByVal value As String)
            _ipAddress = value
        End Set
    End Property

    Public Sub Listen() Implements CNIMonitor.Core.Domain.IDevice.Listen
        Try
            'Server component listens on the specified tcpip port
            _localAdd = System.Net.IPAddress.Parse(_ipAddress)
            _listener = New TcpListener(_localAdd, _port)
            _listener.Start()
            _listener.BeginAcceptTcpClient(AddressOf OnClientConnect, _listener)
            'Update the status message                
            Debug.WriteLine("Listening for host " + _ipAddress + " on port " + _port.ToString + ".")
        Catch ex As SocketException
            Debug.WriteLine("Failed listening on " + _ipAddress + " over port " & vbCrLf & " .")
        End Try
    End Sub

    Private Sub OnClientConnect(ByVal ar As IAsyncResult)

        Debug.WriteLine("Received connection from " + ar.AsyncState.ToString)
        'Get the connection object                
        _activeConnection = _listener.EndAcceptTcpClient(ar)
        'on Client connect                
        Debug.WriteLine("Client" + _ipAddress + " connected over port " & vbCrLf & " ." & _port.ToString)
        'Bind the event handler for dealing with incoming data                
        _activeConnection.GetStream.BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, AddressOf onDataReceived, _
            Nothing)
    End Sub

    Private Sub onDataReceived(ByVal ar As IAsyncResult)
        Dim receiveLength As Integer = 0
        ReDim _receiveBuffer(_activeConnection.ReceiveBufferSize - 1)
        Try
            Debug.WriteLine("Receiving from " + _ipAddress + ".")
            ' Complete the BeginReceive() asynchronous call by EndReceive() method                
            ' which will return the number of bytes written to the stream                 
            ' by the client                
            receiveLength = _activeConnection.GetStream.EndRead(ar)
            _message = Encoding.ASCII.GetString(_receiveBuffer, 0, receiveLength)
            _activeConnection.GetStream.BeginRead(_receiveBuffer, 0, _receiveBuffer.Length, AddressOf onDataReceived, Nothing)

            'NOW PASS THE INFORMATION RECEIVED BACK TO THE FORM

        Catch
            Debug.WriteLine("Transmission complete")
        End Try
    End Sub



    Public Property Port() As Integer Implements CNIMonitor.Core.Domain.IDevice.Port
        Get
            Port = _port
        End Get
        Set(ByVal value As Integer)
            _port = value
        End Set
    End Property

    Public Property PreviousStatus() As Integer Implements CNIMonitor.Core.Domain.IDevice.PreviousStatus
        Get
            PreviousStatus = _previousStatus
        End Get
        Set(ByVal value As Integer)
            _previousStatus = value
        End Set
    End Property

    Public Property Status() As Integer Implements CNIMonitor.Core.Domain.IDevice.Status
        Get
            Status = _status
        End Get
        Set(ByVal value As Integer)
            _status = value
        End Set
    End Property


End Class

1 Ответ

0 голосов
/ 22 февраля 2011

После небольшого дальнейшего изучения удалось заставить код работать.

...