.NET MAUI BindableLayout 在页面加载时不渲染

问题描述 投票:0回答:1

我已经为此苦苦挣扎了好几天,最后我要向社区询问: 我有一个 .NET MAUI 项目,其中涉及一个在 StackLayout 中包含 BindableLayout 的页面。 BindableLayout 的源数据是我从项目中其他地方引用的 ContentView 组件。视图模型中的数据加载正常,一切都如文档所述。它只是在页面加载时不加载内容。 这是超级有趣的部分: 如果在启用热重载的情况下进行调试时,我退格并替换“.”在行

<reusableViews:BathroomView Content="{Binding .}"/>

然后内容会加载,一切都会按照我的意愿进行。

这是我的父页面的 xaml:

<Grid>
    <Grid.RowDefinitions>
        <!--  Row 0: Fixed height for the button  -->
        <RowDefinition Height="*" />

        <!--  Row 1: Remaining space for the ScrollView  -->
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <!--  Row 1: ScrollView  -->
    <ScrollView
        x:Name="ScrollView"
        Grid.Row="0"
        VerticalOptions="FillAndExpand">
        <StackLayout>
            <!-- Display the BathroomView instances -->
            <StackLayout x:Name="BathroomsLayout" BindableLayout.ItemsSource="{Binding BathroomViews}">
                <BindableLayout.ItemTemplate>
                    <DataTemplate>
                        <!-- Directly render the BathroomView -->
                        <reusableViews:BathroomView Content="{Binding .}"/>
                    </DataTemplate>
                </BindableLayout.ItemTemplate>
            </StackLayout>
            <StackLayout x:Name="ScrollReference" />
        </StackLayout>
    </ScrollView>
    <AbsoluteLayout Grid.Row="0">
        <customControls:LoadingFrame x:Name="NewBathroomLoadingFrame" IsVisible="{Binding IsBusy}" />
    </AbsoluteLayout>
    <!--  Row 0: Button  -->
    <Border Grid.Row="1" Margin="0,10,0,10">
        <StackLayout Margin="0,10,0,10">
            <reusableViews:AdditionalCommentsView />
            <Button
                Clicked="AddNewBathroom_Clicked"
                HorizontalOptions="Center"
                Text="Add New Bathroom"
                VerticalOptions="Start" />
            <Button
                x:Name="BathroomsPageSubmitButton"
                Clicked="BathroomsPageSubmitButton_Clicked"
                Text="Submit Bathrooms Page" />
        </StackLayout>
    </Border>
</Grid>

父页面的cs:

public partial class BathroomsPage
{
    private PageMaster _pageMaster;
    private PageFunctions _pageFunctions;
    private bool _navigated;

    public BathroomsPage(PageMaster pageMaster, PageFunctions pageFunctions)
    {
        _pageMaster = pageMaster;
        _pageFunctions = pageFunctions;
        InitializeComponent();

        BindingContext ??= _pageMaster.BathroomsPageViewModel;
    }
}

pageMaster 和 pageFunctions 是单例并且表现良好。

这是我的 BathroomView xaml:

