Я пытаюсь создать таблицу в .NET MAUI на основе макета сетки. Это код:
<CollectionView ItemsSource = "{Binding digitalInputs}">
<CollectionView.Header>
<Grid ColumnDefinitions = "*,*,*,*">
<Label Text = "Name" Grid.Column = "0"/>
<Label Text = "Typ" Grid.Column = "1"/>
<Label Text = "Status" Grid.Column = "2"/>
<Label Text = "Aktiv" Grid.Column = "3"/>
</Grid>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType = "services:DigitalInput">
<Grid ColumnDefinitions = "*,*,*,*">
<Label Text = "{Binding pName}" Grid.Column = "0"/>
<Label Text = "{Binding pDigitalType}" Grid.Column = "1"/>
<Label Text = "{Binding pValueText}" Grid.Column = "2"/>
<Label Text = "{Binding pActive}" Grid.Column = "3"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Вот результат при работе в режиме отладки на MacCatalyst (Visual Studio для Mac):
Теперь мне интересно, как я могу правильно выровнять сетку заголовка по сетке в шаблоне данных? Есть ли у кого-нибудь предложение о том, как я могу улучшить код, чтобы построить правильную таблицу?
Обновлено: похоже, это ошибка в среде IDE. Когда я изменяю свойство HorizontalOptions
в сетке в CollectionView.Header
, как было предложено в комментарии, горячая перезагрузка XAML запускает повторную визуализацию представления, и внезапно сетка заголовка правильно выравнивается с сеткой в ItemTemplate.
Когда я изменяю свойство при запуске приложения в режиме отладки, XAML HotReload запускает повторную визуализацию представления, и сетка идеально выравнивается.
Если вы имеете в виду сначала расположить дочерние элементы по горизонтали, а затем перейти к следующей строке, то текущий MAUI по-прежнему не поддерживает это, вы можете только активировать диапазон (также диапазон не меняется во время выполнения в WinUI прямо сейчас, я думаю, что команда исправить) или создать собственный
public class HorizontalWrapLayout : StackLayout
{
public HorizontalWrapLayout()
{
}
protected override ILayoutManager CreateLayoutManager()
{
return new HorizontalWrapLayoutManager(this);
}
}
public class HorizontalWrapLayoutManager : StackLayoutManager
{
HorizontalWrapLayout _layout;
public HorizontalWrapLayoutManager(HorizontalWrapLayout horizontalWrapLayout) : base(horizontalWrapLayout)
{
_layout = horizontalWrapLayout;
}
public override Size Measure(double widthConstraint, double heightConstraint)
{
var padding = _layout.Padding;
widthConstraint -= padding.HorizontalThickness;
var rows = new Dictionary<int, List<Size>>();
var currentRowIndex = 0;
var currentRow = new List<Size>();
rows.Add(currentRowIndex, currentRow);
foreach (var child in _layout)
{
if (child.Visibility == Visibility.Collapsed)
{
continue;
}
var childSize = child.Measure(double.PositiveInfinity, heightConstraint);
var childWidth = childSize.Width + (currentRow.Any() ? _layout.Spacing : 0);
var rowWidth = currentRow.Aggregate(0.0, (w, x) => w + x.Width);
if (rowWidth + childWidth > widthConstraint)
{
if (currentRow.Any())
{
currentRowIndex++;
currentRow = new List<Size>();
rows.Add(currentRowIndex, currentRow);
}
}
else if (currentRow.Any())
{
currentRow.Add(new Size(_layout.Spacing, 0));
}
currentRow.Add(childSize);
}
var totalWidth = 0.0;
var totalHeight = 0.0;
if (rows.Any())
{
var rowWidths = rows.Select(x => x.Value.Aggregate(0.0, (result, item) => result + item.Width)).ToList();
var rowHeights = rows.Select(x => x.Value.Any() ? x.Value.Max(i => i.Height) : 0).ToList();
totalWidth = rowWidths.Any() ? rowWidths.Max() : 0;
totalHeight = rowHeights.Any() ? rowHeights.Sum() : 0;
if (rows.Keys.Count > 1)
{
totalHeight += _layout.Spacing * (rows.Keys.Count - 1);
}
}
totalWidth += padding.HorizontalThickness;
totalHeight += padding.VerticalThickness;
var finalHeight = ResolveConstraints(heightConstraint, Stack.Height, totalHeight, Stack.MinimumHeight, Stack.MaximumHeight);
var finalWidth = ResolveConstraints(widthConstraint, Stack.Width, totalWidth, Stack.MinimumWidth, Stack.MaximumWidth);
return new Size(finalWidth, finalHeight);
}
public override Size ArrangeChildren(Rect bounds)
{
var padding = Stack.Padding;
double top = padding.Top + bounds.Top;
double left = padding.Left + bounds.Left;
double currentRowTop = top;
double currentX = left;
double currentRowHeight = 0;
double maxStackWidth = currentX;
for (int n = 0; n < _layout.Count; n++)
{
var child = _layout[n];
if (child.Visibility == Visibility.Collapsed)
{
continue;
}
if (currentX + child.DesiredSize.Width > bounds.Right)
{
// Keep track of our maximum width so far
maxStackWidth = Math.Max(maxStackWidth, currentX);
// Move down to the next row
currentX = left;
currentRowTop += currentRowHeight + _layout.Spacing;
currentRowHeight = 0;
}
var destination = new Rect(currentX, currentRowTop, child.DesiredSize.Width, child.DesiredSize.Height);
child.Arrange(destination);
currentX += destination.Width + _layout.Spacing;
currentRowHeight = Math.Max(currentRowHeight, destination.Height);
}
var actual = new Size(maxStackWidth, currentRowTop + currentRowHeight);
return actual.AdjustForFill(bounds, Stack);
}
Применение
<app:HorizontalWrapLayout
BindableLayout.ItemTemplate = "{x:StaticResource HorizontalWrapLayoutItemTemplate}"
BindableLayout.ItemsSource = "{Binding ControlGroups, Mode=OneWay}"
HorizontalOptions = "Center"
Spacing = "50"
VerticalOptions = "Center" />
Я протестировал предоставленный вами код в iOS, Windows в MAUI
. И он может правильно выровнять сетку заголовка по сетке в шаблоне данных в CollectionView. Таким образом, проблема может быть связана с services:DigitalInput
получением данных, они должны быть правильно отформатированы без пробелов в этих свойствах.
Ниже приведен пример кода и работающий вывод, надеюсь, он прольет вам свет!
XAML:
<CollectionView ItemsSource = "{Binding digitalInputs}">
<CollectionView.Header>
<Grid ColumnDefinitions = "*,*,*,*">
<Label Text = "Name" Grid.Column = "0"/>
<Label Text = "Typ" Grid.Column = "1"/>
<Label Text = "Status" Grid.Column = "2"/>
<Label Text = "Aktiv" Grid.Column = "3"/>
</Grid>
</CollectionView.Header>
<CollectionView.ItemTemplate>
<DataTemplate >
<Grid ColumnDefinitions = "*,*,*,*">
<Label Text = "{Binding pName}" Grid.Column = "0"/>
<Label Text = "{Binding pDigitalType}" Grid.Column = "1"/>
<Label Text = "{Binding pValueText}" Grid.Column = "2"/>
<Label Text = "{Binding pActive}" Grid.Column = "3"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Код программной части:
public ObservableCollection<Model> digitalInputs { get; set; }
public NewPage1()
{
InitializeComponent();
//assign data
digitalInputs = new ObservableCollection<Model>()
{
new Model{pName = "KipSchalter", pDigitalType = "Zustand",pActive = "OFF", pValueText = "True" },
new Model{pName = "KipSchalter", pDigitalType = "Zustand",pActive = "OFF", pValueText = "True" },
new Model{pName = "Digital In 3", pDigitalType = "Zustand",pActive = "OFF", pValueText = "FALSE" },
new Model{pName = "Digital In 4", pDigitalType = "Zustand",pActive = "OFF", pValueText = "FALSE" }
}
;
BindingContext = this;
}
Выход iOS:
Вывод Windows:
Обновлять:
Похоже, это потенциальная проблема в среде IDE. При изменении свойства HorizontalOptions
в сетке, как предложил Джейсон, сетка заголовка правильно выравнивается с сеткой в ItemTemplate.
Проблема на самом деле возникает у меня только при работе в режиме отладки MacCatalyst, я должен был это сказать.
@fonzane Не беспокойтесь, я заметил, что изменение свойства HorizontalOptions
сработало. Пожалуйста, помогите принять это как ответ, так как это поможет другим, у кого есть аналогичная проблема. Заранее спасибо!
Да, изменение свойства HorizontalOptions, по-видимому, вызывает повторную визуализацию с помощью горячей перезагрузки XAML и исправляет первоначальную ложную визуализацию. У меня больше проблем в этом отношении.
Я ожидаю, что это сработает. Если вы установите уникальный цвет bg для каждой метки в заголовке, вы можете визуализировать размер каждого из них. Кажется, что контейнер для сетки заголовков больше, чем он есть на самом деле. Возможно, установите для параметров «Горизонтальные» значение «Заполнить» или «Заполнить и развернуть»?