public static void ArrangeColumns(SpreadsheetView spreadsheet) { if (spreadsheet == null) return; var columns = new List<IColumn>(); Action<SpreadsheetColumnCollection, List<IColumn>> addColumns = null; addColumns = (collection, list) => { if (collection == null) return; foreach (var column in collection) { var stackColumn = column as IStackColumn; if (stackColumn != null) //if (column.IsParent) //if (stackColumn is IDetailColumn && stackColumn.SubColumns.Count == 0) // list.Add(stackColumn); //else { var columnPresenter = column.ColumnPresenter as StackColumnHeader; if (columnPresenter != null) { if (!columnPresenter.ShowSubColumns) list.Add(column); else addColumns(stackColumn.SubColumns, list); } else addColumns(stackColumn.SubColumns, list); } else list.Add(column); } }; addColumns(spreadsheet.Columns, columns); if (columns.Count == 0) return; foreach (IColumn column in columns) { if (column.ColumnPresenter != null) { if (!column.WidthBeforeArrangement.HasValue) column.WidthBeforeArrangement = column.ColumnPresenter.DesiredSize.Width; else if (!double.IsNaN(column.Width)) column.WidthBeforeArrangement = ((column.WidthBeforeArrangement + column.Width) / 2); } } var columnPresenterList = columns.Where(x => x.ColumnPresenter != null).Select(x => x.ColumnPresenter).ToList(); var spreadSheetWidth = spreadsheet.CalculateSpreadsheetWidth(); var totalDesiredWidth = columnPresenterList.Sum(x => { var sourceColumn = x.DataContext as IColumn; return sourceColumn != null && sourceColumn.WidthBeforeArrangement.HasValue ? Math.Min(sourceColumn.WidthBeforeArrangement.Value, x.DesiredSize.Width) : x.DesiredSize.Width; }); var totalAvailableWidth = spreadSheetWidth; if (spreadsheet.ParentSpreadsheet == null) { var rowIndicatorColumns = columns.Where(x => x.IsRowIndicator); if (rowIndicatorColumns.Any()) { columnPresenterList.RemoveAll(x => ((IColumn)x.DataContext).IsRowIndicator); var rowIndicatorColumnsWidth = rowIndicatorColumns.Sum(x => x.Width); totalDesiredWidth = totalDesiredWidth - rowIndicatorColumnsWidth; totalAvailableWidth = spreadSheetWidth - rowIndicatorColumnsWidth; } } if (totalDesiredWidth > totalAvailableWidth) { var midWidth = totalAvailableWidth / columnPresenterList.Count; var columnDict = new Dictionary<IColumn, WidthRestrictions>(); foreach (var child in columnPresenterList) { if (child.DataContext is IColumn) { var column = child.DataContext as IColumn; var defaultRange = new WidthRestrictions(column.MinWidth, column.MaxWidth); defaultRange.UpdateValue(column.WidthBeforeArrangement.HasValue ? Math.Min(column.WidthBeforeArrangement.Value, child.DesiredSize.Width) : child.DesiredSize.Width); columnDict.Add(column, defaultRange); } } var regularColumns = columnDict.Where(x => x.Value.DesiredWidth <= midWidth).ToList(); var wideColumns = columnDict.Where(x => x.Value.DesiredWidth > midWidth).ToList(); var totalMinWidth = columnDict.Select(x => x.Value.DesiredWidth > midWidth ? midWidth : x.Value.DesiredWidth).Sum(); var availableWidthLeft = totalAvailableWidth - totalMinWidth; var wideColumnsTotalWidth = wideColumns.Sum(x => x.Value.DesiredWidth); if (availableWidthLeft < wideColumnsTotalWidth) { var availableWidth80 = Math.Ceiling(availableWidthLeft * 0.8); var availableWidth20 = Math.Ceiling(availableWidthLeft * 0.2); foreach (var col in wideColumns.ToList()) { var currentValue = columnDict[col.Key].DesiredWidth; var newPossibleValue = Math.Ceiling(midWidth + ((col.Value.DesiredWidth / wideColumnsTotalWidth) * availableWidth80)); if ((newPossibleValue < 150) && (currentValue > newPossibleValue * 2)) columnDict[col.Key].UpdateValue(newPossibleValue * 2); else columnDict[col.Key].UpdateValue(newPossibleValue); } var extraWidth = availableWidth20 / regularColumns.Count; foreach (var col in regularColumns.ToList()) { columnDict[col.Key].UpdateValue(columnDict[col.Key].DesiredWidth + extraWidth); } } else if (availableWidthLeft > wideColumnsTotalWidth) { var extraWidth = (availableWidthLeft - wideColumnsTotalWidth) / columnDict.Count; foreach (var col in regularColumns.ToList()) { columnDict[col.Key].UpdateValue(columnDict[col.Key].DesiredWidth + extraWidth); } foreach (var col in wideColumns.ToList()) { columnDict[col.Key].UpdateValue(midWidth + ((col.Value.DesiredWidth / wideColumnsTotalWidth) * availableWidthLeft) + extraWidth); } } foreach (var item in columnDict) { if (item.Key.ColumnPanelLoaded) item.Key.Width = Math.Ceiling(item.Value.DesiredWidth);//Math.Round(item.Value.DesiredWidth, 0); } foreach (var col in spreadsheet.Columns.Where(x => x.IsParent)) { col.UpdateAutoSize(); } var roundingInaccuracy = spreadSheetWidth - columns.Sum(x => x.Width); if (wideColumns.Any() && roundingInaccuracy > 0) { columnDict.FirstOrDefault(x => x.Key == wideColumns.First().Key).Key.Width += roundingInaccuracy; } } else { var extraSpace = (totalAvailableWidth - totalDesiredWidth) / columns.Count(x => !x.IsRowIndicator); foreach (var column in columns.Where(x => !x.IsRowIndicator)) { if (column.ColumnPanelLoaded && (double.IsNaN(column.Width) || column.WidthBeforeArrangement.HasValue)) column.Width = Math.Ceiling((column.WidthBeforeArrangement.HasValue ? Math.Min(column.WidthBeforeArrangement.Value, column.ColumnPresenter.DesiredSize.Width) : column.ColumnPresenter.DesiredSize.Width) + extraSpace); else column.Width += extraSpace; } } }