WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 80eacd5

Browse files
authored
Merge pull request #21789 from unoplatform/mergify/bp/release/stable/6.4/pr-21695
fix: `TabView` avoid resizing `TabViewItem` headers during drag-and-drop reorder (backport #21695)
2 parents 15aaec6 + 5e7980b commit 80eacd5

File tree

1 file changed

+126
-119
lines changed

1 file changed

+126
-119
lines changed

src/Uno.UI/UI/Xaml/Controls/TabView/TabView.cs

Lines changed: 126 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)