<ContentView
    x:Class="..."
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:buttons="http://schemas.syncfusion.com/maui"
    xmlns:customControls="clr-namespace:..."
    xmlns:maui="clr-namespace:FFImageLoading.Maui;assembly=FFImageLoading.Maui"
    xmlns:reusableViews="clr-namespace:...">
    <ContentView.Resources>
        <ResourceDictionary>
            <Style TargetType="HorizontalStackLayout">
                <Setter Property="HorizontalOptions" Value="Center" />
            </Style>
            <Style TargetType="customControls:ErrorLabel">
                <Setter Property="Margin" Value="0,10,0,0" />
            </Style>
        </ResourceDictionary>
    </ContentView.Resources>
    <ContentView.Content>
        <Frame>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <buttons:SfExpander
                    x:Name="BathroomsExpander"
                    Margin="0,15,0,15"
                    AnimationDuration="150"
                    ClassId="BathroomsExpander"
                    HorizontalOptions="Center"
                    IsExpanded="False"
                    Expanded="BathroomsExpander_Expanded">
                    <buttons:SfExpander.Header>
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="48" />
                            </Grid.RowDefinitions>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="35" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                            <HorizontalStackLayout HorizontalOptions="Center">
                                <Image
                                    Margin="40,0,2,2"
                                    Source="Resources/Images/bath.png"
                                    VerticalOptions="Center"
                                    WidthRequest="40" />
                                <Label
                                    Grid.Column="1"
                                    Margin="40,0,0,0"
                                    CharacterSpacing="0.25"
                                    FontAttributes="Bold"
                                    FontFamily="Roboto-Regular"
                                    FontSize="14"
                                    HorizontalTextAlignment="Center"
                                    Text="{Binding Bathroom.BathroomName}"
                                    VerticalOptions="CenterAndExpand" />
                            </HorizontalStackLayout>
                        </Grid>
                    </buttons:SfExpander.Header>
                    <buttons:SfExpander.Content>
                        <StackLayout Margin="0,10,0,0">
                            <StackLayout
                                Margin="0,0,20,0"
                                HorizontalOptions="Center"
                                Orientation="Horizontal">
                                <Label Text="Bathroom Name: " />
                                <Entry
                                    x:Name="BathOne"
                                    HorizontalTextAlignment="Center"
                                    Text="{Binding Bathroom.BathroomName}"
                                    WidthRequest="175" />
                                <!--<ImageButton
                                    x:Name="RemoveButton"
                                    Command="{Binding ViewModel.ClearNameCommand}"
                                    CommandParameter="{Binding Bathroom}"
                                    HeightRequest="30"
                                    Source="Resources/Images/remove.png"
                                    WidthRequest="15" />-->
                            </StackLayout>
                            <customControls:ErrorLabel Name="BathroomNameError" Text="Please give a name to this bathroom" />
                            <Label
                                FontAttributes="Bold"
                                HorizontalTextAlignment="Center"
                                Text="GFCI Outlets?" />
                            <StackLayout>
                                <HorizontalStackLayout>
                                    <RadioButton Content="Yes" IsChecked="{Binding Bathroom.GfciOutletsYes}" />
                                    <RadioButton Content="No" IsChecked="{Binding Bathroom.GfciOutletsNo}" />
                                    <RadioButton Content="No Outlet" IsChecked="{Binding Bathroom.GfciNoOutlet}" />
                                </HorizontalStackLayout>
                                <StackLayout x:Name="GfciFuncNonFuncLayout" IsVisible="{Binding Bathroom.GfciOutletsYes}">
                                    <HorizontalStackLayout HorizontalOptions="Center">
                                        <RadioButton Content="Functional" IsChecked="{Binding Bathroom.GfciFunc}" />
                                        <RadioButton Content="Non-Functional" IsChecked="{Binding Bathroom.GfciNonFunc}" />
                                    </HorizontalStackLayout>
                                    <StackLayout HorizontalOptions="Center" IsVisible="{Binding Bathroom.GfciNonFunc}">
                                        <Label HorizontalTextAlignment="Center" Text="Please describe the issue with the outlet:" />
                                        <Entry Text="{Binding Bathroom.GfciNonFuncEntry}" />
                                        <customControls:ErrorLabel Name="GfciNonFuncEntryError" Text="Please detail the problem with the outlet" />
                                    </StackLayout>
                                    <customControls:ErrorLabel Name="GfciFuncNonFuncError" Text="Please select functional or non-functional" />
                                </StackLayout>
                                <customControls:ErrorLabel Name="GfciYesNoNoOutletError" Text="Please select an option for the GFCI outlets" />
                            </StackLayout>
                            <StackLayout Margin="40,0,40,0">
                                <Border
                                    Margin="{OnPlatform Default='8,0,8,8',
                                                        WinUI='8,0,6,8',
                                                        MacCatalyst='8,0,6,8'}"
                                    Stroke="#CAC4D0"
                                    StrokeShape="RoundRectangle 8,8,8,8"
                                    StrokeThickness="{OnPlatform MacCatalyst=2,
                                                                 Default=1}"
                                    WidthRequest="{OnPlatform MacCatalyst=460,
                                                              WinUI=340}">
                                    <buttons:SfExpander AnimationDuration="150">
                                        <buttons:SfExpander.Header>
                                            <Grid>
                                                <Grid.RowDefinitions>
                                                    <RowDefinition Height="48" />
                                                </Grid.RowDefinitions>
                                                <Grid.ColumnDefinitions>
                                                    <ColumnDefinition Width="35" />
                                                    <ColumnDefinition Width="*" />
                                                </Grid.ColumnDefinitions>
                                                <Image
                                                    Margin="14,2,2,2"
                                                    Source="Resources/Images/commentplus.png"
                                                    VerticalOptions="Center" />
                                                <Label
                                                    Grid.Column="1"
                                                    Margin="10,0,0,0"
                                                    CharacterSpacing="0.25"
                                                    FontFamily="Roboto-Regular"
                                                    FontSize="14"
                                                    Text="Additional Comments"
                                                    VerticalOptions="CenterAndExpand" />
                                            </Grid>
                                        </buttons:SfExpander.Header>
                                        <buttons:SfExpander.Content>
                                            <Editor
                                                Margin="20"
                                                HeightRequest="200"
                                                Placeholder="Enter any additional info here"
                                                Text="{Binding Bathroom.AdditionalCommentsText}" />
                                        </buttons:SfExpander.Content>
                                    </buttons:SfExpander>
                                </Border>
                                <Border>
                                    <StackLayout Margin="0,20,0,20">
                                        <HorizontalStackLayout>
                                            <Image
                                                Margin="10"
                                                Source="Resources/Images/imagesicon.png"
                                                WidthRequest="30" />
                                            <Label
                                                FontAttributes="Bold"
                                                FontSize="Large"
                                                HorizontalTextAlignment="Center"
                                                Text="Images" />
                                        </HorizontalStackLayout>
                                        <!--  UPDATE NAME OF BUTTON  -->
                                        <Button
                                            x:Name="AddBathroomPhotoButton"
                                            Clicked="AddBathroomPhotoButton_Clicked"
                                            Text="Add Photo"
                                            WidthRequest="150" />
                                        <StackLayout x:Name="ImagesLayout" />
                                    </StackLayout>
                                </Border>
                            </StackLayout>
                        </StackLayout>
                    </buttons:SfExpander.Content>
                </buttons:SfExpander>
                <StackLayout Grid.Row="1">
                    <Button
                        Command="{Binding ViewModel.RemoveCommand}"
                        CommandParameter="{Binding Bathroom}"
                        Text="Remove Bathroom" />
                </StackLayout>
            </Grid>
        </Frame>
    </ContentView.Content>
