2013-07-11 1 views
1

Я новичок в WPF. Я добавляю Rectangle один за другим на холсте при нажатии кнопки. Когда я устанавливаю Height of Specific Rectangle из TextBox. Он перекрывается в Child Rectangle.Как перемещать прямоугольник рядом с измененным родительским прямоугольником в WPF с помощью C#?

Например :.Когда есть 3 Прямоугольники с Height=100, Width=200 & когда я установил Высота Second Rectangle to 150. то ребенок Rectangle должен появиться после второго прямоугольника & не должен перекрывать третий прямоугольник. Является ли это возможным?

static int val=0; 
List<UIElement> itemstoremove = new List<UIElement>(); 
private void BtnAdd_Click(object sender, RoutedEventArgs e) 
     { 

      int heigt = 0; 
      int wegt = 0; 
      if (!string.IsNullOrEmpty(txtHeight.Text) && !string.IsNullOrEmpty(txtWidth.Text)) 
      { 
       heigt = int.Parse(txtHeight.Text); 
       wegt = int.Parse(txtWidth.Text); 
      } 
      rect = new Rectangle(); 
      rect.Stroke = Brushes.Red; 
      rect.StrokeThickness = 2; 
      rect.Height = heigt; 
      rect.Width = wegt; 
      Canvas.SetLeft(rect, 10); 
      Canvas.SetTop(rect, (rect.Height) * val); 
      rect.Tag = val; 
      canvasboard.Children.Add(rect); 
      val = val + 1; 
      //canvasboard is Canvas object 
      foreach (UIElement ui in canvasboard.Children) 
      { 
       if (ui.GetType() == typeof(Rectangle)) 
       { 
        itemstoremove.Add(ui); 
       } 
      } 
     } 

для изменения высоты & Ширина:

private void BtnModify_Click(object sender, RoutedEventArgs e) 
     { 
      int heigt = 0; 
      int wegt = 0; 
      if (!string.IsNullOrEmpty(txtHeight.Text) && !string.IsNullOrEmpty(txtWidth.Text)) 
      { 
       heigt = int.Parse(txtHeight.Text); 
       wegt = int.Parse(txtWidth.Text); 
      } 
      Rectangle rectToRemove; 

      foreach (UIElement ui in itemstoremove) 
      { 
       if (ui.GetType() == typeof(Rectangle) && ((Rectangle)ui).Tag.ToString() == txtModifyRect.Text) 
       { 
        rectToRemove = ui as Rectangle; 
        //itemstoremove.Remove(rectToRemove); 
        rectToRemove.Height = heigt; 
        rectToRemove.Width = wegt; 
        //canvasboard.Children.Remove(rectToRemove); 
        break; 
       } 
      } 
     } 

Это прекрасно работает. Просто я хочу предотвратить перекрытие Rectangle друг на друга и должен появляться один за другим с автоматической настройкой.

Помогите оценить!

ответ

0

Похоже, вы хотите получить StackPanel для своих прямоугольников. Вы можете использовать StackPanel в вашей Grid.

1

Чтобы получить эффект, который вы хотите, вы должны изменить Canvas на WrapPanel. Таким образом, когда вы добавляете дочерние элементы в холст, вы не добавляете местоположение, оно организует объекты самостоятельно. В основном вы хотите, чтобы это

 <ScrollViewer VerticalScrollBarVisibility="Auto" > 
     <WrapPanel Name="objList" > </WrapPanel> 
     </ScrollViewer> 

ScrollViewer позволит вам прокручивать, если у вас есть больше объектов, чем окно может содержать.

+0

ли вы имеете в виду я должен добавить прямоугольник в WrapPanel? Я новичок в этом, так что ..! –

+0

Это очень хорошее предложение, но автор хотел поместить их под другой, по крайней мере, я думаю, что он хотел этого, увидев «Canvas.SetLeft (rect, 10); Canvas.SetTop (rect, (rect.Height) * val); '.. – quetzalcoatl

+0

@SHEKHARSHETE: Да, он точно это имел в виду. WrapPanel будет контейнером для ваших Rectangles, а затем Rectangles будут компоновать себя так же, как текст на HTML-странице: плотно до тех пор, пока осталось место, а затем оберните «новую строку». – quetzalcoatl

1

Нужно ли конкретно указывать Canvas ..? Даже в чистом WPF/Desktop есть некоторые компоненты компоновки, которые могут сделать именно это для вас, непременно автоматически.

Поведение «укладки» компоненты один за другим именно то, что делает StackPanel класс/компонент/управления:

<StackPanel x:Name="stacker" Orientation="Vertical"> 
    <Rectangle Width="30" Height="100" Background="Green" /> 
    <Rectangle Width="10" Height="50" Background="Blue" /> 
    <Rectangle Width="20" Height="80" Background="Red" Margin="5,10" /> 
