@@ -20,6 +20,7 @@ class PopupListWatcher : IDisposable
2020 public bool IsVisible { get ; set ; } = false ;
2121 public string SelectedItemText { get ; set ; } = string . Empty ;
2222 public Rect SelectedItemBounds { get ; set ; } = Rect . Empty ;
23+ public bool HasVerticalScrollBar { get ; set ; } = false ;
2324 public IntPtr PopupListHandle => _hwndPopupList ;
2425
2526 SynchronizationContext _syncContextAuto ;
@@ -85,7 +86,7 @@ void _windowWatcher_PopupListWindowChanged(object sender, WindowWatcher.WindowCh
8586 case WindowWatcher . WindowChangedEventArgs . ChangeType . Hide :
8687 Logger . WindowWatcher . Verbose ( $ "PopupList window hide") ;
8788 IsVisible = false ;
88- UpdateSelectedItem ( _selectedItem ) ;
89+ UpdateSelectedItem ( _selectedItem , false ) ;
8990 break ;
9091 case WindowWatcher . WindowChangedEventArgs . ChangeType . Focus :
9192 case WindowWatcher . WindowChangedEventArgs . ChangeType . Unfocus :
@@ -128,7 +129,8 @@ void PopupListBoundsChanged(object sender, AutomationPropertyChangedEventArgs e)
128129 if ( IsVisible && _selectedItem != null )
129130 {
130131 // Debug.Print($">>>> PopupListWatcher.LocationChanged on thread {Thread.CurrentThread.ManagedThreadId}");
131- UpdateSelectedItem ( _selectedItem ) ;
132+ // We assume the scroll bar presence has not changed
133+ UpdateSelectedItem ( _selectedItem , HasVerticalScrollBar ) ;
132134 }
133135
134136 //_syncContextAuto.Post(delegate
@@ -165,7 +167,12 @@ void PopupListBoundsChanged(object sender, AutomationPropertyChangedEventArgs e)
165167 void PopupListElementSelectedHandler ( object sender , AutomationEventArgs e )
166168 {
167169 Logger . WindowWatcher . Verbose ( $ "PopupList PopupListElementSelectedHandler on thread { Thread . CurrentThread . ManagedThreadId } ") ;
168- UpdateSelectedItem ( sender as AutomationElement ) ;
170+ var selectedItem = ( AutomationElement ) sender ;
171+ // CONSIDER: Maybe monitor changes to scrollbar as an event? (for performance)
172+ var walker = TreeWalker . ControlViewWalker ;
173+ var list = walker . GetParent ( walker . GetParent ( selectedItem ) ) ;
174+ var hasVerticalScrollBar = ( bool ) list . GetCurrentPropertyValue ( AutomationElement . IsScrollPatternAvailableProperty ) ;
175+ UpdateSelectedItem ( selectedItem , hasVerticalScrollBar ) ;
169176 }
170177
171178 // Runs on our automation thread
@@ -202,12 +209,14 @@ void UpdateSelectedItem()
202209 if ( listElement != null )
203210 {
204211 var selectionPattern = listElement . GetCurrentPattern ( SelectionPattern . Pattern ) as SelectionPattern ;
212+ // CONSIDER: We might dig in a big more (e.g. is horizontal scrolling possible?)
213+ var hasVerticalScrollBar = ( bool ) listElement . GetCurrentPropertyValue ( AutomationElement . IsScrollPatternAvailableProperty ) ;
205214 var currentSelection = selectionPattern . Current . GetSelection ( ) ;
206215 if ( currentSelection . Length > 0 )
207216 {
208217 try
209218 {
210- UpdateSelectedItem ( currentSelection [ 0 ] ) ;
219+ UpdateSelectedItem ( currentSelection [ 0 ] , hasVerticalScrollBar ) ;
211220 }
212221 catch ( Exception ex )
213222 {
@@ -221,98 +230,9 @@ void UpdateSelectedItem()
221230 }
222231 }
223232
224- //// TODO: This should be exposed as an event and popup resize should be elsewhere
225- //// Runs on an automation event thread
226- //void PopupListStructureChangedHandler(object sender, StructureChangedEventArgs e)
227- //{
228- // Debug.Print($">>>> PopupListWatcher.PopupListStructureChangedHandler ({e.StructureChangeType}) on thread {Thread.CurrentThread.ManagedThreadId}");
229- // // Debug.WriteLine($">>> PopupList structure changed - {e.StructureChangeType}");
230- // // CONSIDER: Others too?
231- // if (e.StructureChangeType == StructureChangeType.ChildAdded)
232- // {
233- // var functionList = sender as AutomationElement;
234-
235- // //var listRect = (Rect)functionList.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty);
236-
237- // var listElement = functionList.FindFirst(TreeScope.Children, Condition.TrueCondition);
238- // if (listElement != null)
239- // {
240- // // Debug.Print($">>>> PopupListWatcher.PopupListStructureChangedHandler Post - Children Found !!!");
241-
242- // _popupListList = listElement;
243-
244- // // TODO: Move this code!
245- // // TestMoveWindow(_popupListList, (int)listRect.X, (int)listRect.Y);
246- // // TestMoveWindow(functionList, 0, 0);
247-
248- // // If the _popupListList automation element is no plonger valid then we seem to get a InvalidPattern exception here.
249- // var selPat = _popupListList.GetCurrentPattern(SelectionPattern.Pattern) as SelectionPattern;
250- // Debug.Assert(selPat != null);
251-
252- // // CONSIDER: Send might be a bit disruptive here / might not be necessary...
253- // // _syncContextAuto.Send( _ =>
254- // //{
255- // try
256- // {
257- // Debug.Print("POPUPLISTWATCHER WINDOW SELECTION EVENT HANDLER ADDED");
258- // Automation.AddAutomationEventHandler(
259- // SelectionItemPattern.ElementSelectedEvent, _popupListList, TreeScope.Descendants /* was .Children */, PopupListElementSelectedHandler);
260- // }
261- // catch (Exception ex)
262- // {
263- // Debug.Print("Error during AddAutomationEventHandler! " + ex);
264- // }
265- // //}, null);
266-
267- // // Update the current selection, if any
268- // var curSel = selPat.Current.GetSelection();
269- // if (curSel.Length > 0)
270- // {
271- // try
272- // {
273- // UpdateSelectedItem(curSel[0]);
274- // }
275- // catch (Exception ex)
276- // {
277- // Debug.Print("Error during UpdateSelected! " + ex);
278- // }
279- // }
280- // }
281- // else
282- // {
283- // Debug.Print($">>>> PopupListWatcher.PopupListStructureChangedHandler Post - No Children Found ??? ");
284- // Debug.WriteLine("ERROR!!! Structure changed but no children anymore.");
285- // }
286- // }
287- // else if (e.StructureChangeType == StructureChangeType.ChildRemoved)
288- // {
289- // if (_popupListList != null)
290- // {
291- // var selPat = _popupListList.GetCurrentPattern(SelectionPattern.Pattern) as SelectionPattern;
292- // Debug.Assert(selPat != null);
293- // // CONSIDER: Send might be a bit disruptive here / might not be necessary...
294- // //_syncContextAuto.Send( _ =>
295- // //{
296- // try
297- // {
298- // Debug.Print("POPUPLISTWATCHER WINDOW SELECTION EVENT HANDLER REMOVED");
299- // Automation.RemoveAutomationEventHandler(SelectionItemPattern.ElementSelectedEvent, _popupListList, PopupListElementSelectedHandler);
300- // }
301- // catch (Exception ex)
302- // {
303- // Debug.Print("Error during RemoveAutomationEventHandler! " + ex);
304- // }
305- // //}, null);
306- // _popupListList = null;
307- // }
308- // _selectedItem = null;
309- // OnSelectedItemChanged();
310- // }
311- //}
312-
313233 // Can run on our automation thread or on any automation event thread (which is also allowed to read properties)
314234 // But might fail, if the newSelectedItem is already gone by the time we run...
315- void UpdateSelectedItem ( AutomationElement newSelectedItem )
235+ void UpdateSelectedItem ( AutomationElement newSelectedItem , bool hasVerticalScrollBar )
316236 {
317237 // Debug.Print($"POPUPLISTWATCHER WINDOW CURRENT SELECTION {newSelectedItem}");
318238
@@ -353,13 +273,14 @@ void UpdateSelectedItem(AutomationElement newSelectedItem)
353273 SelectedItemBounds = selectedItemBounds ;
354274 // Debug.Print($"SelectedItemBounds: {SelectedItemBounds}");
355275 }
276+ HasVerticalScrollBar = hasVerticalScrollBar ;
356277 OnSelectedItemChanged ( ) ;
357278 }
358279
359280 // Raises the event on the automation thread (but the SyncContext.Post here is redundant)
360281 void OnSelectedItemChanged ( )
361282 {
362- Logger . WindowWatcher . Verbose ( $ "PopupList SelectedItemChanged { SelectedItemText } ") ;
283+ Logger . WindowWatcher . Verbose ( $ "PopupList SelectedItemChanged { SelectedItemText } ( { ( HasVerticalScrollBar ? "Scroll" : "NoScroll" ) } ) ") ;
363284 _syncContextAuto . Post ( _ => SelectedItemChanged ( this , EventArgs . Empty ) , null ) ;
364285 }
365286
0 commit comments