Требование: Наше требование — нарисовать пустую сетку (таблицу со строками и столбцами) поверх таблиц, представленных на изображении, и для одного изображения может быть несколько сеток. Все сетки должны быть настраиваемыми, и мы можем добавить разделитель строк и разделитель столбцов по щелчку кнопки мыши в сетке. Определения сеток, миниатюр и строк и столбцов создаются на основе кода.
Проблема: Если создано определение столбца или строки, положение ползунка сетки изменяется и он перемещается в первый столбец первой строки, а не остается статическим во внешней сетке. Изменяется положение верхнего, левого, правого и нижнего большого пальца. Можете ли вы помочь нам в этом вопросе?
КСАМЛ:
<Grid Name = "MainGrid" Background = "Gray" MouseDown = "MainGrid_MouseDown" MouseMove = "MainGrid_MouseMove" MouseUp = "MainGrid_MouseUp">
<Image x:Name = "imgDisplay" Source = "{Binding ImagePath, RelativeSource = {RelativeSource AncestorType=UserControl}}" Stretch = "None"/>
<StackPanel Orientation = "Horizontal" HorizontalAlignment = "Right" VerticalAlignment = "Top" Margin = "10" Cursor = "Hand">
<StackPanel.Background>
<LinearGradientBrush EndPoint = "0.5,1" StartPoint = "0.5,0">
<GradientStop Color = "Black"/>
<GradientStop Color = "#FF086B69" Offset = "1"/>
</LinearGradientBrush>
</StackPanel.Background>
<Button Name = "btnAddGrid" Content = "Grid" Width = "30" Margin = "5" Click = "AddAdjustableBox_Click"/>
<Button Name = "btnRowSeperator" Content = "Row" Width = "30" Margin = "5" Click = "btnRowSeperator_Click"/>
<Button Name = "btnColumnSeperator" Content = "Col" Width = "30" Margin = "5" Click = "btnColumnSeperator_Click"/>
Код C Sharp:
public partial class TableDesignerUserControl : UserControl
{
private Point startPoint;
private Rectangle selectionRectangle;
private Border resizeBorder;
private bool isResizing = false;
private bool isDragging = false;
private string resizeDirection;
private bool _columnSeperator;
private bool _rowSeperator;
private bool gridGenerator;
private Grid selectedGrid;
private Dictionary<Grid, GridData> gridDataMap = new Dictionary<Grid, GridData>();
private List<Border> selectedCells = new List<Border>();
private List<Border> gridBorders = new List<Border>();
private Border activeBorder = null;
private bool isSelecting = false;
private bool isDeselecting = false;
private Border initialCell = null;
public TableDesignerUserControl()
{
InitializeComponent();
}
private void MainGrid_MouseDown(object sender, MouseButtonEventArgs e)
{
if (gridGenerator)
{
startPoint = e.GetPosition(MainGrid);
double imageWidth = imgDisplay.ActualWidth;
double imageHeight = imgDisplay.ActualHeight;
Point imagePosition = imgDisplay.TranslatePoint(new Point(0, 0), MainGrid);
if (startPoint.X < imagePosition.X || startPoint.X > imagePosition.X + imageWidth ||
startPoint.Y < imagePosition.Y || startPoint.Y > imagePosition.Y + imageHeight)
{
MessageBox.Show("Cannot draw outside the boundaries of the image.", "Alert", MessageBoxButton.OK, MessageBoxImage.Warning);
return;
}
selectionRectangle = new Rectangle
{
Stroke = Brushes.Black,
StrokeDashArray = new DoubleCollection { 2 },
StrokeThickness = 1,
Width = 0,
Height = 0,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Margin = new Thickness(startPoint.X, startPoint.Y, 0, 0)
};
MainGrid.Children.Add(selectionRectangle);
}
else
{
if (e.OriginalSource is Border border && gridBorders.Contains(border))
{
activeBorder = border;
SelectGrid(activeBorder.Child as Grid);
return;
}
else if (e.OriginalSource is Grid grid && grid != MainGrid)
{
SelectGrid(grid);
return;
}
}
}
private void MainGrid_MouseMove(object sender, MouseEventArgs e)
{
if (selectionRectangle == null || isResizing || isDragging)
return;
var currentPoint = e.GetPosition(MainGrid);
double imageWidth = imgDisplay.ActualWidth;
double imageHeight = imgDisplay.ActualHeight;
Point imagePosition = imgDisplay.TranslatePoint(new Point(0, 0), MainGrid);
currentPoint.X = Math.Max(imagePosition.X, Math.Min(currentPoint.X, imagePosition.X + imageWidth));
currentPoint.Y = Math.Max(imagePosition.Y, Math.Min(currentPoint.Y, imagePosition.Y + imageHeight));
var minX = Math.Min(startPoint.X, currentPoint.X);
var minY = Math.Min(startPoint.Y, currentPoint.Y);
var width = Math.Abs(currentPoint.X - startPoint.X);
var height = Math.Abs(currentPoint.Y - startPoint.Y);
selectionRectangle.Margin = new Thickness(minX, minY, 0, 0);
selectionRectangle.Width = width;
selectionRectangle.Height = height;
}
private void MainGrid_MouseUp(object sender, MouseButtonEventArgs e)
{
if (selectionRectangle != null && !isResizing && !isDragging)
{
var currentPoint = e.GetPosition(MainGrid);
double imageWidth = imgDisplay.ActualWidth;
double imageHeight = imgDisplay.ActualHeight;
Point imagePosition = imgDisplay.TranslatePoint(new Point(0, 0), MainGrid);
currentPoint.X = Math.Max(imagePosition.X, Math.Min(currentPoint.X, imagePosition.X + imageWidth));
currentPoint.Y = Math.Max(imagePosition.Y, Math.Min(currentPoint.Y, imagePosition.Y + imageHeight));
var minX = Math.Min(startPoint.X, currentPoint.X);
var minY = Math.Min(startPoint.Y, currentPoint.Y);
var width = Math.Abs(currentPoint.X - startPoint.X);
var height = Math.Abs(currentPoint.Y - startPoint.Y);
MainGrid.Children.Remove(selectionRectangle);
var border = new Border
{
Width = width,
Height = height,
BorderBrush = Brushes.Black,
BorderThickness = new Thickness(1),
Margin = new Thickness(minX, minY, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
var grid = new Grid
{
Background = Brushes.LightBlue,
Opacity = 0.3,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
AddResizeThumbs(grid);
grid.MouseLeftButtonDown += Grid_MouseLeftButtonDown;
border.Child = grid;
MainGrid.Children.Add(border);
grid.Margin = new Thickness(0);
SelectGrid(grid);
selectionRectangle = null;
gridBorders.Add(border);
activeBorder = border;
gridDataMap[grid] = new GridData(); // Initialize GridData for the new grid
}
}
private void SelectGrid(Grid grid)
{
if (grid == null)
return;
selectedGrid = grid;
selectedGrid.Background = Brushes.LightBlue;
selectedGrid.Opacity = 0.5;
foreach (var border in gridBorders)
{
if (border.Child != selectedGrid)
{
(border.Child as Grid).Background = Brushes.Gray;
(border.Child as Grid).Opacity = 0.3;
}
}
}
private void AddResizeThumbs(Grid container)
{
AddResizeThumb(container, Cursors.SizeWE, HorizontalAlignment.Right, VerticalAlignment.Stretch, "Right", 0, 0);
AddResizeThumb(container, Cursors.SizeNS, HorizontalAlignment.Stretch, VerticalAlignment.Bottom, "Bottom", 0, 0);
AddResizeThumb(container, Cursors.SizeWE, HorizontalAlignment.Left, VerticalAlignment.Stretch, "Left", 0, 0);
AddResizeThumb(container, Cursors.SizeNS, HorizontalAlignment.Stretch, VerticalAlignment.Top, "Top", 0, 0);
AddDraggingThumb(container, 0, 0);
}
private void AddResizeThumb(Grid container, Cursor cursor, HorizontalAlignment horizontalAlignment, VerticalAlignment verticalAlignment, string direction, double marginLeft, double marginTop)
{
var thumb = new Thumb
{
Width = 10,
Height = 10,
Opacity = 1,
Background = Brushes.White,
HorizontalAlignment = horizontalAlignment,
VerticalAlignment = verticalAlignment,
Cursor = cursor,
Tag = direction,
Margin = new Thickness(marginLeft, marginTop, 0, 0)
};
thumb.DragStarted += (s, e) =>
{
resizeBorder = (Border)container.Parent;
activeBorder = resizeBorder;
isResizing = true;
resizeDirection = (string)thumb.Tag;
MainGrid.Children.Remove(activeBorder);
MainGrid.Children.Add(activeBorder);
};
thumb.DragDelta += Thumb_DragDelta;
thumb.DragCompleted += (s, e) =>
{
isResizing = false;
resizeDirection = null;
};
container.Children.Add(thumb);
}
private void AddDraggingThumb(Grid container, double marginLeft, double marginTop)
{
var thumb = new Thumb
{
Width = 10,
Height = 10,
Opacity = 1,
Background = Brushes.Red,
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top,
Cursor = Cursors.SizeAll,
Margin = new Thickness(marginLeft, marginTop, 0, 0)
};
thumb.DragStarted += (s, e) =>
{
resizeBorder = (Border)container.Parent;
activeBorder = resizeBorder;
isDragging = true;
MainGrid.Children.Remove(activeBorder);
MainGrid.Children.Add(activeBorder);
};
thumb.DragDelta += Thumb_DragMove;
thumb.DragCompleted += (s, e) =>
{
isDragging = false;
};
container.Children.Add(thumb);
}
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (resizeBorder == null || !isResizing)
return;
double newWidth, newHeight, newLeft, newTop;
double imageWidth = imgDisplay.ActualWidth;
double imageHeight = imgDisplay.ActualHeight;
Point imagePosition = imgDisplay.TranslatePoint(new Point(0, 0), MainGrid);
switch (resizeDirection)
{
case "Right":
newWidth = resizeBorder.Width + e.HorizontalChange;
if (newWidth > 0 && resizeBorder.Margin.Left + newWidth <= imagePosition.X + imageWidth)
resizeBorder.Width = newWidth;
break;
case "Bottom":
newHeight = resizeBorder.Height + e.VerticalChange;
if (newHeight > 0 && resizeBorder.Margin.Top + newHeight <= imagePosition.Y + imageHeight)
resizeBorder.Height = newHeight;
break;
case "Left":
newWidth = resizeBorder.Width - e.HorizontalChange;
newLeft = resizeBorder.Margin.Left + e.HorizontalChange;
if (newWidth > 0 && newLeft >= imagePosition.X)
{
resizeBorder.Width = newWidth;
resizeBorder.Margin = new Thickness(newLeft, resizeBorder.Margin.Top, 0, 0);
}
break;
case "Top":
newHeight = resizeBorder.Height - e.VerticalChange;
newTop = resizeBorder.Margin.Top + e.VerticalChange;
if (newHeight > 0 && newTop >= imagePosition.Y)
{
resizeBorder.Height = newHeight;
resizeBorder.Margin = new Thickness(resizeBorder.Margin.Left, newTop, 0, 0);
}
break;
}
AdjustGridCells();
}
private void Thumb_DragMove(object sender, DragDeltaEventArgs e)
{
if (resizeBorder == null || !isDragging)
return;
double newLeft = resizeBorder.Margin.Left + e.HorizontalChange;
double newTop = resizeBorder.Margin.Top + e.VerticalChange;
double imageWidth = imgDisplay.ActualWidth;
double imageHeight = imgDisplay.ActualHeight;
Point imagePosition = imgDisplay.TranslatePoint(new Point(0, 0), MainGrid);
if (newLeft >= imagePosition.X && newTop >= imagePosition.Y &&
newLeft + resizeBorder.Width <= imagePosition.X + imageWidth &&
newTop + resizeBorder.Height <= imagePosition.Y + imageHeight)
{
resizeBorder.Margin = new Thickness(newLeft, newTop, 0, 0);
}
}
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Point clickPosition = e.GetPosition(selectedGrid);
if (_rowSeperator && !isDragging)
{
if (!gridDataMap[selectedGrid].RowSeparators.Contains(clickPosition.Y))
{
gridDataMap[selectedGrid].RowSeparators.Add(clickPosition.Y);
gridDataMap[selectedGrid].RowSeparators.Sort();
}
UpdateGrid();
}
else if (_columnSeperator && !isDragging)
{
if (!gridDataMap[selectedGrid].ColumnSeparators.Contains(clickPosition.X))
{
gridDataMap[selectedGrid].ColumnSeparators.Add(clickPosition.X);
gridDataMap[selectedGrid].ColumnSeparators.Sort();
}
UpdateGrid();
}
}
private void UpdateGrid()
{
if (selectedGrid == null)
return;
selectedGrid.RowDefinitions.Clear();
selectedGrid.ColumnDefinitions.Clear();
double previousY = 0;
foreach (var separator in gridDataMap[selectedGrid].RowSeparators)
{
selectedGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(separator - previousY, GridUnitType.Pixel) });
previousY = separator;
}
selectedGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(selectedGrid.ActualHeight - previousY, GridUnitType.Pixel) });
double previousX = 0;
foreach (var separator in gridDataMap[selectedGrid].ColumnSeparators)
{
selectedGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(separator - previousX, GridUnitType.Pixel) });
previousX = separator;
}
selectedGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(selectedGrid.ActualWidth - previousX, GridUnitType.Pixel) });
for (int row = 0; row < selectedGrid.RowDefinitions.Count; row++)
{
for (int column = 0; column < selectedGrid.ColumnDefinitions.Count; column++)
{
AddGridCell(selectedGrid, row, column);
}
}
}
private void AdjustGridCells()
{
if (selectedGrid == null)
return;
foreach (var cell in selectedGrid.Children.OfType<Border>())
{
var row = Grid.GetRow(cell);
var column = Grid.GetColumn(cell);
cell.Width = selectedGrid.ColumnDefinitions[column].Width.Value;
cell.Height = selectedGrid.RowDefinitions[row].Height.Value;
}
}
private void AddGridCell(Grid grid, int row, int column)
{
var cellBorder = new Border
{
BorderBrush = Brushes.Blue,
BorderThickness = new Thickness(0.5),
Background = Brushes.Transparent
};
Grid.SetRow(cellBorder, row);
Grid.SetColumn(cellBorder, column);
cellBorder.MouseLeftButtonDown += CellBorder_MouseLeftButtonDown;
cellBorder.MouseMove += CellBorder_MouseMove;
cellBorder.MouseLeftButtonUp += CellBorder_MouseLeftButtonUp;
AddCellResizeThumbs(cellBorder); // Add this line to add thumbs to each cell
grid.Children.Add(cellBorder);
}
Выход:
Перед добавлением разделителя: большой палец работает как положено.
После добавления разделителей: большой палец перемещается в другое положение.
После добавления UpdateThumbArrangement — (изменение размера сетки не работает, большой палец перемещается к границам ячеек, а не к границе сетки)
Вывод сейчас:
По крайней мере, по изображению мы можем сказать, что поле, по которому выровнены элементы Thumb, идеально расположено для заполнения первой ячейки. Возможно, это поможет.
@BionicCode — я добавил полный код. Большой палец предназначен не для ячеек, а для регулировки высоты и ширины сетки. Большой палец перемещается к первой ячейке после создания определения строки в методе updategrid.
Привет @BionicCode! Спасибо, что исправили проблему. Теперь большой палец не двигается, он все еще остается в сетке, и это нормально, но я не могу настроить размер сетки. Я не получил курсор изменения размера, если навести указатель мыши на большой палец. Я добавил изображение
Проблема в том, что вы не переставляете элементы Thumb
.
Дело в том, что по умолчанию дочерние элементы Grid
помещаются в первую ячейку. Их соответствующие значения Grid.Row
и Grid.Column
равны 0
. Это нормально, если Grid
не содержит ячеек. Но как только вы определяете ячейки, добавляя элементы макета RowDefinition
и ColumnDefinition
к Grid
, вам придется явно упорядочить дочерние элементы так, чтобы они располагались в соответствующих ячейках.
В вашем случае вы просто хотите, чтобы все элементы Thumb
оставались в первой ячейке, но заставляли их охватывать все ячейки и строки (чтобы они вели себя так, как будто ячеек нет - как в исходном состоянии), установив Grid.RowSpan
на количество строк и Grid.ColumnSpan
к количеству столбцов:
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (!isDragging)
{
return;
}
Point clickPosition = e.GetPosition(selectedGrid);
if (_rowSeperator)
{
if (!gridDataMap[selectedGrid].RowSeparators.Contains(clickPosition.Y))
{
gridDataMap[selectedGrid].RowSeparators.Add(clickPosition.Y);
gridDataMap[selectedGrid].RowSeparators.Sort();
}
}
else if (_columnSeperator)
{
if (!gridDataMap[selectedGrid].ColumnSeparators.Contains(clickPosition.X))
{
gridDataMap[selectedGrid].ColumnSeparators.Add(clickPosition.X);
gridDataMap[selectedGrid].ColumnSeparators.Sort();
}
}
// You should pull the UpdateGrid() call out of the if-else blocks
// to eliminate duplicate code
UpdateGrid();
// After you have added RowDefinitions and ColumnDefinitions you have to
// rearrange the Thumb elements to make them span across their parent Grid
UpdateThumbArrangement();
}
private void UpdateThumbArrangement()
{
int rowCount = gridDataMap[selectedGrid].RowSeparators.Count + 1;
int columnCount = gridDataMap[selectedGrid].ColumnSeparators.Count + 1;
IEnumerable<Thumb> thumbs = selectedGrid.Children.OfType<Thumb>();
foreach (Thumb thumb in thumbs)
{
Grid.SetRowSpan(thumb, rowCount);
Grid.SetColumnSpan(thumb, columnCount);
}
}
После предоставления большего контекста новые исправления должны быть следующими:
Thumb
в первой Grid
ячейке.UpdateThumbArrangement
изменил подпись, чтобы принять хостинг Grid
в качестве аргумента. UpdateThumbArrangement
обычно следует вызывать всякий раз, когда вы добавляете Thumb
элементы в корень Grid
.
private void UpdateThumbArrangement(Grid thumbContainer)
{
int rowCount = thumbContainer.RowDefinitions.Count;
int columnCount = thumbContainer.ColumnDefinitions.Count;
IEnumerable<Thumb> thumbs = thumbContainer.Children.OfType<Thumb>();
foreach (Thumb thumb in thumbs)
{
Grid.SetRowSpan(thumb, rowCount);
Grid.SetColumnSpan(thumb, columnCount);
}
}
UpdateThumbArrangement
теперь вызывается из LoadGridState
и Grid_MouseLeftButtonDown
. Обычно вам нужно вызвать новый UpdateThumbArrangement´ method whenever you add
Thumbekements to the root
Gridand whenever you change the cell size of the root
Grid. And whenever you change the size of the root
Gridyou must also recalculate the cell sizes. You can use the new
RedistributeCellSpacemethod from the next section down below. With "root Grid" I mean the outer
Grid, который содержит элементы изменения размера сетки Thumb
.
public void LoadGridState(string filePath)
{
if (!File.Exists(filePath)) return;
var json = File.ReadAllText(filePath);
var grids = JsonConvert.DeserializeObject<List<GridModel>>(json);
gridBorders.Clear();
gridDataMap.Clear();
foreach (var gridModel in grids)
{
var border = new Border
{
Width = gridModel.Width,
Height = gridModel.Height,
BorderBrush = Brushes.Black,
BorderThickness = new Thickness(1),
Margin = new Thickness(gridModel.Left, gridModel.Top, 0, 0),
HorizontalAlignment = HorizontalAlignment.Left,
VerticalAlignment = VerticalAlignment.Top
};
var grid = new Grid
{
Background = Brushes.LightBlue,
Opacity = 0.3,
HorizontalAlignment = HorizontalAlignment.Stretch,
VerticalAlignment = VerticalAlignment.Stretch
};
foreach (var columnDefinition in gridModel.ColumnDefinitions)
{
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(columnDefinition) });
}
foreach (var rowDefinition in gridModel.RowDefinitions)
{
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(rowDefinition) });
}
foreach (var cell in gridModel.Cells)
{
var cellBorder = new Border
{
BorderBrush = Brushes.Blue,
BorderThickness = new Thickness(0.5),
Background = Brushes.Transparent,
};
Grid.SetRow(cellBorder, cell.Row);
Grid.SetColumn(cellBorder, cell.Column);
if (cell.RowSpan > 1)
{
Grid.SetRowSpan(cellBorder, cell.RowSpan);
}
if (cell.ColumnSpan > 1)
{
Grid.SetColumnSpan(cellBorder, cell.ColumnSpan);
}
cellBorder.MouseLeftButtonDown += CellBorder_MouseLeftButtonDown;
cellBorder.MouseMove += CellBorder_MouseMove;
cellBorder.MouseLeftButtonUp += CellBorder_MouseLeftButtonUp;
AddCellResizeThumbs(cellBorder);
grid.Children.Add(cellBorder);
}
gridDataMap[grid] = new GridData
{
RowSeparators = gridModel.Separators.RowSeparators,
ColumnSeparators = gridModel.Separators.ColumnSeparators
};
AddResizeThumbs(grid);
UpdateThumbArrangement(grid);
grid.MouseLeftButtonDown += Grid_MouseLeftButtonDown;
border.Child = grid;
MainGrid.Children.Add(border);
grid.Margin = new Thickness(0);
gridBorders.Add(border);
SelectGrid(grid);
}
}
И Grid_MouseLeftButtonDown
теперь выглядит следующим образом (добавлен новый UpdateThumbArrangement
и переработан). После изменения количества ячеек необходимо применить диапазоны столбцов и строк. UpdateThumbArrangement
делает это.
private void Grid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (isDragging)
{
return;
}
Point clickPosition = e.GetPosition(selectedGrid);
if (_rowSeperator)
{
if (!gridDataMap[selectedGrid].RowSeparators.Contains(clickPosition.Y))
{
gridDataMap[selectedGrid].RowSeparators.Add(clickPosition.Y);
gridDataMap[selectedGrid].RowSeparators.Sort();
}
}
else if (_columnSeperator)
{
if (!gridDataMap[selectedGrid].ColumnSeparators.Contains(clickPosition.X))
{
gridDataMap[selectedGrid].ColumnSeparators.Add(clickPosition.X);
gridDataMap[selectedGrid].ColumnSeparators.Sort();
}
}
UpdateGrid();
UpdateThumbArrangement(selectedGrid);
}
Добавьте проверку высоты и ширины, чтобы избежать исключения для отрицательных значений. В этой версии Math.Max
используется для обеспечения значения, большего или равного нулю.
private void UpdateGrid()
{
if (selectedGrid == null)
return;
selectedGrid.Children.Clear();
selectedGrid.RowDefinitions.Clear();
selectedGrid.ColumnDefinitions.Clear();
double previousY = 0;
foreach (var separator in gridDataMap[selectedGrid].RowSeparators)
{
selectedGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(separator - previousY, GridUnitType.Pixel) });
previousY = separator;
}
// Use Math.Max to avoid negative height values
selectedGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(Math.Max(0, selectedGrid.ActualHeight - previousY), GridUnitType.Pixel) });
double previousX = 0;
foreach (var separator in gridDataMap[selectedGrid].ColumnSeparators)
{
selectedGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(separator - previousX, GridUnitType.Pixel) });
previousX = separator;
}
// Use Math.Max to avoid negative width values
selectedGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(Math.Max(0, selectedGrid.ActualWidth - previousX), GridUnitType.Pixel) });
for (int row = 0; row < selectedGrid.RowDefinitions.Count; row++)
{
for (int column = 0; column < selectedGrid.ColumnDefinitions.Count; column++)
{
AddGridCell(selectedGrid, row, column);
}
}
AddResizeThumbs(selectedGrid);
}
Вызовите представленный метод RedistributeCellSpace
после изменения размера Border
. Также добавьте Math.Max
для надежности (чтобы предотвратить отрицательные значения или значения ниже пределов minHeight
minWidth
).
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
if (resizeBorder == null || !isResizing) return;
double newLeft, newTop;
double imageWidth = imgDisplay.ActualWidth;
double imageHeight = imgDisplay.ActualHeight;
Point imagePosition = imgDisplay.TranslatePoint(new Point(0, 0), MainGrid);
// TODO::Define both variables as const fields
const double minWidth = 10;
const double minHeight = 10;
Size oldResizeBorderSize = resizeBorder.RenderSize;
double newWidth = oldResizeBorderSize.Width;
double newHeight = oldResizeBorderSize.Height;
switch (resizeDirection)
{
case "Right":
newWidth = Math.Max(minWidth, resizeBorder.Width + e.HorizontalChange / 2);
if (newWidth >= minWidth && resizeBorder.Margin.Left + newWidth <= imagePosition.X + imageWidth)
resizeBorder.Width = newWidth;
break;
case "Bottom":
newHeight = Math.Max(minHeight, resizeBorder.Height + e.VerticalChange / 2);
if (newHeight >= minHeight && resizeBorder.Margin.Top + newHeight <= imagePosition.Y + imageHeight)
resizeBorder.Height = newHeight;
break;
case "Left":
newWidth = Math.Max(minWidth, resizeBorder.Width - e.HorizontalChange / 2);
newLeft = resizeBorder.Margin.Left + e.HorizontalChange / 2;
if (newWidth >= minWidth && newLeft >= imagePosition.X)
{
resizeBorder.Width = newWidth;
resizeBorder.Margin = new Thickness(newLeft, resizeBorder.Margin.Top, 0, 0);
}
break;
case "Top":
newHeight = Math.Max(minHeight, resizeBorder.Height - e.VerticalChange / 2);
newTop = resizeBorder.Margin.Top + e.VerticalChange / 2;
if (newHeight >= minHeight && newTop >= imagePosition.Y)
{
resizeBorder.Height = newHeight;
resizeBorder.Margin = new Thickness(resizeBorder.Margin.Left, newTop, 0, 0);
}
break;
}
// Ensure the last cell and last column remain static
if (resizeBorder.Child is Grid grid)
{
var newResizeBorderSize = new Size(newWidth, newHeight);
RedistributeCellSpace(grid, oldResizeBorderSize, newResizeBorderSize);
foreach (var child in grid.Children.OfType<Border>())
{
if (IsLastCellOrLastColumn(child))
{
child. Width = double. Nan;
child. Height = double. Nan;
}
}
}
}
Добавлен новый метод для пересчета размера ячейки после изменения размера Grid
. Это фактически позволит правильно расположить элементы Thumb. Это необходимо из-за фиксированных размеров ячеек.
private static void RedistributeCellSpace(Grid grid, Size oldSize, Size newSize)
{
bool hasHeightChanged = oldSize.Height != newSize.Height;
if (hasHeightChanged)
{
double heightRatio = newSize.Height / oldSize.Height;
foreach (RowDefinition rowDefinition in grid.RowDefinitions.Where(rowDefinition => rowDefinition.Height.IsAbsolute))
{
double heightChange = rowDefinition.Height.Value * heightRatio;
rowDefinition.Height = new GridLength(heightChange);
}
}
bool hasWidthChanged = oldSize.Width != newSize.Width;
if (hasWidthChanged)
{
double widthRatio = newSize.Width / oldSize.Width ;
foreach (ColumnDefinition columnDefinition in grid.ColumnDefinitions.Where(columnDefinition => columnDefinition.Width.IsAbsolute))
{
double heightChange = columnDefinition.Width.Value * widthRatio;
columnDefinition.Width = new GridLength(heightChange);
}
}
}
Вот и все. Но вы также должны проверить поведение изменения размера ячейки. Он тоже сломан.
Спасибо за исправление проблемы. Теперь большой палец не двигается, он все еще остается в сетке, и это нормально, но я не могу настроить размер сетки. У меня не появился курсор изменения размера
Я обновил пример. В рефакторинговом методе Grid_MouseLeftButtonDown
была ошибка. Я также улучшил операторы if.
Вы хотите сказать, что поведение изменения размера работало правильно до предложенных мной изменений? Я сомневаюсь в этом.
Спасибо. Я не могу открыть молнию. Почему бы вам не создать подходящий репозиторий, чтобы я мог напрямую просматривать исходный код или даже клонировать его? Это было бы большим подспорьем для нас обоих.
Тем не менее, я думаю, что я уже определил проблему, я думаю. Просто не было времени ничего постить. Всегда ли ячейки сетки имеют одинаковый размер (пространство сетки распределено равномерно) или каждая может иметь разный размер?
Привет @BionicCode. Используйте этот репозиторий GitHub github.com/VigneshJayaraman05/WPF-Grid.git
Спасибо. Я рассмотрю это завтра. Исправить это просто. Затем я опубликую изменения в исходных файлах.
Изображение отсутствует.
Пожалуйста, найдите ссылку на изображение ниже github.com/VigneshJayaraman05/WPF-Grid/blob/main/demo1.jpg
Привет @BionicCode! Спасибо, что потратили на это время и поделились кодом. Изменение размера сетки теперь работает, но нижний и правый большие пальцы перемещаются за пределы/исчезают. Я настраиваю ползунок отдельных ячеек. Не могли бы вы помочь мне, как сделать последний столбец и строку сетки статическими?
Я не знаю, как вы хотите, чтобы клетки вели себя. Что вы подразумеваете под статикой последней строки и столбца?
Необходимо перераспределить пространство ячеек и строк. Просто переделайте свои расчеты
Я имею в виду границу таблиц
Изменение размера всей сетки теперь работает, верно? Изменение размера ячейки необходимо исправить путем исправления вычислений. Вы можете попытаться исключить последний столбец и строку из вашего алгоритма. Например, если ваша сетка имеет 3 ячейки, вы устанавливаете только ширину и высоту первых двух строк и столбцов. Последний столбец и строка имеют значение *
. Это позволит последней ячейке всегда заполнять оставшееся пространство. Затем напишите расчет ячейки с нуля. Первый размер изменяется, потому что ваши расчеты неверны. Если вы даете столбцу большую ширину, вам придется взять ту же сумму из соседнего столбца (перераспределение).
Давайте продолжим обсуждение в чате.
Хм, в твоем коде нет Thumbs? И логика, которая находит «Большие пальцы», также отсутствует. Трудно понять, как все связано. В сетке могут отображаться линии сетки:
Grid.ShowGridLines = true
.