@@ -164,12 +164,18 @@ ListView GetListView()
164164 {
165165 listView . DragItemsCompleted -= OnListViewDragItemsCompleted ;
166166 } ) ;
167- listView . Drop += OnListViewDrop ;
167+
168+ listView . DragOver += OnListViewDragOver ;
168169 m_listViewDragOverRevoker . Disposable = Disposable . Create ( ( ) =>
169170 {
170- listView . Drop -= OnListViewDrop ;
171+ listView . DragOver -= OnListViewDragOver ;
171172 } ) ;
172173
174+ listView . Drop += OnListViewDrop ;
175+ m_listViewDropRevoker . Disposable = Disposable . Create ( ( ) =>
176+ {
177+ listView . Drop -= OnListViewDrop ;
178+ } ) ;
173179 listView . DragEnter += OnListViewDragEnter ;
174180 m_listViewDragEnterRevoker . Disposable = Disposable . Create ( ( ) =>
175181 {
@@ -181,11 +187,6 @@ ListView GetListView()
181187 listView . DragLeave -= OnListViewDragLeave ;
182188 } ) ;
183189
184- listView . Drop += OnListViewDrop ;
185- m_listViewDropRevoker . Disposable = Disposable . Create ( ( ) =>
186- {
187- listView . Drop -= OnListViewDrop ;
188- } ) ;
189190
190191 listView . GettingFocus += OnListViewGettingFocus ;
191192 m_listViewGettingFocusRevoker . Disposable = Disposable . Create ( ( ) =>
@@ -1284,156 +1285,162 @@ internal void UpdateTabWidths(bool shouldUpdateWidths = true, bool fillAllAvaila
12841285 // Note: can be infinite
12851286 var availableWidth = m_previousAvailableSize . Width - widthTaken ;
12861287
1287- // Size can be 0 when window is first created; in that case, skip calculations; we'll get a new size soon
1288- if ( availableWidth > 0 )
1288+ // TODO: UNO workaround: Handles layout timing difference to WinUI
1289+ // After ListView drag&drop, MeasureOverride can call this before ActualWidth of LeftContentColumn is calculated.
1290+ // Reading ActualWidth might return Infinity, causing availableWidth=-Infinity.
1291+ // This check prevents applying NaN to TabViewItem widths when layout is in this intermediate async state.
1292+ // The layout corrects itself in a subsequent pass (e.g., via SizeChanged/PointerExited).
1293+ // Part of: https://github.com/unoplatform/uno/issues/21762
1294+ if ( availableWidth <= 0 )
12891295 {
1290- if ( TabWidthMode == TabViewWidthMode . Equal )
1291- {
1296+ return ;
1297+ }
12921298
1293- var minTabWidth = ( double ) SharedHelpers . FindInApplicationResources ( c_tabViewItemMinWidthName , c_tabMinimumWidth ) ;
1299+ if ( TabWidthMode == TabViewWidthMode . Equal )
1300+ {
1301+ var minTabWidth = ( double ) SharedHelpers . FindInApplicationResources ( c_tabViewItemMinWidthName , c_tabMinimumWidth ) ;
12941302
1295- // If we should fill all of the available space, use scrollviewer dimensions
1296- var padding = Padding ;
1303+ // If we should fill all of the available space, use scrollviewer dimensions
1304+ var padding = Padding ;
12971305
1298- double headerWidth = 0.0 ;
1299- double footerWidth = 0.0 ;
1300- if ( m_itemsPresenter is { } itemsPresenter )
1306+ double headerWidth = 0.0 ;
1307+ double footerWidth = 0.0 ;
1308+ if ( m_itemsPresenter is { } itemsPresenter )
1309+ {
1310+ if ( itemsPresenter . Header is FrameworkElement header )
13011311 {
1302- if ( itemsPresenter . Header is FrameworkElement header )
1303- {
1304- headerWidth = header . ActualWidth ;
1305- }
1306- if ( itemsPresenter . Footer is FrameworkElement footer )
1307- {
1308- footerWidth = footer . ActualWidth ;
1309- }
1312+ headerWidth = header . ActualWidth ;
13101313 }
1311-
1312- if ( fillAllAvailableSpace )
1314+ if ( itemsPresenter . Footer is FrameworkElement footer )
13131315 {
1314- // Calculate the proportional width of each tab given the width of the ScrollViewer.
1315- var tabWidthForScroller = ( availableWidth - ( padding . Left + padding . Right + headerWidth + footerWidth ) ) / tabCount ;
1316- tabWidth = Math . Clamp ( tabWidthForScroller , minTabWidth , maxTabWidth ) ;
1316+ footerWidth = footer . ActualWidth ;
13171317 }
1318- else
1319- {
1320- double availableTabViewSpace = ( tabColumn . ActualWidth - ( padding . Left + padding . Right + headerWidth + footerWidth ) ) ;
1321- var increaseButton = m_scrollIncreaseButton ;
1322- if ( increaseButton != null )
1323- {
1324- if ( increaseButton . Visibility == Visibility . Visible )
1325- {
1326- availableTabViewSpace -= increaseButton . ActualWidth ;
1327- }
1328- }
1318+ }
13291319
1330- var decreaseButton = m_scrollDecreaseButton ;
1331- if ( decreaseButton != null )
1320+ if ( fillAllAvailableSpace )
1321+ {
1322+ // Calculate the proportional width of each tab given the width of the ScrollViewer.
1323+ var tabWidthForScroller = ( availableWidth - ( padding . Left + padding . Right + headerWidth + footerWidth ) ) / tabCount ;
1324+ tabWidth = Math . Clamp ( tabWidthForScroller , minTabWidth , maxTabWidth ) ;
1325+ }
1326+ else
1327+ {
1328+ double availableTabViewSpace = ( tabColumn . ActualWidth - ( padding . Left + padding . Right + headerWidth + footerWidth ) ) ;
1329+ var increaseButton = m_scrollIncreaseButton ;
1330+ if ( increaseButton != null )
1331+ {
1332+ if ( increaseButton . Visibility == Visibility . Visible )
13321333 {
1333- if ( decreaseButton . Visibility == Visibility . Visible )
1334- {
1335- availableTabViewSpace -= decreaseButton . ActualWidth ;
1336- }
1334+ availableTabViewSpace -= increaseButton . ActualWidth ;
13371335 }
1338-
1339- // Use current size to update items to fill the currently occupied space
1340- var tabWidthUnclamped = availableTabViewSpace / tabCount ;
1341- tabWidth = Math . Clamp ( tabWidthUnclamped , minTabWidth , maxTabWidth ) ;
13421336 }
13431337
1344-
1345- // Size tab column to needed size
1346- tabColumn . MaxWidth = availableWidth + headerWidth + footerWidth ;
1347- var requiredWidth = tabWidth * tabCount + headerWidth + footerWidth + padding . Left + padding . Right ;
1348- if ( requiredWidth > availableWidth )
1338+ var decreaseButton = m_scrollDecreaseButton ;
1339+ if ( decreaseButton != null )
13491340 {
1350- tabColumn . Width = GridLengthHelper . FromPixels ( availableWidth ) ;
1351- var listview = m_listView ;
1352- if ( listview != null )
1341+ if ( decreaseButton . Visibility == Visibility . Visible )
13531342 {
1354- ScrollViewer . SetHorizontalScrollBarVisibility ( listview , ScrollBarVisibility . Visible ) ;
1355- UpdateScrollViewerDecreaseAndIncreaseButtonsViewState ( ) ;
1343+ availableTabViewSpace -= decreaseButton . ActualWidth ;
13561344 }
13571345 }
1358- else
1346+
1347+ // Use current size to update items to fill the currently occupied space
1348+ var tabWidthUnclamped = availableTabViewSpace / tabCount ;
1349+ tabWidth = Math . Clamp ( tabWidthUnclamped , minTabWidth , maxTabWidth ) ;
1350+ }
1351+
1352+
1353+ // Size tab column to needed size
1354+ tabColumn . MaxWidth = availableWidth + headerWidth + footerWidth ;
1355+ var requiredWidth = tabWidth * tabCount + headerWidth + footerWidth + padding . Left + padding . Right ;
1356+ if ( requiredWidth > availableWidth )
1357+ {
1358+ tabColumn . Width = GridLengthHelper . FromPixels ( availableWidth ) ;
1359+ var listview = m_listView ;
1360+ if ( listview != null )
13591361 {
1360- // If we're dragging over the TabView, we need to set the width to a specific value,
1361- // since we want it to be larger than the items actually in it in order to accommodate
1362- // the item being dragged into the TabView. Otherwise, we can just set its width to Auto.
1363- tabColumn . Width =
1364- m_isItemDraggedOver ?
1365- GridLengthHelper . FromPixels ( requiredWidth ) :
1366- GridLengthHelper . FromValueAndType ( 1.0 , GridUnitType . Auto ) ;
1367-
1368- var listview = m_listView ;
1369- var tabListView = m_listView as TabViewListView ;
1370- if ( listview != null )
1371- {
1372- if ( shouldUpdateWidths && fillAllAvailableSpace )
1373- {
1374- ScrollViewer . SetHorizontalScrollBarVisibility ( listview , ScrollBarVisibility . Hidden ) ;
1375- }
1376- else
1377- {
1378- var decreaseButton = m_scrollDecreaseButton ;
1379- if ( decreaseButton != null )
1380- {
1381- decreaseButton . IsEnabled = false ;
1382- }
1383- var increaseButton = m_scrollIncreaseButton ;
1384- if ( increaseButton != null )
1385- {
1386- increaseButton . IsEnabled = false ;
1387- }
1388- }
1389- }
1362+ ScrollViewer . SetHorizontalScrollBarVisibility ( listview , ScrollBarVisibility . Visible ) ;
1363+ UpdateScrollViewerDecreaseAndIncreaseButtonsViewState ( ) ;
13901364 }
13911365 }
13921366 else
13931367 {
1394- // Case: TabWidthMode "Compact" or "SizeToContent"
1395- tabColumn . MaxWidth = availableWidth ;
1368+ // If we're dragging over the TabView, we need to set the width to a specific value,
1369+ // since we want it to be larger than the items actually in it in order to accommodate
1370+ // the item being dragged into the TabView. Otherwise, we can just set its width to Auto.
1371+ tabColumn . Width =
1372+ m_isItemDraggedOver ?
1373+ GridLengthHelper . FromPixels ( requiredWidth ) :
1374+ GridLengthHelper . FromValueAndType ( 1.0 , GridUnitType . Auto ) ;
1375+
13961376 var listview = m_listView ;
13971377 var tabListView = m_listView as TabViewListView ;
13981378 if ( listview != null )
13991379 {
1400- // When an item is being dragged over, we need to reserve extra space for the potential new tab,
1401- // so we can't rely on auto sizing in that case. However, the ListView expands to the size of the column,
1402- // so we need to store the value lest we keep expanding the width of the column every time we call this method.
1403- if ( m_isItemDraggedOver )
1380+ if ( shouldUpdateWidths && fillAllAvailableSpace )
14041381 {
1405- if ( ! m_expandedWidthForDragOver . HasValue )
1406- {
1407- m_expandedWidthForDragOver = listview . ActualWidth + maxTabWidth ;
1408- }
1409-
1410- tabColumn . Width = GridLengthHelper . FromPixels ( ( double ) m_expandedWidthForDragOver ) ;
1382+ ScrollViewer . SetHorizontalScrollBarVisibility ( listview , ScrollBarVisibility . Hidden ) ;
14111383 }
14121384 else
14131385 {
1414- if ( m_expandedWidthForDragOver . HasValue )
1386+ var decreaseButton = m_scrollDecreaseButton ;
1387+ if ( decreaseButton != null )
1388+ {
1389+ decreaseButton . IsEnabled = false ;
1390+ }
1391+ var increaseButton = m_scrollIncreaseButton ;
1392+ if ( increaseButton != null )
14151393 {
1416- m_expandedWidthForDragOver = null ;
1394+ increaseButton . IsEnabled = false ;
14171395 }
1396+ }
1397+ }
1398+ }
1399+ }
1400+ else
1401+ {
1402+ // Case: TabWidthMode "Compact" or "SizeToContent"
1403+ tabColumn . MaxWidth = availableWidth ;
1404+ var listview = m_listView ;
1405+ var tabListView = m_listView as TabViewListView ;
1406+ if ( listview != null )
1407+ {
1408+ // When an item is being dragged over, we need to reserve extra space for the potential new tab,
1409+ // so we can't rely on auto sizing in that case. However, the ListView expands to the size of the column,
1410+ // so we need to store the value lest we keep expanding the width of the column every time we call this method.
1411+ if ( m_isItemDraggedOver )
1412+ {
1413+ if ( ! m_expandedWidthForDragOver . HasValue )
1414+ {
1415+ m_expandedWidthForDragOver = listview . ActualWidth + maxTabWidth ;
1416+ }
14181417
1419- tabColumn . Width = GridLengthHelper . FromValueAndType ( 1.0 , GridUnitType . Auto ) ;
1418+ tabColumn . Width = GridLengthHelper . FromPixels ( ( double ) m_expandedWidthForDragOver ) ;
1419+ }
1420+ else
1421+ {
1422+ if ( m_expandedWidthForDragOver . HasValue )
1423+ {
1424+ m_expandedWidthForDragOver = null ;
14201425 }
14211426
1427+ tabColumn . Width = GridLengthHelper . FromValueAndType ( 1.0 , GridUnitType . Auto ) ;
1428+ }
1429+
14221430
1423- listview . MaxWidth = availableWidth ;
1431+ listview . MaxWidth = availableWidth ;
14241432
1425- // Calculate if the scroll buttons should be visible.
1426- var itemsPresenter = m_itemsPresenter ;
1427- if ( itemsPresenter != null )
1433+ // Calculate if the scroll buttons should be visible.
1434+ var itemsPresenter = m_itemsPresenter ;
1435+ if ( itemsPresenter != null )
1436+ {
1437+ var visible = itemsPresenter . ActualWidth > availableWidth ;
1438+ ScrollViewer . SetHorizontalScrollBarVisibility ( listview , visible
1439+ ? ScrollBarVisibility . Visible
1440+ : ScrollBarVisibility . Hidden ) ;
1441+ if ( visible )
14281442 {
1429- var visible = itemsPresenter . ActualWidth > availableWidth ;
1430- ScrollViewer . SetHorizontalScrollBarVisibility ( listview , visible
1431- ? ScrollBarVisibility . Visible
1432- : ScrollBarVisibility . Hidden ) ;
1433- if ( visible )
1434- {
1435- UpdateScrollViewerDecreaseAndIncreaseButtonsViewState ( ) ;
1436- }
1443+ UpdateScrollViewerDecreaseAndIncreaseButtonsViewState ( ) ;
14371444 }
14381445 }
14391446 }
0 commit comments