</StackPanel> 

Обратите внимание, как прямоугольники, расположенные друг под другом в соответствии с их различным Heights. Обратите внимание, что мне не нужно было указывать Orientation=Vertical, потому что поведение StackPanel по умолчанию заключается в том, чтобы позиционировать их так. Вы можете переключить его по горизонтали, если хотите, и затем поместите их в соответствии с их Widths. Вы также можете настроить и добавить дополнительный интервал, например, Margin, как в третьем прямоугольнике.

Если вам нужно сделать это с помощью кода, то StackPanel имени stacker идеально подходит для этого: вы можете добавлять новые элементы к нему динамически, и он будет раскладывать добавлены те же, как это происходит с детьми, определенными в XAML: один под другим.

С помощью StackPanel вы получите еще больше! StackPanel наблюдает за своими детьми. Если через некоторое время после размещения детей вы меняете высоты/ширину детей, то StackPanel мгновенно отрегулирует позиции, поэтому ни одна из них не будет перекрываться (если вы сделаете детей меньшими, они сжимают их, если вы сделаете детей большими - это будет расширяться и т. д.).

Если вы действительно-действительно хотите использовать Canvas, то в момент добавления-а-новый пункт повестки дня, вы должны петлю над всеми существующими-элементами, хранящихся в холсте, суммы до их высот и установите позицию Y нового элемента на именно такую ​​сумму. Таким образом, он появится точно под последним элементом. Это самый очевидный способ сделать это. Однако он не учитывает поля, расстояния и несколько других мелких деталей, которые могут оказаться на вашем холсте.

Лучшим, но менее очевидным способом является не суммировать высоты снова и снова, а вместо этого позиционировать новый элемент в соответствии с самым нижним существующим элементом. В конце концов, все старые предметы расположены правильно, не так ли? Но что означает bottommost? Иногда высокий элемент, расположенный рядом с вершиной, может опускаться дальше вниз, чем не очень высокий элемент, сидящий в центре. Следовательно, bottommost не означает the item with maximum Y position, но означает изделие с наибольшим Bottom, поэтому maximum Y+Height. Итак:

  • петли через существующие пункты
  • найти элемент которого Size.Height+Position.Bottom является крупнейшим
  • установить Position.Y нового элемента к этому значению

Теперь, вы получите примерно то же самое, что и StackPanel, но это будет только одноразовый эффект. Если вы позже измените высоты некоторых элементов, вам придется пересчитать все позиции и отрегулировать все позиции .. (*)

EDIT: (*) Я точно не помню, но если свойства X/Y/Bottom DependencyProperty, тогда вы даже можете попытаться использовать Bindings для автоматического управления позициями. На Холсте может быть довольно забавно. Просто попробуйте привязать Y последнего элемента к Bottom первого, и он должен все волшебным образом выстроить себя и даже автоматически обновить при перемещении/изменении размера. Однако сначала попробуйте StackPanel!

+0

FYI: Статья: [MSDN - сравнение контейнера компоновки] (http://msdn.microsoft.com/en-us/ библиотека/bb514628 (v = vs.90) .aspx) – quetzalcoatl

+0

И еще лучше, с изображениями, показывающими мотыгу, каждый контейнер работает: [Панели и контейнеры] (http://www.dotnetfunda.com/articles/article900-wpf-tutorial- топологий панель-контейнеры-макет-преобразование-2.aspx) – quetzalcoatl

0

Вот мое решение:

<ScrollViewer VerticalScrollBarVisibility="Auto" Width="250" Height="500"> 
       <WrapPanel Name="wrapboard" Orientation="Vertical" ></WrapPanel> 
    </ScrollViewer> 

private void BtnAdd_Click(object sender, RoutedEventArgs e) 
     { 

      int heigt = 0; 
      int wegt = 0; 
      if (!string.IsNullOrEmpty(txtHeight.Text) && !string.IsNullOrEmpty(txtWidth.Text)) 
      { 
       heigt = int.Parse(txtHeight.Text); 
       wegt = int.Parse(txtWidth.Text); 
      } 
      rect = new Rectangle(); 
      rect.Stroke = Brushes.Red; 
      rect.StrokeThickness = 2; 
      rect.Height = heigt; 
      rect.Width = wegt; 
      rect.Tag = val; 
      wrapboard.Children.Add(rect); 
      val = val + 1; 
      //wrapboard is WrapPanel object 
      foreach (UIElement ui in wrapboard.Children) 
      { 
       if (ui.GetType() == typeof(Rectangle)) 
       { 
        itemstoremove.Add(ui); 
       } 
      } 
     }