Friday, March 5, 2010

Linq Remove Duplicates and Merge Two Collections using Union and Distinct

Linq is a boon from Microsoft to all .net developers; it makes things really easy and simple and also gives the ability to perform several tasks that you do using sql (many more).I had to remove duplicates based on some columns from two different collections, it was done using for loops in the past, as linq is available I thought of giving it a shot.

Union and distinct is used to obtain the desired results; also notice a custom IEqualityComparer is passed to distinct instead of the default equality comparer to compare values. In custom equality comparer you can ignore the columns or properties you don’t want to consider when deciding the uniqueness. If you don’t have a custom IEqualityComparer then linq distinct wont work as expected and might return duplicates.

Let’s dive into some code here.
''define lists
Dim list1 As New List(Of Item)
Dim list2 As New List(Of Item)

''add two items to list 1
Dim item1 As New Item
item1.ItemID = Guid.Empty
item1.ItemName = "item1"


Dim item2 As New Item
item2.ItemID = Guid.Empty
item2.ItemName = "item2"


''add same item(item 2 from list1) to list 2
Dim item3 As New Item
item3.ItemID = Guid.Empty
item3.ItemName = "item1"


''get thee distinct of the two lists
Dim aaaaa = (From l1i In list1 Select l1i).Union _
(From l2i In list2 Select l2i).Distinct(New ItemComparer)

''a simple item class
Public Class Item
Public ItemID As Guid
Public ItemName As String
End Class

''custom IEqualityComparer for our item class
Public Class ItemComparer
Implements IEqualityComparer(Of Item)

Public Function Equals1(ByVal x As Item, ByVal y As Item) As Boolean _
Implements IEqualityComparer(Of Item).Equals

If x Is y Then Return True

If x Is Nothing OrElse y Is Nothing Then Return False

Return (x.ItemID = y.ItemID) AndAlso (x.ItemName = y.ItemName)

End Function

Public Function GetHashCode1(ByVal item As Item) As Integer _
Implements IEqualityComparer(Of Item).GetHashCode

If item Is Nothing Then Return 0

Dim hashname = _
If(item.ItemName Is Nothing, 0, item.ItemName.GetHashCode())

Dim hashid = item.ItemID.GetHashCode()

Return hashname Xor hashid
End Function
End Class

Complex and a special three state (tri state) Treeview Control

As we all know treeview is used to show hierarchy of items easily. Microsoft tree is readily available for you if your needs are simple. But if you want to have the tree do more than two states it might not be possible with the treeview control as it is. You might have seen several treeview .net controls out there that have three states but the treeview in this post here might be little different than those. A parent can have its own state and can depict its child check state when stateless, also all the children under a parent are not affected when check state on the parent changes.

Checked – Green Check
Unchecked – No Check
AtLeastOneChild Checked (only for Parent) – Light Gray Check

State Determination:

Node when checked a green check is shown regardless of whether any child nodes have been checked
Node when unchecked but has checked child, gray check is shown for the node.
Node when unchecked and has no children or all children unchecked, an empty check is shown

State Images:

What it can do:

Bind to Any Type of DataSource
Bind to a Single Datasource (With node definition and its check state)
Bind to Two Datasources(One that has node definition and other that has check state of the nodes)
Select All
Deselect All
Expand All
Collapse All
Escape on a node gets previous check state back
Enter Select the node
Node color change on editing
Configurable coloring scheme for read-only and edited nodes

Using It:

For the treeview to properly work you have to set the members(columns in your binding objects)

ParentIDMember - Column to determine heirarchy
ValueMember – Column that holds the ID of the node
DisplayMember – Column that holds the Node Text
DefinitionValueRelationshipMember – Column that is common in the definition object and value object
DefinitionEntityCheckValueMember – Column that determines the check state of the node in the definition
ValueEntityCheckValueMember - Column that determines the check state of the node in the value object
CheckBoxEnabledMember – Column to enable/disable the node

Loading Nodes And Values

a)With no node values in the definition
TriStateTreeView1.DefinitionHasValue = False
TriStateTreeView1.DisplayMember = "Name"
TriStateTreeView1.ValueMember = "ID"
TriStateTreeView1.ParentIDMember = "ParentID"
TriStateTreeView1.CheckBoxEnabledMember = "CheckBoxEnabled"

TriStateTreeView1. ValueEntityCheckValueMember = “NodeValue”
TriStateTreeView1. DefinitionValueRelationshipMember = “ID”

b)With node values in the definition

TriStateTreeView1.DefinitionHasValue = True
TriStateTreeView1.DisplayMember = "Name"
TriStateTreeView1.ValueMember = "ID"
TriStateTreeView1.ParentIDMember = "ParentID"
TriStateTreeView1.CheckBoxEnabledMember = "CheckBoxEnabled"
TriStateTreeView1.DefinitionEntityCheckValueMember = “NodeValue”

Link below has the control and the sample code on how to use the control.