|
VB Form |
|
This is a simple form sample that attempts to demonstrate many of the operations you may use in developing an interactive client application.
Imports System Imports System.Timers Imports System.Text Imports System.Drawing Imports System.Collections Imports System.Windows.Forms Imports System.Data Imports System.IO Imports System.Runtime.Serialization Imports System.Runtime.Serialization.Formatters.Binary Imports IDN.IO
Public Class Form1 Inherits System.Windows.Forms.Form
' -------------------------------------------------------------------- Private m_tagServer As TagServer = Nothing ' The Tag Server. Private m_schedule As IOSchedule = Nothing ' Current schedule. Private m_tag As IOTag = Nothing ' Current tag. Private m_fileName As String = "default.qd" ' Default filename.
' Used for displaying information in the textboxes. Private m_tagEventLines As New ArrayList(100) Private m_scheduleEventLines As New ArrayList(100) Private m_outputLines As New ArrayList(100)
Private WithEvents m_getTagButton As System.Windows.Forms.Button Private m_tagEventTextBox As System.Windows.Forms.TextBox Private WithEvents m_outputTextBox As System.Windows.Forms.TextBox Private WithEvents m_getScheduleButton As System.Windows.Forms.Button Private m_scheduleEventTextBox As System.Windows.Forms.TextBox Private m_openFileDialog As System.Windows.Forms.OpenFileDialog Private m_saveFileDialog As System.Windows.Forms.SaveFileDialog Private WithEvents m_tagPropertiesButton As System.Windows.Forms.Button Private WithEvents m_schedulePropertiesButton As System.Windows.Forms.Button Private WithEvents m_tagSubscribeButton As System.Windows.Forms.Button Private WithEvents m_tagUnsubscribeButton As System.Windows.Forms.Button Private WithEvents m_scheduleSubscribeButton As System.Windows.Forms.Button Private WithEvents m_scheduleUnsubscribeButton As System.Windows.Forms.Button Private WithEvents m_tagWriteButton As System.Windows.Forms.Button Private m_mainMenu As System.Windows.Forms.MainMenu Private menuItem1 As System.Windows.Forms.MenuItem Private menuItem2 As System.Windows.Forms.MenuItem Private WithEvents m_newMenuItem As System.Windows.Forms.MenuItem Private WithEvents m_openMenuItem As System.Windows.Forms.MenuItem Private WithEvents m_saveMenuItem As System.Windows.Forms.MenuItem Private WithEvents m_saveAsMenuItem As System.Windows.Forms.MenuItem Private WithEvents m_exitMenuItem As System.Windows.Forms.MenuItem Private WithEvents m_tagServerMenuItem As System.Windows.Forms.MenuItem Private m_scheduleGroupBox As System.Windows.Forms.GroupBox
' -------------------------------------------------------------------- Public Sub New() InitializeComponent() End Sub
' -------------------------------------------------------------------- #Region "Windows Form Designer generated code" ' removed... #End Region
' -------------------------------------------------------------------- <STAThread()> _ Shared Sub Main() Application.Run(New Form1)
End Sub
' -------------------------------------------------------------------- ' Private Sub OnFormLoad(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
' Create a Tag Server. m_tagServer = New TagServer
' Clean now. m_tagServer.Dirty = False
' Sign up for any error events from the IO. AddHandler m_tagServer.Errored, AddressOf OnIOErroredEventHandler End Sub
' -------------------------------------------------------------------- ' Let the user select servers, create or edit schedules and tags to ' be monitored. Private Sub OnTagServerMenuItemClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_tagServerMenuItem.Click If Not (m_tagServer Is Nothing) Then m_tagServer.ShowDialog() End If
' We can do this because the server objects ignore duplicte ' event handlers. SubscribeToAllPropertyChangedEvents(m_tagServer) End Sub
' --------------------------------------------------------------------- ' Demonstrate how to select a tag from the Tag Server and subscribe and ' and unsubscribe from its Updated event. Private Sub OnGetTagClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_getTagButton.Click If Not (m_tagServer Is Nothing) Then
' Let the user browse the configured IOTag's and select one. Dim tag As IOTag = CType(m_tagServer.SelectItem(GetType(IOTag)), IOTag)
' Was a new tag was selected by the user? If Not (tag Is Nothing) Then
' If we already had one running in our example UI ' then unsubscribe from the old tag's events. If Not (m_tag Is Nothing) Then RemoveHandler m_tag.Updated, New UpdatedDelegate(AddressOf OnTagUpdatedEventHandler) End If
' This is now our new selected tag. m_tag = tag
' Subscribe to the tag's Updated event. AddHandler m_tag.Updated, AddressOf OnTagUpdatedEventHandler
' Change the tag GroupBox text to the tag name. m_tagGroupBox.Text = tag.Name End If End If End Sub
' -------------------------------------------------------------------- ' This event comes from the tag so 'sender' can be cast to an IOTag. ' Check the type before casting in a real application. Public Sub OnTagUpdatedEventHandler(ByVal sender As Object, ByVal e As UpdateEventArgs) Try ' Use a StringBuilder for better speed. Dim sb As New StringBuilder
' Is the tag an array? If e.Sample.Value.GetType().IsArray Then
' Display the array values on a line. Dim val As System.Array = CType(e.Sample.Value, System.Array) Dim i As Integer For i = 0 To val.Length -1 sb.AppendFormat("{0}, ", val.GetValue(i)) Next i
' Get rid of that last comma separator so it looks good and add a LF. If sb.Length >= 2 Then sb.Length = sb.Length - 2 End If sb.Append(vbCr + vbLf) WriteTagTextBox(sb.ToString())
' Display the timestamp and quality. sb.Length = 0 sb.AppendFormat("{0:MM/dd/yyyy, hh:mm:ss}:" + vbTab + "{1}", e.Sample.TimeStamp, e.Sample.Quality) WriteTagTextBox(sb.ToString()) Else ' Not an array so it's much easier. sb.AppendFormat("{0}:" + vbTab + "{1:MM/dd/yyyy, hh:mm:ss}:" + vbTab + "{2}", e.Sample.Value, e.Sample.TimeStamp, e.Sample.Quality) WriteTagTextBox(sb.ToString()) End If Catch ex As Exception WriteOutputTextBox("Error updating tag: " + ex.Message) End Try End Sub
' -------------------------------------------------------------------- ' Demonstrate using an object's ShowDialog() method for editing properties. Private Sub OnTagPropertiesClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_tagPropertiesButton.Click If Not (m_tag Is Nothing) Then m_tag.ShowDialog() Else WriteOutputTextBox("No current tag exist. Try selecting a tag first.") End If End Sub
' -------------------------------------------------------------------- ' Demonstrate using a tag's Write() method, using dialogs. Private Sub OnTagWriteClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_tagWriteButton.Click If Not (m_tag Is Nothing) Then WriteOutputTextBox(m_tag.Write().ToString()) Else WriteOutputTextBox("No current tag exists. Try selecting a tag first.") End If End Sub
' -------------------------------------------------------------------- ' Start listening to UpdatedEvents. Duplicate assignments are ignored. Private Sub OnTagSubscribeClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_tagSubscribeButton.Click If Not (m_tag Is Nothing) Then AddHandler m_tag.Updated, AddressOf OnTagUpdatedEventHandler Else WriteOutputTextBox("No current tag exists. Try Configuring servers then Selecting a tag first.") End If End Sub
' -------------------------------------------------------------------- ' Stop listening to UpdatedEvents. Duplicates are ignored. Private Sub OnTagUnsubscribeClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_tagUnsubscribeButton.Click If Not (m_tag Is Nothing) Then RemoveHandler m_tag.Updated, New UpdatedDelegate(AddressOf OnTagUpdatedEventHandler) Else WriteOutputTextBox("No current tag exists. Try Configuring servers then Selecting a tag first.") End If End Sub
' -------------------------------------------------------------------- ' Let the user select a schedule to monitor. Private Sub OnGetScheduleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_getScheduleButton.Click If Not (m_tagServer Is Nothing) Then
' Use the provided UI to pick a schedule. Dim schedule As IOSchedule = CType(m_tagServer.SelectItem(GetType(IOSchedule)), IOSchedule)
' Was a new schedule was selected by the user? If Not (schedule Is Nothing) Then
' If we already had one running If Not (m_schedule Is Nothing) Then RemoveHandler m_schedule.Updated, New UpdatedDelegate(AddressOf OnScheduleUpdatedEventHandler) End If
' This is now our new current schedule. m_schedule = schedule
' Subscribe to the events. AddHandler m_schedule.Updated, AddressOf OnScheduleUpdatedEventHandler
' Change the schedule's GroupBox text to the schedule name? m_scheduleGroupBox.Text = m_schedule.Name End If End If End Sub
' ------------------------------------------------------------------------ ' Handle schedule Updated events. The schedule has an UpdatedTags list. ' Get the tag values directly from the IOTag objects. Private Sub OnScheduleUpdatedEventHandler(ByVal sender As Object, ByVal e As UpdateEventArgs) Try ' Use a StringBuilder for better speed. Dim sb As New StringBuilder
' Scan and display the list of tags that changed. WriteScheduleTextBox("") Dim i As Integer For i = 0 To (CType(sender, IOSchedule).UpdatedTags.Count) -1
' Array values are not processed here for simplicity. ' Look at the tag Updated handler for an array example. Dim tag As IOTag = CType(CType(sender, IOSchedule).UpdatedTags.GetByIndex(i), IOTag) sb.Length = 0 sb.AppendFormat("{0}:" + vbTab + "{1}:" + vbTab + "{2:MM/dd/yyyy, hh:mm:ss}:" + vbTab + "{3}", tag.Name, tag.Value, tag.TimeStamp, tag.Quality) WriteScheduleTextBox(sb.ToString()) Next i Catch ex As Exception WriteOutputTextBox("Error updating schedule: " + ex.Message) End Try End Sub
' -------------------------------------------------------------------- ' Demonstrate using an object's ShowDialog() method for editing properties. Private Sub OnSchedulePropertiesClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_schedulePropertiesButton.Click If Not (m_schedule Is Nothing) Then m_schedule.ShowDialog() Else WriteOutputTextBox("No current schedule exist. Try selecting a schedule first.") End If End Sub
' -------------------------------------------------------------------- ' Susbscribe to the schedule Updated event. Private Sub OnScheduleSubscribeClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_scheduleSubscribeButton.Click If Not (m_schedule Is Nothing) Then AddHandler m_schedule.Updated, AddressOf OnScheduleUpdatedEventHandler Else WriteOutputTextBox("No current schedule exists. Try Configuring servers then Selecting a schedule first.") End If End Sub
' -------------------------------------------------------------------- ' Unsubscribe from the schedule Updated event. Private Sub OnScheduleUnsubscribeClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_scheduleUnsubscribeButton.Click If Not (m_schedule Is Nothing) Then RemoveHandler m_schedule.Updated, New UpdatedDelegate(AddressOf OnScheduleUpdatedEventHandler) Else WriteOutputTextBox("No current schedule exists. Try Configuring servers then Selecting a schedule first.") End If End Sub
' ------------------------------------------------------------------------ ' Handle PropertyChanged events for all of the Tag Server's objects. Public Sub OnPropertyChangedEventHandler(ByVal sender As Object, ByVal e As IDN.IO.PropertyChangedEventArgs) Try ' Display the sender's name. WriteOutputTextBox(vbCr + vbLf + "Property changed event from: " + CType(sender, IDNBrowsable).Name)
' Loop through and display any changed property's name and value. Dim ke As IEnumerator = e.Properties.Keys.GetEnumerator() Dim ve As IEnumerator = e.Properties.Values.GetEnumerator() ke.MoveNext() ve.MoveNext() Dim i As Integer For i = 0 To e.Properties.Count -1 WriteOutputTextBox(ke.Current.ToString() + ": " + ve.Current.ToString()) ke.MoveNext() ve.MoveNext() Next i
' This is how to specifically detect watchdog failure. If sender.GetType() Is GetType(IOServer) Then If e.Properties.Contains("Mode") Then If CType(e.Properties("Mode"), ServerMode) = ServerMode.StatusCheckFailure Then WriteOutputTextBox("Watchdog status check failure.") End If End If End If
Catch ex As Exception WriteOutputTextBox("Error on PropertyChanged event: " + ex.Message) End Try End Sub
' -------------------------------------------------------------------- ' Handle error message events. Public Sub OnIOErroredEventHandler(ByVal sender As Object, ByVal e As IDN.IO.ErroredEventArgs) If Not (e.Sender Is Nothing) AndAlso e.Sender.GetType().IsSubclassOf(GetType(IDNBrowsable)) Then WriteOutputTextBox(e.Severity.ToString() + ": " + e.Timestamp.ToString() + ": " + CType(e.Sender, IDNBrowsable).Name+" " + e.Message) Else WriteOutputTextBox(e.Severity.ToString() + ": " + e.Timestamp.ToString()+" " + e.Message) End If End Sub
' -------------------------------------------------------------------- ' Recursive method to scan the entire Tag Server data tree and to direct ' ALL PropertyChanged events to our one handler. "Node" in this case ' refers to a data tree node. Private Sub SubscribeToAllPropertyChangedEvents(ByVal inNode As IDNBrowsable) AddHandler inNode.PropertyChanged, AddressOf OnPropertyChangedEventHandler If inNode.Children.Count > 0 Then Dim i As Integer For i = 0 To inNode.Children.Count -1 SubscribeToAllPropertyChangedEvents(CType(inNode.Children.GetByIndex(i), IDNBrowsable)) Next i End If End Sub
' -------------------------------------------------------------------- ' Save the Tag Server configuration to the current file. Private Sub OnSaveMenuItemClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_saveMenuItem.Click If Not (m_tagServer Is Nothing) Then
' Ever been saved yet? If m_fileName = "default.qd" Then OnSaveAsMenuItemClick(sender, e) Else Dim stream As Stream = File.Open(m_fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None) If Not (stream Is Nothing) Then Dim formatter As New BinaryFormatter
' This is all that is needed to save the contents of the ' IO configuration onto the stream. formatter.Serialize(stream, m_tagServer) stream.Close() End If
' This clears the dirty flag for ALL items in the Tag Server. m_tagServer.Dirty = False End If End If End Sub
' -------------------------------------------------------------------- ' Save the Tag Server configuration to a user selected file. Private Sub OnSaveAsMenuItemClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_saveAsMenuItem.Click If Not (m_tagServer Is Nothing) Then m_saveFileDialog.FileName = m_fileName If m_saveFileDialog.ShowDialog(Me) = DialogResult.OK Then Dim stream As Stream = File.Open(m_fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None) If Not (stream Is Nothing) Then m_fileName = m_saveFileDialog.FileName Dim formatter As New BinaryFormatter
' Serialize the Tag Server configuration onto the stream formatter.Serialize(stream, m_tagServer) stream.Close() End If
' Clean. m_tagServer.Dirty = False End If End If End Sub
' -------------------------------------------------------------------- ' Open a Tag Server configuration. Private Sub OnOpenMenuItemClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_openMenuItem.Click
' If we already have an active node object... If Not (m_tagServer Is Nothing) Then
' Check for changes so we don't overwrite it with the new selection. If m_tagServer.Dirty Then
' Prompt the user to save the changes before overwriting with the new configuration. If MessageBox.Show("Save Changes to: " + m_fileName + "?", "Save Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
' Reuse this for saving. OnSaveMenuItemClick(sender, e) End If End If End If
' Now let the user get the file to open. If m_openFileDialog.ShowDialog(Me) = DialogResult.OK Then Dim stream As Stream = Nothing stream = m_openFileDialog.OpenFile() If Not (stream Is Nothing) Then m_fileName = m_openFileDialog.FileName Dim formatter As New BinaryFormatter
' Release any existing Tag Server. m_tagServer.Release()
' Create a new Tag Server and its configuration from the file m_tagServer = CType(formatter.Deserialize(stream), TagServer) stream.Close() End If
If Not (m_tagServer Is Nothing) Then
' Sign up for any error message events from the IO. AddHandler m_tagServer.Errored, AddressOf OnIOErroredEventHandler
' Consider this a fresh start. m_tagServer.Dirty = False
' Connect any servers that were loaded. m_tagServer.Connect()
' Watch ALL of the property changed events. SubscribeToAllPropertyChangedEvents(m_tagServer) End If End If End Sub
' -------------------------------------------------------------------- ' Create a new Tag Server configuration. Private Sub OnNewMenuItemClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_newMenuItem.Click
' Check for changes in any of the Tag Server objects If Not (m_tagServer Is Nothing) Then
' Has anything changed? If m_tagServer.Dirty Then
' Does the user want to save those changes? If MessageBox.Show("Save Changes to: " + m_fileName + "?", "Save Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then OnSaveMenuItemClick(sender, e) End If End If
' Release the old Tag Server. m_tagServer.Release()
' Create a new 'blank' one. m_tagServer = New TagServer
' We're fresh and clean. m_tagServer.Dirty = False
' Set the default filename (this is NOT the way to maintain the filename). m_fileName = "default.qd" End If End Sub
' -------------------------------------------------------------------- ' Exit. Private Sub OnExitMenuItemClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_exitMenuItem.Click
' Check for Tag Server configuration changes. OnClosing(Nothing, Nothing) Close() End Sub
' -------------------------------------------------------------------- ' Called directly when the "X" is clicked. Private Overloads Sub OnClosing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
' Check for changes in Tag Server items. If Not (m_tagServer Is Nothing) Then
' Any changes? If m_tagServer.Dirty Then
' Prompt to save changes. If MessageBox.Show("Save Changes to: " + m_fileName + "?", "Save Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Question) = DialogResult.Yes Then
' Call the save method. OnSaveMenuItemClick(sender, e) End If End If End If
' Releases everything. m_tagServer.Release() End Sub
' -------------------------------------------------------------------- ' The UI handlers below are needed because generally you can only call ' a UI control from the thread that created it. Access to these methods ' in our example are from a mixture of UI calls and event handlers. The ' event handlers' threads are not going to be the same as the UI thread. Private Sub WriteScheduleTextBox(ByVal inLine As String) If m_scheduleEventLines.Count = 100 Then m_scheduleEventLines.RemoveAt(99) End If m_scheduleEventLines.Insert(0, inLine) If m_scheduleEventTextBox.InvokeRequired Then m_scheduleEventTextBox.BeginInvoke(New OnScheduleUIDelegate(AddressOf OnScheduleUIEventHandler), Nothing) Else m_scheduleEventTextBox.Lines = CType(m_scheduleEventLines.ToArray(GetType(String)), String()) End If End Sub
' -------------------------------------------------------------------- Protected Delegate Sub OnScheduleUIDelegate() Protected Sub OnScheduleUIEventHandler() m_scheduleEventTextBox.Lines = CType(m_scheduleEventLines.ToArray(GetType(String)), String()) End Sub
' -------------------------------------------------------------------- Private Sub WriteTagTextBox(ByVal inLine As String) If m_tagEventLines.Count = 100 Then m_tagEventLines.RemoveAt(99) End If m_tagEventLines.Insert(0, inLine) If m_tagEventTextBox.InvokeRequired Then m_tagEventTextBox.BeginInvoke(New OnTagUIDelegate(AddressOf OnTagUIEventHandler), Nothing) Else m_tagEventTextBox.Lines = CType(m_tagEventLines.ToArray(GetType(String)), String()) End If End Sub
' -------------------------------------------------------------------- Protected Delegate Sub OnTagUIDelegate() Protected Sub OnTagUIEventHandler() m_tagEventTextBox.Lines = CType(m_tagEventLines.ToArray(GetType(String)), String()) End Sub
' -------------------------------------------------------------------- ' This one scrolls backwards. Private Sub WriteOutputTextBox(ByVal inLine As String) If m_outputLines.Count = 500 Then m_outputLines.RemoveAt(0) End If m_outputLines.Add(inLine) If m_outputTextBox.InvokeRequired Then m_outputTextBox.BeginInvoke(New OnOutputUIDelegate(AddressOf OnOutputUIEventHandler), Nothing) Else m_outputTextBox.Lines = CType(m_outputLines.ToArray(GetType(String)), String()) End If End Sub
' -------------------------------------------------------------------- Protected Delegate Sub OnOutputUIDelegate() Protected Sub OnOutputUIEventHandler() m_outputTextBox.Lines = CType(m_outputLines.ToArray(GetType(String)), String()) End Sub
' -------------------------------------------------------------------- ' We are using this event handler to scroll to the bottom when we ' change the text allowing it to go backwards. Private Sub OnOutputTextBoxTextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_outputTextBox.TextChanged m_outputTextBox.SelectionStart = m_outputTextBox.Text.Length m_outputTextBox.ScrollToCaret() End Sub End Class |
|