public string TouchesEnded(PointF touch, out bool urlLaunchesExternalBrowser, out bool urlUsesRockImpersonation) { // TouchesEnded is tricky. It's reasonable a User will have // the keyboard up and decide to open/close/move another Note. // This should NOT cause the keyboard to hide. The only time a keyboard // should hide is if a User taps on a general area of the screen. // To accomplish this, we rely on ActiveUserNoteAnchor. If it's valid in TouchesEnded, // that means the touch was in an anchor and not a general part of the screen. // Secondly, if a normal control was touched, it may contain an active link. If a control // consumes input, we will ask it for its link and return that to the caller. // An example would be a Quote. It will consume input and then return a link to the citation. string activeUrl = string.Empty; urlLaunchesExternalBrowser = false; urlUsesRockImpersonation = false; // If there's an active UserNote Anchor, notify only it. if (ActiveUserNoteAnchor != null) { // Notify the active anchor, and clear it since the user released input. ActiveUserNoteAnchor.TouchesEnded(touch); // does this note want to be deleted? if (ActiveUserNoteAnchor.State == UserNote.TouchState.Delete) { // reset its state, and we'll let the messagebox result decide ActiveUserNoteAnchor.State = UserNote.TouchState.None; // then store a pointer to this note UserNote activeNote = ActiveUserNoteAnchor; // and have the system prompt the user for confirmation RequestDisplayMessageBox(MessagesStrings.UserNote_DeleteTitle, MessagesStrings.UserNote_DeleteMessage, delegate(int result) { // if they said yes, do it. if (result == 0) { // remove it from our list. UserNoteControls.Remove(activeNote); // notify our parent UserNoteChanged(activeNote); // now clear the anchor ref, which will effectively delete the note (eligible for garbage collection) activeNote.Dispose(MasterView); } }); } // clear the user note ActiveUserNoteAnchor = null; } else { // Since a UserNote Anchor was NOT touched, we know it was a "general" // area of the screen, and can allow the keyboard to hide. foreach (UserNote userNote in UserNoteControls) { userNote.NoteTouchesCleared( ); } // Now notify all remaining controls until we find out one consumed it. // 1. Start with User Notes. They should get first priority bool consumed = false; foreach (IUIControl control in UserNoteControls) { // was it consumed? IUIControl consumingControl = control.TouchesEnded(touch); if (consumingControl != null) { consumed = true; break; } } // if no user note consumed it, notify all regular controls if (consumed == false) { // 2. check all NON-revealed reveal boxees. // This allows them to get priority over taps on URLs and already-revealed boxes. List <IUIControl> revealBoxes = new List <IUIControl>( ); GetControlOfType <RevealBox>(revealBoxes); foreach (IUIControl control in revealBoxes) { // if not revealed and consuming input, we're good. if ((control as RevealBox).Revealed == false && control.TouchesEnded(touch) != null) { consumed = true; break; } } // 3. notify all remaining controls if (consumed == false) { foreach (IUIControl control in ChildControls) { // was it consumed? IUIControl consumingControl = control.TouchesEnded(touch); if (consumingControl != null) { // then see if it has an active URL we should hit activeUrl = consumingControl.GetActiveUrl(out urlLaunchesExternalBrowser, out urlUsesRockImpersonation); break; } } } } } return(activeUrl); }