Положение большого пальца динамической сетки данных WPF изменилось, когда определение строки и столбца добавляется в выбранную динамическую сетку

Требование: Наше требование — нарисовать пустую сетку (таблицу со строками и столбцами) поверх таблиц, представленных на изображении, и для одного изображения может быть несколько сеток. Все сетки должны быть настраиваемыми, и мы можем добавить разделитель строк и разделитель столбцов по щелчку кнопки мыши в сетке. Определения сеток, миниатюр и строк и столбцов создаются на основе кода.

Проблема: Если создано определение столбца или строки, положение ползунка сетки изменяется и он перемещается в первый столбец первой строки, а не остается статическим во внешней сетке. Изменяется положение верхнего, левого, правого и нижнего большого пальца. Можете ли вы помочь нам в этом вопросе?

КСАМЛ:

<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 — (изменение размера сетки не работает, большой палец перемещается к границам ячеек, а не к границе сетки)

Вывод сейчас:

Хм, в твоем коде нет Thumbs? И логика, которая находит «Большие пальцы», также отсутствует. Трудно понять, как все связано. В сетке могут отображаться линии сетки: Grid.ShowGridLines = true.

BionicCode 02.07.2024 15:25

По крайней мере, по изображению мы можем сказать, что поле, по которому выровнены элементы Thumb, идеально расположено для заполнения первой ячейки. Возможно, это поможет.

BionicCode 02.07.2024 15:29

@BionicCode — я добавил полный код. Большой палец предназначен не для ячеек, а для регулировки высоты и ширины сетки. Большой палец перемещается к первой ячейке после создания определения строки в методе updategrid.

Vignesh Jayaraman 02.07.2024 18:04

Привет @BionicCode! Спасибо, что исправили проблему. Теперь большой палец не двигается, он все еще остается в сетке, и это нормально, но я не могу настроить размер сетки. Я не получил курсор изменения размера, если навести указатель мыши на большой палец. Я добавил изображение

Vignesh Jayaraman 03.07.2024 04:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
4
84
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Проблема в том, что вы не переставляете элементы 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 rootGridand whenever you change the cell size of the rootGrid. And whenever you change the size of the root Gridyou must also recalculate the cell sizes. You can use the newRedistributeCellSpacemethod from the next section down below. With "root Grid" I mean the outerGrid, который содержит элементы изменения размера сетки 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 для надежности (чтобы предотвратить отрицательные значения или значения ниже пределов minHeightminWidth).

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);
    }
  }
}

Вот и все. Но вы также должны проверить поведение изменения размера ячейки. Он тоже сломан.

Спасибо за исправление проблемы. Теперь большой палец не двигается, он все еще остается в сетке, и это нормально, но я не могу настроить размер сетки. У меня не появился курсор изменения размера

Vignesh Jayaraman 03.07.2024 01:26

Я обновил пример. В рефакторинговом методе Grid_MouseLeftButtonDown была ошибка. Я также улучшил операторы if.

BionicCode 03.07.2024 10:12

Вы хотите сказать, что поведение изменения размера работало правильно до предложенных мной изменений? Я сомневаюсь в этом.

BionicCode 03.07.2024 10:13
github.com/VigneshJayaraman05/WpfTableDesigner.git. Я добавил полный исходный код на GitHub. Пожалуйста, найдите ссылку
Vignesh Jayaraman 03.07.2024 11:29

Спасибо. Я не могу открыть молнию. Почему бы вам не создать подходящий репозиторий, чтобы я мог напрямую просматривать исходный код или даже клонировать его? Это было бы большим подспорьем для нас обоих.

BionicCode 03.07.2024 12:58

Тем не менее, я думаю, что я уже определил проблему, я думаю. Просто не было времени ничего постить. Всегда ли ячейки сетки имеют одинаковый размер (пространство сетки распределено равномерно) или каждая может иметь разный размер?

BionicCode 03.07.2024 13:53

Привет @BionicCode. Используйте этот репозиторий GitHub github.com/VigneshJayaraman05/WPF-Grid.git

Vignesh Jayaraman 03.07.2024 21:47

Спасибо. Я рассмотрю это завтра. Исправить это просто. Затем я опубликую изменения в исходных файлах.

BionicCode 03.07.2024 23:37

Изображение отсутствует.

BionicCode 03.07.2024 23:41

Пожалуйста, найдите ссылку на изображение ниже github.com/VigneshJayaraman05/WPF-Grid/blob/main/demo1.jpg

Vignesh Jayaraman 04.07.2024 02:55

Привет @BionicCode! Спасибо, что потратили на это время и поделились кодом. Изменение размера сетки теперь работает, но нижний и правый большие пальцы перемещаются за пределы/исчезают. Я настраиваю ползунок отдельных ячеек. Не могли бы вы помочь мне, как сделать последний столбец и строку сетки статическими?

Vignesh Jayaraman 04.07.2024 18:00

Я не знаю, как вы хотите, чтобы клетки вели себя. Что вы подразумеваете под статикой последней строки и столбца?

BionicCode 04.07.2024 22:11

Необходимо перераспределить пространство ячеек и строк. Просто переделайте свои расчеты

BionicCode 04.07.2024 22:14

Я имею в виду границу таблиц

Vignesh Jayaraman 05.07.2024 02:59

Изменение размера всей сетки теперь работает, верно? Изменение размера ячейки необходимо исправить путем исправления вычислений. Вы можете попытаться исключить последний столбец и строку из вашего алгоритма. Например, если ваша сетка имеет 3 ячейки, вы устанавливаете только ширину и высоту первых двух строк и столбцов. Последний столбец и строка имеют значение *. Это позволит последней ячейке всегда заполнять оставшееся пространство. Затем напишите расчет ячейки с нуля. Первый размер изменяется, потому что ваши расчеты неверны. Если вы даете столбцу большую ширину, вам придется взять ту же сумму из соседнего столбца (перераспределение).

BionicCode 05.07.2024 07:36

Давайте продолжим обсуждение в чате.

Vignesh Jayaraman 05.07.2024 15:42

Другие вопросы по теме