.NET MAUI Как сделать правильный Gridlayout в Collectionview с заголовком?

Я пытаюсь создать таблицу в .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.

Я ожидаю, что это сработает. Если вы установите уникальный цвет bg для каждой метки в заголовке, вы можете визуализировать размер каждого из них. Кажется, что контейнер для сетки заголовков больше, чем он есть на самом деле. Возможно, установите для параметров «Горизонтальные» значение «Заполнить» или «Заполнить и развернуть»?

Jason 16.02.2023 17:43

Когда я изменяю свойство при запуске приложения в режиме отладки, XAML HotReload запускает повторную визуализацию представления, и сетка идеально выравнивается.

fonzane 17.02.2023 13:22
Стоит ли изучать 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
2
71
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Если вы имеете в виду сначала расположить дочерние элементы по горизонтали, а затем перейти к следующей строке, то текущий 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 17.02.2023 13:15

@fonzane Не беспокойтесь, я заметил, что изменение свойства HorizontalOptions сработало. Пожалуйста, помогите принять это как ответ, так как это поможет другим, у кого есть аналогичная проблема. Заранее спасибо!

Alexandar May - MSFT 20.02.2023 06:59

Да, изменение свойства HorizontalOptions, по-видимому, вызывает повторную визуализацию с помощью горячей перезагрузки XAML и исправляет первоначальную ложную визуализацию. У меня больше проблем в этом отношении.

fonzane 20.02.2023 10:06

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