/// <summary>
 /// Called when a subscription is added or removed from the control.
 /// </summary>
 public void OnSubscriptionModified(Subscription subscription, bool deleted)
 {
     if (subscription == null)
     {
         return;
     }
     if (!deleted)
     {
         // check if the subscription is already added to the control.
         if (m_items.Contains(subscription.ClientHandle))
         {
             return;
         }
         // register for data updates.
         subscription.DataChanged        += new OpcDa::DataChangedEventHandler(OnDataChange);
         subscription.DeleteSubscription += new System.EventHandler(subscription_DeleteSubscription);
         // add to subscription list.
         m_subscriptions.Add(subscription.ClientHandle, subscription);
         m_items.Add(subscription.ClientHandle, new ArrayList());
     }
     else
     {
         // check if the subscription is already removed from the control.
         if (!m_items.Contains(subscription.ClientHandle))
         {
             return;
         }
         // unregister for data updates.
         try
         {
             subscription.DataChanged -= new OpcDa::DataChangedEventHandler(OnDataChange);
         }
         catch (System.Exception)
         {
             //Now we can do nothig abou it
         }
         subscription.DeleteSubscription -= new System.EventHandler(subscription_DeleteSubscription);
         // remove all items for the subscription.
         ArrayList existingItemList = (ArrayList)m_items[subscription.ClientHandle];
         foreach (ListViewItem listItem in existingItemList)
         {
             EditComplexValueDlg dialog = (EditComplexValueDlg)m_viewers[listItem];
             if (dialog != null)
             {
                 dialog.Close();
                 m_viewers.Remove(listItem);
             }
             listItem.Remove();
         }
         // remove from subscription list.
         m_subscriptions.Remove(subscription.ClientHandle);
         m_items.Remove(subscription.ClientHandle);
     }
 }
 /// <summary>
 /// Called when a data update event is raised by a subscription.
 /// </summary>
 private void OnDataChange(object subscriptionHandle, object requestHandle, OpcDa::ItemValueResult[] values)
 {
     // ensure processing is done on the control's main thread.
     if (InvokeRequired)
     {
         BeginInvoke(new OpcDa::DataChangedEventHandler(OnDataChange), new object[] { subscriptionHandle, requestHandle, values });
         return;
     }
     try
     {
         // find subscription.
         ArrayList existingItemList = (ArrayList)m_items[subscriptionHandle];
         // check if subscription is still valid.
         if (existingItemList == null)
         {
             return;
         }
         // change all existing item values for the subscription to 'grey'.
         // this indicates an update arrived but the value did not change.
         foreach (ListViewItem listItem in existingItemList)
         {
             if (listItem.ForeColor != Color.Gray)
             {
                 listItem.ForeColor = Color.Gray;
             }
         }
         // do nothing more if only a keep alive callback.
         if (values == null || values.Length == 0)
         {
             OnKeepAlive(subscriptionHandle);
             return;
         }
         if (UpdateEvent != null)
         {
             UpdateEvent(subscriptionHandle, values);
         }
         // update list view.
         ArrayList newListItems = new ArrayList();
         foreach (OpcDa::ItemValueResult value in values)
         {
             // item value should never have a null client handle.
             if (value.ClientHandle == null)
             {
                 continue;
             }
             // this item can be updated with new values instead of inserting/removing items.
             ListViewItem replacableItem = null;
             // remove existing items.
             if (!m_CMS_KeepValues.Checked)
             {
                 // search list of existing items for previous values for this item.
                 ArrayList updatedItemList = new ArrayList(existingItemList.Count);
                 foreach (ListViewItem listItem in existingItemList)
                 {
                     OpcDa::ItemValueResult previous = (OpcDa::ItemValueResult)listItem.Tag;
                     if (!value.ClientHandle.Equals(previous.ClientHandle))
                     {
                         updatedItemList.Add(listItem);
                         continue;
                     }
                     if (replacableItem != null)
                     {
                         EditComplexValueDlg dialog = (EditComplexValueDlg)m_viewers[replacableItem];
                         if (dialog != null)
                         {
                             dialog.Close();
                             m_viewers.Remove(replacableItem);
                         }
                         replacableItem.Remove();
                     }
                     replacableItem = listItem;
                 }
                 // the updated list has all values for the current item removed.
                 existingItemList = updatedItemList;
             }
             // add value to list.
             AddValue(subscriptionHandle, value, ref replacableItem);
             // save new list item.
             if (replacableItem != null)
             {
                 newListItems.Add(replacableItem);
             }
         }
         // add new items to existing item list.
         existingItemList.AddRange(newListItems);
         m_items[subscriptionHandle] = existingItemList;
         // adjust column widths.
         for (int ii = 0; ii < m_ItemListLV.Columns.Count; ii++)
         {
             if (ii != VALUE && ii != QUALITY)
             {
                 m_ItemListLV.Columns[ii].Width = -2;
             }
         }
     }
     catch (System.Exception e)
     {
         OnException(subscriptionHandle, e);
     }
 }