Как переставить прямоугольники на холсте после изменения высоты любого прямоугольника в wpf?
Я добавляю Rectangle
из значений ячеек сетки, которые вводятся пользователем непосредственно в строках сетки. Когда я изменяю значение определенного столбца, говорю Thickness
т.е. Height
тогда то увеличивается Height
выбранного прямоугольника строки, но он не переставляет весь прямоугольник под ним точно после выбранного прямоугольника строки.
В xaml.cs
public class MyLayer : INotifyPropertyChanged
{
public string Thickness { get; set; }
public string OffsetRight { get; set; }
public string OffsetLeft { get; set; }
public string Material { get; set; }
public string MaterialPopup { get; set; }
public Rectangle rectangle { get; set; }
public GlassRectangle GlassRectangle { get; set; }
public MaterialLayer()
{
GlassRectangle = new GlassRectangle();
}
event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
{
add { }
remove { }
}
}
public class GlassRectangle
{
public Rectangle Rectangle { get; set; }
public double Top = 0;
public GlassRectangle()
{
Rectangle = new Rectangle();
}
}
private void gridInner_CellValueChanged(object sender, DevExpress.Xpf.Grid.CellValueChangedEventArgs e)
{
string cellValue = string.Empty;
MyLayer currentLayer = ((MyLayer)(e.Row));
if (e.Column.HeaderCaption.ToString() == "Thickness")
{
cellValue =(e.Value.ToString());
//there is alredy a rectangle - means this is edit mode
if (currentLayer.rectangle != null)
{
currentLayer.rectangle.Height = Convert.ToDouble(cellValue);
currentLayer.rectangle.Stroke = new SolidColorBrush(Color.FromRgb(0, 255, 0));
}
//else this is insert mode
else
{
currentLayer.rectangle = CreateRectangle(cellValue);
}
}
}
protected Rectangle CreateRectangle(string cellval)
{
Rectangle newrect = new Rectangle();
newrect.Stroke = Brushes.Red;
newrect.StrokeThickness = 1;
if (cellval.ToString().Contains("."))
{
newrect.Height = Convert.ToDouble(cellval) * 100;
}
else
{
newrect.Height = Convert.ToDouble(cellval);
}
newrect.Width = width;
Canvas.SetLeft(newrect, 100);
double canvasTop = 0.0;
if (canvasboard.Children.Count > 0)
{
var lastChildIndex = canvasboard.Children.Count - 1;
var lastChild = canvasboard.Children[lastChildIndex] as FrameworkElement;
if (lastChild != null)
//lastChild.Height-1: so that it come extactly on existing if set to +1 it comes below first rectangle
canvasTop = Canvas.GetTop(lastChild) + lastChild.Height - 1;
}
Canvas.SetTop(newrect, canvasTop);
val = val + 1;
newrect.Tag = val;
canvasboard.Children.Add(newrect);
//rectangle = rect;
foreach (UIElement ui in canvasboard.Children)
{
if (ui.GetType() == typeof(Rectangle))
{
itemstoremove.Add(ui);
}
}
return newrect;
}
Метод НОВОГО СОБЫТИЯ:
private void gridMaterialInner_CellValueChanged(object sender, DevExpress.Xpf.Grid.CellValueChangedEventArgs e)
{
string cellValue = string.Empty;
string cellOldValue = string.Empty;
MyLayer currentLayer = ((MyLayer)(e.Row));
if (e.Column.HeaderCaption.ToString() == "Thickness")
{
//current cell value
cellValue =(e.Value.ToString());// GetRowCellValue(e.RowHandle, gridMaterialInner.Columns["LastName"]).ToString();
//there is alredy a rectangle - means this is edit mode
double currentheight = 0.0;
double oldht = 0.0;
// old cell value
if (e.OldValue != null)
{
cellOldValue = (e.OldValue.ToString());
}
if (currentLayer.rectangle != null)
{
if (cellValue.ToString().Contains("."))
{
currentheight = Convert.ToDouble(cellValue) * 100;
}
else
{
currentheight = Convert.ToDouble(cellValue) * 100;
}
if (cellOldValue.ToString().Contains("."))
{
oldht = Convert.ToDouble(cellOldValue) * 100;
}
else if(cellOldValue!=string.Empty)
{
oldht = Convert.ToDouble(cellOldValue) * 100;
}
currentLayer.rectangle.Height = currentheight;
currentLayer.rectangle.Stroke = new SolidColorBrush(Color.FromRgb(0, 255, 0));
//Refresh();
//Get the index of selected row
int layerIndex = materialBindlist.IndexOf(currentLayer);
for(int i = layerIndex; i < materialBindlist.Count-1; i++)
{
//set the top position of all other rectangles that are below selected rectangle/row
//(Current-Old)+Top
Canvas.SetTop(materialBindlist[i + 1].rectangle, (currentheight - oldht) + materialBindlist[i + 1].GlassRectangle.Top);
//Canvas.SetTop(materialBindlist[i].rectangle, (currentheight - oldht) + materialBindlist[i + 1].GlassRectangle.Top);
}
}
//else this is insert mode
else
{
//MaterialLayer object
currentLayer.rectangle = CreateRectangle(cellValue);
//store Top & Rectangle object in GlassRectangle class which is referenced in MaterialLayer class
currentLayer.GlassRectangle.Rectangle = currentLayer.rectangle;
currentLayer.GlassRectangle.Top = canvasTop;
}
}
}
Это создает прямоугольник один за другим, как Stacked элемент на холсте. Но когда я изменяю значение Thickness
столбец, который Height
из Rectangle
это отражается на холсте, но другой прямоугольник ниже должен появиться после измененной высоты текущего прямоугольника.
Примечание: я не могу использовать WrapPanel в своем приложении. Просто чтобы изменить существующий код с помощью Canvas.
Помощь приветствуется!
Изменено для цикла в событии CellChange:
int layerIndex = materialBindlist.IndexOf(currentLayer);
for(int i = layerIndex; i < materialBindlist.Count-1; i++)
{
//set the top position of all other rectangles that are below selected rectangle/row
//(Current-Old)+Top
double top=Convert.ToDouble((currentHeight - oldHeight) + materialBindlist[i + 1].GlassRectangle.Top);
Canvas.SetTop(materialBindlist[i + 1].rectangle,top);
materialBindlist[i + 1].GlassRectangle.Top = top;
}
2 ответа
То, что вы ищете, может быть сделано даже с Canvas
Однако вы должны подумать об использовании чего-то вроде ItemsControl
за это.
Решение, когда вынужден использовать Canvas
:
private void Refresh() {
for (int i = 1; i < canvasboard.Children.Count; ++i) {
var currentElement = canvasboard.Children[i] as FrameworkElement;
var previousElement = canvasboard.Children[i - 1] as FrameworkElement;
if (currentElement == null || previousElement == null)
return;
var requiredTop = Canvas.GetTop(previousElement) + previousElement.Height - 1;
if (Math.Abs(Canvas.GetTop(currentElement) - requiredTop) > 0.0)
Canvas.SetTop(currentElement, requiredTop);
}
}
Теперь вызывайте эту функцию "после", вы меняете размер существующего элемента в Canvas
и это переместит элементы соответственно, чтобы соответствовать новому измерению. В вашем коде это будет вызвано из gridInner_CellValueChanged(...)
Функция после установки новой высоты в режиме "редактирования".
Что вы должны попытаться сделать:
Если вы можете убедить кого-либо, что вам нужно, и использовать что-то вроде ItemsControl
это будет намного проще.
скажем грубый пример:
XAML может быть:
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
с Items
объявлен как public ObservableCollection<Rectangle> Items { get; set; }
в коде.
Теперь ваш Add()
функция может быть просто:
private void Add() {
var rect = new Rectangle {
Stroke = Brushes.Red,
StrokeThickness = 1,
Height = Convert.ToDouble(txtheight.Text),
Width = 100
};
Items.Add(rect);
}
и что касается обновлений при редактировании существующих элементов управления, которые в этом случае будут автоматическими. Здесь нет жестко запрограммированного позиционирования, так как контейнер Layout позаботится обо всем, что вам нужно.
Вы можете, конечно, переключить Items
тип коллекции для вашего собственного типа элемента управления MyLayer
и с его внедрением INPC, изменения по-прежнему будут автоматически. Вы должны определить DataTemplate
Теперь, чтобы получить ваш Предмет для рендеринга, но это как 3 строки работы только в xaml.
Вы также можете просто работать Items
свойство непосредственно, когда нужно настроить существующий элемент управления, чем ссылаться на ItemsControl
в коде позади. Привязка должна автоматически обновлять представление.
Изменено для цикла в событии смены ячейки:
int layerIndex = materialBindlist.IndexOf(currentLayer);
for(int i = layerIndex; i < materialBindlist.Count-1; i++)
{
//set the top position of all other rectangles that are below selected rectangle/row
//(Current-Old)+Top
double top=Convert.ToDouble((currentHeight - oldHeight) + materialBindlist[i + 1].GlassRectangle.Top);
Canvas.SetTop(materialBindlist[i + 1].rectangle,top);
materialBindlist[i + 1].GlassRectangle.Top = top;
}
это работает сейчас..! Спасибо всем!