示例#1
0
        private static void RaiseEventsOnClient(IntPtr hwnd, int eventId, object idProp, int idObject, int idChild)
        {
            ProxySimple el = null;

            WindowsListView wlv = new WindowsListView (hwnd, null, -1);
            AutomationProperty automationProperty = idProp as AutomationProperty;
            AutomationEvent automationEvent = idProp as AutomationEvent;

            if (eventId == NativeMethods.EventObjectSelectionRemove && automationProperty == SelectionItemPattern.IsSelectedProperty)
            {
                el = wlv.CreateListViewItemCheckIfInGroup(idChild - 1);
                if (el != null)
                {
                    el.DispatchEvents(eventId, idProp, idObject, idChild);
                    return;
                }
            }
            else if (eventId == NativeMethods.EventObjectSelection
            || eventId == NativeMethods.EventObjectSelectionRemove
            || eventId == NativeMethods.EventObjectSelectionAdd)
            {
                // This is the speced behavior for events and selection 
                //
                // The following rule should be used to decide when to fire Selected vs Add/Remove events:
                // If the result of a SelectElement or an AddElementToSelection is that a single item is selected, 
                // then send a Select for that element; otherwise send Add/Removes as appropriate.
                // Note that this rule does not depend on whether the selection container is single- or multi- select, 
                // or on what method was used to change the selection. Only the result matters.
                // Overall message to clients (test automation and assistive technologies)
                //
                // 1) If you receive ElementSelectedEvent this guarantees that the element that raised the 
                //    event is the only selected element in that container.
                // 2) If you receive ElementAddedToSelectionEvent this guarantees that those items are added 
                //    to selection and the end result of the selection is more than one item.  
                // 3) If you receive ElementRemovedFromSelectionEvent this guarantees that those items are 
                //    deselected and the end result is NOT one item selected.  
                //
                // For the listview adhering to the spec is not possible because of an ambiguity with the winevents that 
                // are fired.  This code is trying to map the winevents received to the UIAutomaiton events that are expected.
                // These are the two cases that are ambiguous:
                //
                // Case 1:
                // The user clicks two different items in succession.
                // We get an EventObjectSelectionRemove WinEvent for each item that loses 
                // selection and in addition an EventObjectSelection for the new item that got selection.  
                // In this case we want to disregard the EventObjectSelectionRemove (not raise UIA 
                // ElementRemovedFromSelectionEvent) because the end result of this scenario is that only one item is selected.
                // 
                // Case 2:
                // If the ListView is multi-select and there are two items selected and the user cntl clicks on one (unselects it).
                // The listview fires only one WinEvent (an EventObjectSelectionRemove) for the 
                // item that was removed.   In this case since there is only one 
                // item left selected UIA should raise ElementSelectedEvent for the remaining item.
                // 
                // If we turn the EventObjectSelectionRemove WinEvent in case 2 into a ElementSelected 
                // event for the remaining element we would end up firing two events for each click in a multi 
                // select list.  This is because the EventObjectSelectionRemove in case 1 is just like 
                // the one case 2.  Except that in case 1 we also get a EventObjectSelection separately so we
                // would end up firing another selected event.
                //
                // It has been decided that it is preferred to receive extra EventObjectSelection events 
                // then receiving EventObjectSelectionRemove events at the wrong time. If two items are selected
                // in a listview and the user clicks on one of them the only event winevent we get is a remove so
                // we have to convert removed winevent to selected event or we would miss an event.  So it better
                // to have multiple events in some case than none when there should be ([....] 9/8/2004).
                //
                if (eventId == NativeMethods.EventObjectSelectionRemove && GetSelectedItemCount(hwnd) == 1)
                {
                    if (MultiSelected(hwnd))
                    {
                        // Change the EventObjectSelectionRemove to an EventObjectSelection.
                        eventId = NativeMethods.EventObjectSelection;
                        idProp = SelectionItemPattern.ElementSelectedEvent;

                        // Change the child id to the selected child.
                        int item = GetStartOfSelectedItems(hwnd);
                        if (item > -1)
                        {
                            idChild = item + 1;
                        }
                    }
                    else
                    {
                        // Since case 2 does not apply to single selection listviews, suppress the
                        // EventObjectSelectionRemove.
                        return;
                    }
                } 
                
                el = wlv.CreateListViewItemCheckIfInGroup(idChild - 1);
            }
            // GridItem case
            else if (eventId == NativeMethods.EventObjectReorder && (automationProperty == GridItemPattern.ColumnProperty || automationProperty == GridItemPattern.RowProperty))
            {
                // GridItem case. We need to recursively call all of the list items
                for (el = wlv.GetFirstChild(); el != null; el = wlv.GetNextSibling(el))
                {
                    el.DispatchEvents(eventId, idProp, idObject, idChild);
                }
                return;
            }
            // Map the WinEvent NameChange to ValueChange to go through the dispatch
            else if (eventId == NativeMethods.EventObjectNameChange)
            {
                el = wlv.CreateListViewItemCheckIfInGroup(idChild - 1);
                eventId = NativeMethods.EventObjectValueChange;
            }
            // Change of state for the check box must generates a StateChange Win Events.
            // Map it to of ObjectChange for the checkbox
            else if (eventId == NativeMethods.EventObjectStateChange && CheckBoxes(hwnd))
            {
                el = wlv.CreateListViewItemCheckIfInGroup(idChild - 1);

                el = ((ProxyFragment)el).GetFirstChild();
                eventId = NativeMethods.EventObjectValueChange;

                // Assert if the assumption that the first child is a check box is false
                System.Diagnostics.Debug.Assert(el is ListViewItemCheckbox);
            }
            // Special case for logical element change for a list view item
            else if ((eventId == NativeMethods.EventObjectDestroy || eventId == NativeMethods.EventObjectCreate) && automationEvent == AutomationElement.StructureChangedEvent)
            {
                ProxySimple parent = wlv;
                bool fGroupView = IsGroupViewEnabled(hwnd);

                // Allways disable the groups as one may have been created or
                // destroyed
                if (fGroupView)
                {
                    // remove groupmanager from collection
                    _groupsCollection.Remove(hwnd);

                    // If it is an object creation, create the element and picks
                    // its parent to invalidate. The parent can be either a group
                    // or  the listview itself.
                    if (eventId == NativeMethods.EventObjectCreate && fGroupView)
                    {
                        // Get the item with the resetted collection of groups (may be null if the group is empty)
                        ProxySimple lvi = wlv.CreateListViewItemCheckIfInGroup(idChild - 1);
                        if (lvi != null)
                            parent = lvi.GetParent();
                    }
                }

                // If the element destroyed is in a group invalidate the whole listview as we have no
                // idea the element was part of before
                // Since children are referenced by position in the tree, addition and removal
                // of items leads to different results when asking properties for the same element
                // On removal, item + 1 is now item!
                // Use Children Invalidated to let the client knows that all the cached children are invalid
                AutomationInteropProvider.RaiseStructureChangedEvent( parent, new StructureChangedEventArgs( StructureChangeType.ChildrenInvalidated, parent.MakeRuntimeId() ) );
                return;
            }
            else
            {
                el = wlv;
            }

            if (el != null)
            {
                el.DispatchEvents(eventId, idProp, idObject, idChild);
            }

            return;
        }
示例#2
0
        internal static IRawElementProviderSimple Create(IntPtr hwnd, int idChild)
        {
            WindowsListView lv = new WindowsListView(hwnd, null, 0);

            if( idChild == 0 )
                return lv;
            else
                return lv.CreateListViewItemCheckIfInGroup (idChild - 1);
        }