} // ListViewUnloaded // ---------------------------------------------------------------------- private void ThumbPreviewMouseMove(object sender, MouseEventArgs e) { if (!(sender is Thumb thumb)) { return; } var gridViewColumn = FindParentColumn(thumb); if (gridViewColumn == null) { return; } // suppress column resizing for proportional, fixed and range fill columns if (ProportionalColumn.IsProportionalColumn(gridViewColumn) || FixedColumn.IsFixedColumn(gridViewColumn) || IsFillColumn(gridViewColumn)) { thumb.Cursor = null; return; } // check range column bounds if (thumb.IsMouseCaptured && RangeColumn.IsRangeColumn(gridViewColumn)) { var minWidth = RangeColumn.GetRangeMinWidth(gridViewColumn); var maxWidth = RangeColumn.GetRangeMaxWidth(gridViewColumn); if (minWidth.HasValue && maxWidth.HasValue && minWidth > maxWidth) { return; // invalid case } if (_resizeCursor == null) { _resizeCursor = thumb.Cursor; // save the resize cursor } if (minWidth.HasValue && gridViewColumn.Width <= minWidth.Value) { thumb.Cursor = Cursors.No; } else if (maxWidth.HasValue && gridViewColumn.Width >= maxWidth.Value) { thumb.Cursor = Cursors.No; } else { thumb.Cursor = _resizeCursor; // between valid min/max } } } // ThumbPreviewMouseMove
} // ThumbPreviewMouseMove // ---------------------------------------------------------------------- private void ThumbPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) { var thumb = (Thumb)sender; var gridViewColumn = FindParentColumn(thumb); if (gridViewColumn == null) { throw new InvalidOperationException("Could not find parent column"); } // suppress column resizing for proportional, fixed and range fill columns if (ProportionalColumn.IsProportionalColumn(gridViewColumn) || FixedColumn.IsFixedColumn(gridViewColumn) || IsFillColumn(gridViewColumn)) { e.Handled = true; } } // ThumbPreviewMouseLeftButtonDown
} // Refresh // ---------------------------------------------------------------------- private void RegisterEvents(DependencyObject start) { for (var i = 0; i < VisualTreeHelper.GetChildrenCount(start); i++) { var childVisual = (Visual)VisualTreeHelper.GetChild(start, i); if (childVisual is Thumb thumb) { var gridViewColumn = FindParentColumn(childVisual); if (gridViewColumn != null) { if (ProportionalColumn.IsProportionalColumn(gridViewColumn) || FixedColumn.IsFixedColumn(gridViewColumn) || IsFillColumn(gridViewColumn)) { thumb.IsHitTestVisible = false; } else { thumb.PreviewMouseMove += ThumbPreviewMouseMove; thumb.PreviewMouseLeftButtonDown += ThumbPreviewMouseLeftButtonDown; DependencyPropertyDescriptor.FromProperty(GridViewColumn.WidthProperty, typeof(GridViewColumn)) .AddValueChanged(gridViewColumn, GridColumnWidthChanged); } } } else if (childVisual is GridViewColumnHeader columnHeader) { columnHeader.SizeChanged += GridColumnHeaderSizeChanged; } else if (_scrollViewer == null && childVisual is ScrollViewer) { _scrollViewer = (ScrollViewer)childVisual; _scrollViewer.ScrollChanged += ScrollViewerScrollChanged; // assume we do the regulation of the horizontal scrollbar _scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden; _scrollViewer.VerticalScrollBarVisibility = VerticalScrollBarVisibility; } RegisterEvents(childVisual); // recursive } } // RegisterEvents
} // ThumbPreviewMouseLeftButtonDown // ---------------------------------------------------------------------- private void GridColumnWidthChanged(object sender, EventArgs e) { if (!_loaded) { return; } var gridViewColumn = (GridViewColumn)sender; if (gridViewColumn == null) { throw new ArgumentNullException(nameof(sender)); } // suppress column resizing for proportional and fixed columns if (ProportionalColumn.IsProportionalColumn(gridViewColumn) || FixedColumn.IsFixedColumn(gridViewColumn)) { return; } // ensure range column within the bounds if (RangeColumn.IsRangeColumn(gridViewColumn)) { // special case: auto column width - maybe conflicts with min/max range if (gridViewColumn.Width.Equals(double.NaN)) { _autoSizedColumn = gridViewColumn; return; // handled by the change header size event } // ensure column bounds if (Math.Abs(SetRangeColumnToBounds(gridViewColumn) - 0) > ZeroWidthRange) { return; } } DoResizeColumns(); } // GridColumnWidthChanged
} // RegisterEvents // ---------------------------------------------------------------------- private void UnregisterEvents(DependencyObject start) { for (var i = 0; i < VisualTreeHelper.GetChildrenCount(start); i++) { var childVisual = (Visual)VisualTreeHelper.GetChild(start, i); if (childVisual is Thumb) { var gridViewColumn = FindParentColumn(childVisual); if (gridViewColumn != null) { var thumb = (Thumb)childVisual; if (ProportionalColumn.IsProportionalColumn(gridViewColumn) || FixedColumn.IsFixedColumn(gridViewColumn) || IsFillColumn(gridViewColumn)) { thumb.IsHitTestVisible = true; } else { thumb.PreviewMouseMove -= ThumbPreviewMouseMove; thumb.PreviewMouseLeftButtonDown -= ThumbPreviewMouseLeftButtonDown; DependencyPropertyDescriptor.FromProperty(GridViewColumn.WidthProperty, typeof(GridViewColumn)) .RemoveValueChanged(gridViewColumn, GridColumnWidthChanged); } } } else if (childVisual is GridViewColumnHeader columnHeader) { columnHeader.SizeChanged -= GridColumnHeaderSizeChanged; } else if (_scrollViewer == null && childVisual is ScrollViewer viewer) { _scrollViewer = viewer; _scrollViewer.ScrollChanged -= ScrollViewerScrollChanged; } UnregisterEvents(childVisual); // recursive } } // UnregisterEvents
} // InitColumns // ---------------------------------------------------------------------- protected virtual void ResizeColumns() { if (!(ListView.View is GridView view) || view.Columns.Count == 0) { return; } // listview width var actualWidth = double.PositiveInfinity; if (_scrollViewer != null) { actualWidth = _scrollViewer.ViewportWidth; } if (double.IsInfinity(actualWidth)) { actualWidth = ListView.ActualWidth; } if (double.IsInfinity(actualWidth) || actualWidth <= 0) { return; } double resizeableRegionCount = 0; double otherColumnsWidth = 0; // determine column sizes foreach (var gridViewColumn in view.Columns) { if (ProportionalColumn.IsProportionalColumn(gridViewColumn)) { var proportionalWidth = ProportionalColumn.GetProportionalWidth(gridViewColumn); if (proportionalWidth != null) { resizeableRegionCount += proportionalWidth.Value; } } else { otherColumnsWidth += gridViewColumn.ActualWidth; } } if (resizeableRegionCount <= 0) { // no proportional columns present: commit the regulation to the scroll viewer if (_scrollViewer != null) { _scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto; } // search the first fill column GridViewColumn?fillColumn = null; for (var i = 0; i < view.Columns.Count; i++) { var gridViewColumn = view.Columns[i]; if (IsFillColumn(gridViewColumn)) { fillColumn = gridViewColumn; break; } } if (fillColumn != null) { var otherColumnsWithoutFillWidth = otherColumnsWidth - fillColumn.ActualWidth; var fillWidth = actualWidth - otherColumnsWithoutFillWidth; if (fillWidth > 0) { var minWidth = RangeColumn.GetRangeMinWidth(fillColumn); var maxWidth = RangeColumn.GetRangeMaxWidth(fillColumn); var setWidth = !(minWidth.HasValue && fillWidth < minWidth.Value); if (maxWidth.HasValue && fillWidth > maxWidth.Value) { setWidth = false; } if (setWidth) { if (_scrollViewer != null) { _scrollViewer.HorizontalScrollBarVisibility = ScrollBarVisibility.Hidden; } fillColumn.Width = fillWidth; } } } return; } var resizeableColumnsWidth = actualWidth - otherColumnsWidth; if (resizeableColumnsWidth <= 0) { return; // missing space } // resize columns var resizeableRegionWidth = resizeableColumnsWidth / resizeableRegionCount; foreach (var gridViewColumn in view.Columns) { if (ProportionalColumn.IsProportionalColumn(gridViewColumn)) { var proportionalWidth = ProportionalColumn.GetProportionalWidth(gridViewColumn); if (proportionalWidth != null) { gridViewColumn.Width = proportionalWidth.Value * resizeableRegionWidth; } } } } // ResizeColumns