</ContentView>

还有 BathroomView.xaml.cs:

using ECHI_Inspection_App_Maui.CustomControls;
using ECHI_Inspection_App_Maui.Helpers;
using Echi_Inspection_App_Maui.Models;
using Echi_Inspection_App_Maui.ViewModels.InspectionPageViewModels;
using Microsoft.Maui.Controls.Compatibility;
using Newtonsoft.Json;
using SQLite;
using Guid = System.Guid;
using FFImageLoading.Maui;
using StackLayout = Microsoft.Maui.Controls.StackLayout;
using System.Collections.ObjectModel;

namespace Echi_Inspection_App_Maui.Reusable_Views;

public partial class BathroomView
{
    public static readonly BindableProperty ViewModelProperty =
        BindableProperty.Create(nameof(ViewModel), typeof(BathroomsPageViewModel), typeof(BathroomView));

    public static readonly BindableProperty BathroomModelProperty =
        BindableProperty.Create(nameof(Bathroom), typeof(Bathroom), typeof(BathroomView));

    public BathroomsPageViewModel ViewModel
    {
        get => (BathroomsPageViewModel)GetValue(ViewModelProperty);
        set => SetValue(ViewModelProperty, value);
    }

    public Bathroom Bathroom
    {
        get => (Bathroom)GetValue(BathroomModelProperty);
        set => SetValue(BathroomModelProperty, value);
    }

