У меня есть страница, содержащая три области (каждая VerticalStackLayout
с Label
и Frame
с CollectionView
) с двумя Buttons
внизу. Каждая из областей может отображаться или не отображаться в зависимости от базовых условий. Какая бы из областей ни была видимой (три, две или одна — и это могут быть любые две или любая одна), она должна расширяться, чтобы заполнить доступное пространство просмотра. Но мне не удалось найти правильную комбинацию элементов XAML, чтобы это произошло.
В настоящее время у меня есть эта структура:
<Grid
ColumnDefinitions = "*,*"
RowDefinitions = "*,60">
<VerticalStackLayout Grid.Row = "0" Grid.ColumSpan = "2">
<VerticalStackLayout IsVisible = "{Binding ConditionA}">
<Label Text = "States" />
<Frame HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
<VerticalStackLayout IsVisible = "{Binding ConditionB}">
<Label Test = "Topics" />
<Frame HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
<VerticalStackLayout IsVisible = "{Binding ConditionC}">
<Label Text = "Activities" />
<Frame HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
</VerticalStackLayout>
<Button Grid.Row = "1" Grid.Column = "0" />
<Button Grid.Row = "1" Grid.Column = "1" />
</Grid>
Без HeightRequest
на Frame
CollectionView
расширяется, чтобы заполнить всю страницу и ниже, убегая от нижней части страницы. Идея программного управления HeightRequest
(т. е. вычисления соответствующей высоты для отображаемых областей) просто не кажется правильной. Похоже, что расширение должно обрабатываться элементами XAML в зависимости от доступного пространства; например, HorizontalOptions = "CenterAndExpand"
или что-то в этом роде.
Таким образом, когда все три области видны, они должны отображать вечер по всей странице сверху вниз:
List A
+-----------------------------+
| |
| |
| |
| |
| |
| |
+-----------------------------+
List B
+-----------------------------+
| |
| |
| |
| |
| |
| |
+-----------------------------+
List C
+-----------------------------+
| |
| |
| |
| |
| |
| |
+-----------------------------+
+----------+ +-----------+
| Button | | Button |
+----------+ +-----------+
Но если только две области, высота областей должна быть увеличена, чтобы сбалансировать пространство просмотра:
List A
+------------------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
+------------------------------+
List C
+------------------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
+------------------------------+
+----------+ +-----------+
| Button | | Button |
+----------+ +-----------+
Или, если отображается только один регион, он должен заполнять доступное пространство просмотра:
List B
+------------------------------+
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
+------------------------------+
+----------+ +-----------+
| Button | | Button |
+----------+ +-----------+
ОБНОВЛЕНИЕ: вот что я сделал, основываясь на ответе.
XAML
<Grid
ColumnDefinitions = "*,*">
<Grid.RowDefinitions>
<RowDefinition x:Name = "MainArea" Height = "*" />
<RowDefinition x:Name = "ButtonArea" Height = "60" />
</Grid.RowDefinitions>
<VerticalStackLayout Grid.Row = "0" Grid.ColumSpan = "2">
<VerticalStackLayout x:Name = "StatesFilter" IsVisible = "{Binding ConditionA}">
<Label Text = "List A" />
<Frame x:Name = "StatesFrame" HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
<VerticalStackLayout x:Name = "TopicsFilter" IsVisible = "{Binding ConditionB}">
<Label Test = "List B" />
<Frame x:Name = "TopicsFrame" HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
<VerticalStackLayout x:Name = "ActivitiesFilter" IsVisible = "{Binding ConditionC}">
<Label Text = "List C" />
<Frame x:Name = "ActivitiesFrame" HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
</VerticalStackLayout>
<Button Grid.Row = "1" Grid.Column = "0" />
<Button Grid.Row = "1" Grid.Column = "1" />
</Grid>
Код программной части
protected override void OnSizeAllocated(double width, double height)
{
base.OnSizeAllocated(width, height);
// This is called twice, once with -1, -1 then the next call with
// the actual width and height.
if (Height > 0)
{
AdjustRegionHeight(height);
}
}
private void AdjustRegionHeight(double pageHeight)
{
double frameHeight;
double bottomSpace = 44;
int cnt = 0;
cnt += (StatesFilter.IsVisible) ? 1 : 0;
cnt += (TopicsFilter.IsVisible) ? 1 : 0;
cnt += (ActivitiesFilter.IsVisible) ? 1 : 0;
double fullHeight = pageHeight - ButtonArea.Height.Value;
frameHeight = (fullHeight / cnt) - bottomSpace;
StatesFrame.HeightRequest = (StatesFilter.IsVisible) ? frameHeight : 0;
TopicsFrame.HeightRequest = (TopicsFilter.IsVisible) ? frameHeight : 0;
ActivitiesFrame.HeightRequest = (ActivitiesFilter.IsVisible) ? frameHeight : 0;
}
Идея программного управления HeightRequest (т. е. вычисления соответствующей высоты для отображаемых областей) просто не кажется правильной. Похоже, что расширение должно обрабатываться элементами XAML в зависимости от доступного пространства;
Наоборот, идея программного управления HeightRequest, скорее всего, будет реализована.
Судя по вашему коду, я не знаю кода {Binding ConditionA}
. Итак, чтобы реализовать это требование: нажмите кнопку, чтобы изменить макет:
.xaml:
<ContentPage xmlns = "http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
x:Class = "MauiApp1.NewPage1"
Title = "NewPage1">
<Grid ColumnDefinitions = "*,*" RowDefinitions = "*,60">
<VerticalStackLayout Grid.Row = "0" Grid.ColumnSpan = "2">
<VerticalStackLayout x:Name = "ListA" IsVisible = "true">
<Label Text = "List A" />
<Frame x:Name = "FrameA" HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
<VerticalStackLayout x:Name = "ListB" IsVisible = "true">
<Label Text = "List B" />
<Frame x:Name = "FrameB" HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
<VerticalStackLayout x:Name = "ListC" IsVisible = "true">
<Label Text = "List C" />
<Frame x:Name = "FrameC" HeightRequest = "150">
<CollectionView />
</Frame>
</VerticalStackLayout>
</VerticalStackLayout>
<Button Grid.Row = "1" Grid.Column = "0" Clicked = "onlyOne"/>
<Button Grid.Row = "1" Grid.Column = "1" Clicked = "Two"/>
</Grid>
</ContentPage>
.xaml.cs:
public partial class NewPage1 : ContentPage
{
public NewPage1()
{
InitializeComponent();
}
private void onlyOne(object sender, EventArgs e)
{
//change the state of IsVisible of VerticalStackLayout
ListB.IsVisible = false;
ListA.IsVisible = false;
ListC.IsVisible = true;
FrameC.HeightRequest = 450;
}
private void Two(object sender, EventArgs e)
{
ListC.IsVisible = false;
ListB.IsVisible = true;
ListA.IsVisible = true;
FrameA.HeightRequest = 225;
FrameB.HeightRequest = 225;
}
}
Первая кнопка предназначена для отображения только одного региона (список C). Вторая кнопка заключается в том, что отображаются только две области (список A и B).
Возвращаясь к вашей ситуации, ConditionA/B/C change
эквивалентно нажатию кнопки выше. Вы можете добавить логику кода в Button.Clicked к функции ConditionA/B/C change
.
Собственно, я так и сделал в свое время. Тем не менее, это казалось неправильным, потому что теперь код должен знать об устройстве, на котором он работает, поскольку размер устройства может отличаться. Это заставило меня рассмотреть другие варианты. Но, безусловно, код программной части — это правильное место, где можно узнать о доступном пространстве.
В VerticalStackLayout нет механизма, который мог бы решить эту проблему. Вместо этого сделайте их 3-мя рядами сетки. В коде позади установите RowDefinitions в зависимости от того, какие из них видны.
*
за каждый видимый,0
за каждый скрытый.myGridName.RowDefinitions = new RowDefinitions ...
Если вы застряли, пытаясь понять, как это сделать, продвиньтесь как можно дальше и добавьте свой код к вопросу.