This example focuses on basic set theory. The .Net Framework has several applicable LINQ extension methods, which can be easily used for determining four functions in basic set theory. These are...
This is a simple application requiring minimal coding. The code is annotated throughout, with the Operations Class having more detailed annotations.
Figure 1.0 - The Form at runtime
Figure 1.1 - The UserControl
This control encapsulates adding to or removing from a set of text items. It has a method to clear all of your input, and a function that returns your set as an array of Strings. This is a neat way for dealing with sets as a UserControl acts as an information specialist and avoids duplicating code.
Public Class SetInput 'custom event Public Event contentChanged() Dim cms As New ContextMenuStrip 'sets label text Public WriteOnly Property SetID As String Set(value As String) lblTitle.Text = "Set " & value End Set End Property 'returns set size Public ReadOnly Property setLength() As Integer Get Return lstDisplay.Items.Count End Get End Property 'sets up the ContextMenuStrip for the ListBox Private Sub SetInput_Load(sender As Object, e As EventArgs) Handles MyBase.Load cms.Items.Add("Remove item", Nothing, AddressOf removeItem) RaiseEvent contentChanged() End Sub 'paints title background Private Sub SetInput_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint e.Graphics.FillRectangle(SystemBrushes.ControlDark, New Rectangle(0, 0, Me.Width, 23)) End Sub 'tests if item exists in set, if not it adds it to the set Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click If lstDisplay.Items.Contains(txtInput.Text) Then inputErrorProvider.SetError(txtInput, "Set contains '" & txtInput.Text & "'") Else lstDisplay.Items.Add(txtInput.Text) RaiseEvent contentChanged() txtInput.Clear() End If End Sub 'clears the ErrorProvider Private Sub txtInput_TextChanged(sender As Object, e As EventArgs) Handles txtInput.TextChanged inputErrorProvider.Clear() End Sub 'enables Enter-Button press Private Sub txtInput_KeyDown(sender As Object, e As KeyEventArgs) Handles txtInput.KeyDown If e.KeyCode = Keys.Enter Then btnAdd.PerformClick() End Sub 'only shows ContextMenuStrip if an item is selected in the ListBox Private Sub lstDisplay_SelectedIndexChanged(sender As Object, e As EventArgs) Handles lstDisplay.SelectedIndexChanged If lstDisplay.SelectedIndex <> -1 Then lstDisplay.ContextMenuStrip = cms Else lstDisplay.ContextMenuStrip = Nothing End If End Sub 'MenuItem click eventhandler. Removes list item Private Sub removeItem(sender As Object, e As EventArgs) If lstDisplay.SelectedIndex <> -1 Then lstDisplay.Items.RemoveAt(lstDisplay.SelectedIndex) RaiseEvent contentChanged() End If End Sub 'Control clear method. Clears any input Public Sub clear() inputErrorProvider.Clear() lstDisplay.Items.Clear() txtInput.Clear() End Sub 'Returns set items Public Function getSet() As String() Return lstDisplay.Items.Cast(Of String).ToArray End Function End Class
The Form is the container for the GUI, which consists of two SetInput UserControls, a ComboBox, a ListBox, and two Buttons. The Form code is fairly simple and annotated throughout.
Public Class frmExample Dim functions As New Dictionary(Of Integer, [Delegate]) Dim operations As New Operations 'app initializing Private Sub frmExample_Load(sender As Object, e As EventArgs) Handles MyBase.Load SetInput1.SetID = "A" SetInput2.SetID = "B" cboChoice.SelectedIndex = 0 functions.Add(1, New Func(Of String(), String(), String())(AddressOf operations.union)) functions.Add(2, New Func(Of String(), String(), String())(AddressOf operations.intersection)) functions.Add(3, New Func(Of String(), String(), String())(AddressOf operations.complement)) functions.Add(4, New Func(Of String(), String(), String())(AddressOf operations.cartesianProduct)) End Sub 'clears any input Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click SetInput1.clear() SetInput2.clear() If cboChoice.SelectedIndex > 0 Then lstResults.Items.Clear() setEnabled() End Sub 'changes btnClear.Enabled if necessary Private Sub setEnabled() btnClear.Enabled = SetInput1.setLength + SetInput2.setLength + lstResults.Items.Count + If(cboChoice.SelectedIndex = 0, -1, 0) > 0 End Sub 'adds results from selected function to lstResults Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click lstResults.Items.Clear() lstResults.Items.AddRange(DirectCast(functions(cboChoice.SelectedIndex).DynamicInvoke(SetInput1.getSet, SetInput2.getSet), String())) setEnabled() End Sub 'sets some gui properties Private Sub cboChoice_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboChoice.SelectedIndexChanged lstResults.Items.Clear() If cboChoice.SelectedIndex = 0 Then lstResults.Items.Add("No operation selected") btnCompute.Enabled = cboChoice.SelectedIndex > 0 End Sub 'Calls setEnabled(), which changes btnClear.Enabled if necessary Private Sub SetInput1_contentChanged() Handles SetInput1.contentChanged, SetInput2.contentChanged setEnabled() End Sub End Class
This Class contains just four functions, all of which take two String array arguments, and return a String array. These four functions correspond to the four set theory functions mentioned in the overview. Using LINQ, these really are one-liners, but they produce the required results.
Public Class Operations 'error message Dim errortext() As String = New String() {"Insufficient data"} ''' <summary> ''' union Function ''' </summary> ''' <param name="setA"></param> ''' <param name="setB"></param> ''' <returns>with two inputs {1, 2} and {2, 3} returns {1, 2, 3}</returns> Public Function union(setA() As String, setB() As String) As String() Return If(setA.Count <> 0 Or setB.Count <> 0, setA.Union(setB).ToArray, errortext) End Function ''' <summary> ''' intersection Function ''' </summary> ''' <param name="setA"></param> ''' <param name="setB"></param> ''' <returns>with two inputs {1, 2} and {2, 3} returns {2} as both arrays contain 2</returns> Public Function intersection(setA() As String, setB() As String) As String() Return If(setA.Count <> 0 And setB.Count <> 0, setA.Intersect(setB).ToArray, errortext) End Function ''' <summary> ''' complement Function ''' </summary> ''' <param name="setA"></param> ''' <param name="setB"></param> ''' <returns>with two inputs {1, 2} and {2, 3} returns {1} as 1 is the only ''' number in array1 that doesn't exist in array2</returns> Public Function complement(setA() As String, setB() As String) As String() Return If(setA.Count > 0 And setB.Count <> 0, setA.Except(setB).ToArray, errortext) End Function ''' <summary> ''' cartesianProduct Function ''' </summary> ''' <param name="setA"></param> ''' <param name="setB"></param> ''' <returns>with two inputs {1, 2} and {apple, orange} returns {(1, apple), (1, orange), (2, apple), (2, orange)}</returns> Public Function cartesianProduct(setA() As String, setB() As String) As String() Return If(setA.Count <> 0 And setB.Count <> 0, setA.SelectMany(Function(x) setB.Select(Function(y) "(" & x & ", " & y & ")")).ToArray, errortext) End Function End Class
This example shows some LINQ methods, but more importantly, shows how to create reusable UserControls for data input, editing, and display.
You can download the example project here