    public BathroomView()
    {
        InitializeComponent();
    }

    private void DeletePhotoButton_Clicked(object? sender, EventArgs e)
    {
        if (sender is not Button button) return;
        // Get the parent StackLayout that contains both the CachedImage and the Button
        if (button.Parent is not StackLayout parentLayout) return;
        // Find the CachedImage within the parent StackLayout
        if (parentLayout.Children.FirstOrDefault(c => c is CachedImage) is not CachedImage cachedImage) return;
        // Remove the image source from your data collection
        var imageUrl = cachedImage.Source?.ToString();
        if (imageUrl != null)
        {
            Bathroom.Images.Remove(imageUrl);
            // Perform any additional cleanup or logic related to the image removal
            PageFunctions.DeletePhoto(imageUrl);
        }

        // Remove the CachedImage and the Button from the parent StackLayout
        parentLayout.Children.Remove(cachedImage);
        parentLayout.Children.Remove(button);
    }

    private async void AddBathroomPhotoButton_Clicked(object sender, EventArgs e)
    {
        var uploadedUrl = await PageFunctions.CapturePhotoAndGetUrl($"Interior WCF {Guid.NewGuid()}.jpg");

        if (uploadedUrl == null) return;

        Bathroom.Images.Add(uploadedUrl); //UPDATE THIS

        var deleteButton = new Button()
        {
            Text = "Delete",
            WidthRequest = 100,
            ClassId = "ImageButton",
        };

        deleteButton.Clicked += DeletePhotoButton_Clicked;

        ImagesLayout.Children.Add(new StackLayout()
        {
            Children =
            {
                new CachedImage()
                {
                    Source = uploadedUrl,
                    Aspect = Aspect.Center,
                    WidthRequest = 200
                },
                deleteButton
            }
        });
    }

    private static void AddImagesToStackLayout(StackLayout layout, ObservableCollection<string> images)
    {
        foreach (var image in images)
        {
            layout.Children.Add(new StackLayout()
            {
                Children =
                {
                    new CachedImage()
                    {
                        Source = image,
                        Aspect = Aspect.Center,
                        WidthRequest = 200
                    },
                    new Button()
                    {
                        Text = "Delete",
                        WidthRequest = 100,
                        ClassId = "ImageButton"
                    }
                }
            });
        }
    }

    private void BathroomsExpander_Expanded(object sender, Syncfusion.Maui.Expander.ExpandedAndCollapsedEventArgs e)
    {
        Bathroom.Images ??= [];

        if (!Bathroom.Images.Any()) return; //UPDATE THIS

        AddImagesToStackLayout(ImagesLayout, Bathroom.Images);

        var imageButtons = this.GetVisualTreeDescendants().OfType<Button>().Where(x => x.ClassId == "ImageButton")
            .ToList();

        foreach (var imageButton in imageButtons)
        {
            imageButton.Clicked += DeletePhotoButton_Clicked;
        }
    }
}

BathroomsExpander_Expanded() 是为了尝试加载 ContentView 底部的图像,因为另一个问题我不会在这里讨论。

重申一下有趣的部分:我可以删除并替换“.”在


    <reusableViews:BathroomView Content="{Binding .}"/>

一切都呈现良好。我认为这是最大的线索。它要么与渲染与数据的顺序有关,要么是框架中的错误,要么是我没有正确使用它。

应该直接使用 Angular

maui
1个回答
0
投票

首先,

BathroomView
?有史以来最酷的页面名称!

在这里,您创建了

BathroomView
的新实例,并将其内容设置为 ItemsSource 的项目,这又是
BathroomView
的对象。

这并不理想。您可以定义一个新的

ContentView
并将其
Content
设置为您的
BathroomView
对象。就像下面这样

 <DataTemplate>
        <!-- Directly render the BathroomView -->
        <ContentView Content="{Binding .}"/>
 </DataTemplate>
© www.soinside.com 2019 - 2024. All rights reserved.