.net MAUI 社区工具包弹出与页面不同的布局行为

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

我正在处理来自 .net MAUI Community Toolkit 的弹出窗口。 我目前正在弹出窗口中显示我的自定义控件。 但是,我注意到当控件显示在页面或弹出窗口中时,它们的布局存在差异。 当我的控件显示在弹出窗口中时,它们的元素的宽度将自动拉伸以填充所有可用空间(我不希望这样做,并且在页面上显示时它们不会这样做)。

例如,以下是我在页面和弹出窗口中显示相同控件时得到的两个渲染(注意

Show a popup
按钮宽度差异)

在页面中 在弹出窗口中

当我使用相同的控件时,我希望渲染结果是相同的。

我的问题是,为什么我的控件在页面或弹出窗口中显示时呈现不同?以及如何避免布局行为差异?

这是示例代码:

控制定义

namespace Medali.Views.Components
{
    public partial class TestComponent : ContentView
    {
        public TestComponent()
        {
            InitializeComponent();
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:Class="Medali.Views.Components.TestComponent"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:Medali.Views.Components"
             >
    <VerticalStackLayout Spacing="30" WidthRequest="500" BackgroundColor="Yellow" >
        <Label Text="Test"
               FontFamily="Inter700"
               FontSize="32"
               HeightRequest="60"
               HorizontalOptions="Center"
               TextColor="{StaticResource Blue}"
               VerticalTextAlignment="Center"
               HorizontalTextAlignment="Center"
               />
        <controls:ButtonComponent Text="Test button - Fill"
                                  FillContainer="True"
                                 />
        <controls:ButtonComponent Text="Test button - No fill"
                                  FillContainer="True"
                                 />
    </VerticalStackLayout>
</ContentView>

弹出定义

using CommunityToolkit.Maui.Views;
using CommunityToolkit.Mvvm.Input;
using Medali.ViewModels.Components;

namespace Medali.Views.Components
{
    public partial class ComponentPopup: Popup
    {
        public ComponentPopup(int width, int height, Color backgroundColor)
        {
            InitializeComponent();
            Size = new Size(width, height);
            mainFrame.BackgroundColor = backgroundColor;
        }

        public T setComponent<T>() where T : ContentView, new()
        {
            mainFrame.Content = new T();
            return (T)mainFrame.Content;
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<mct:Popup x:Class="Medali.Views.Components.ComponentPopup"
           xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
           xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
           xmlns:controls="clr-namespace:Medali.Views.Components"
           xmlns:mct="clr-namespace:CommunityToolkit.Maui.Views;assembly=CommunityToolkit.Maui"
           x:Name="componentPopupComponent"
           CanBeDismissedByTappingOutsideOfPopup="False"
           Color="Transparent"
           >

    <Frame x:Name="mainFrame"
           CornerRadius="10"
           Padding="0"
            >
    </Frame>
</mct:Popup>

页面定义

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:DataType="viewmodel:ConnectionViewModel"
             x:Class="Medali.Views.Pages.ConnectionPage"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:controls="clr-namespace:Medali.Views.Components"
             xmlns:models="clr-namespace:Medali.Models.Pages"
             xmlns:viewmodel="clr-namespace:Medali.ViewModels.Pages"
             Title=""
             >

    <Grid BackgroundColor="{StaticResource White}">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="885*"/>
            <ColumnDefinition Width="1035*"/>
        </Grid.ColumnDefinitions>
        <Image Grid.Column="0"
               Aspect="Fill"
               Source="waves.png"
               />
        <Image Grid.Column="0"
               Margin="200,0,0,0"
               HeightRequest="250"
               HorizontalOptions="Start"
               Source="medali.png"
               WidthRequest="250"
               />

        <controls:AuthFormComponent Grid.Column="1"
                                    HorizontalOptions="FillAndExpand"
                                    VerticalOptions="Center"
                                    />
    </Grid>
</ContentPage>

按钮控件定义:

using CommunityToolkit.Mvvm.Input;
using Medali.Services;
using Medali.ViewModels.Components;

namespace Medali.Views.Components
{
    public partial class ButtonComponent : ContentView
    {
        private readonly ButtonComponentViewModel vm;

        public ButtonComponent()
        {
            InitializeComponent();
            vm = new() { paddingStyle = NoI, fillStyle = NoFillC, MainColor = ColorHelper.GetColor("DarkBlue") };
            updateColors();
            Loaded += (s, e) =>
            {
                contentContainer.Style = vm.paddingStyle;
                btnContainer.Style = vm.fillStyle;
            };
        }

        public static BindableProperty TypeProperty = BindableProperty.Create(
            nameof(Type),
            typeof(string),
            typeof(ButtonComponent),
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;

                switch (newValue as string)
                {
                    case "Secondary":
                        control.vm.MainColor = ColorHelper.GetColor("Blue");
                        break;
                    case "Confirm":
                        control.vm.MainColor = ColorHelper.GetColor("Green");
                        break;
                    case "Danger":
                        control.vm.MainColor = ColorHelper.GetColor("Red");
                        break;
                    case "Primary":
                    default:
                        control.vm.MainColor = ColorHelper.GetColor("DarkBlue");
                        break;
                }
                control.updateColors();
            }
        );
        public string Type
        {
            get => (string)GetValue(TypeProperty);
            set => SetValue(TypeProperty, value);
        }

        public static BindableProperty ImageLeftProperty = BindableProperty.Create(
            nameof(ImageLeft),
            typeof(string),
            typeof(ButtonComponent),
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;
                control.IconLeft.Source = newValue as string;
                control.IconLeft.IsVisible = true;
                if (control.ImageRight is null)
                {
                    control.vm.paddingStyle = control.ILeft;
                } else
                {
                    control.vm.paddingStyle = control.ILeftRight;
                }
            }
        );
        public string ImageLeft
        {
            get => (string)GetValue(ImageLeftProperty);
            set => SetValue(ImageLeftProperty, value);
        }

        public static BindableProperty ImageRightProperty = BindableProperty.Create(
            nameof(ImageRight),
            typeof(string),
            typeof(ButtonComponent),
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;
                control.IconRight.Source = newValue as string;
                control.IconRight.IsVisible = true;
                if (control.ImageLeft is null)
                {
                    control.vm.paddingStyle = control.IRight;
                } else
                {
                    control.vm.paddingStyle = control.ILeftRight;
                }
            }
        );
        public string ImageRight
        {
            get => (string)GetValue(ImageRightProperty);
            set => SetValue(ImageRightProperty, value);
        }

        public static BindableProperty FillContainerProperty = BindableProperty.Create(
            nameof(FillContainer),
            typeof(bool),
            typeof(ButtonComponent),
            defaultValue: false,
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;
                control.vm.fillStyle = ((bool)newValue ? control.FillC : control.NoFillC);
            }
        );
        public bool FillContainer
        {
            get => (bool)GetValue(FillContainerProperty);
            set => SetValue(FillContainerProperty, value);
        }

        public static BindableProperty TextProperty = BindableProperty.Create(
            nameof(Text),
            typeof(string),
            typeof(ButtonComponent),
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;

                control.lbl.Text = newValue as string;
            }
        );
        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }

        public static BindableProperty BgColorProperty = BindableProperty.Create(
            nameof(BgColor),
            typeof(Color),
            typeof(ButtonComponent),
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;
                if (newValue as Color is not null)
                {
                    control.vm.MainColor = (Color)newValue;
                }
                control.updateColors();
            }
        );
        public Color BgColor
        {
            get => (Color)GetValue(BgColorProperty);
            set => SetValue(BgColorProperty, value);
        }

        public static BindableProperty IsDisableProperty = BindableProperty.Create(
            nameof(IsDisable),
            typeof(bool),
            typeof(ButtonComponent),
            defaultValue: false,
            propertyChanged: (bindable, oldValue, newValue) =>
            {
                var control = (ButtonComponent)bindable;

                control.vm.isDisable = (bool)newValue;
                control.updateColors();
            }
        );
        public bool IsDisable
        {
            get => (bool)GetValue(IsDisableProperty);
            set => SetValue(IsDisableProperty, value);
        }

        public static BindableProperty AsyncActionCommandProperty = BindableProperty.Create(
            nameof(AsyncActionCommand),
            typeof(AsyncRelayCommand),
            typeof(ButtonComponent),
            null
        );
        public AsyncRelayCommand AsyncActionCommand
        {
            get => (AsyncRelayCommand)GetValue(AsyncActionCommandProperty);
            set => SetValue(AsyncActionCommandProperty, value);
        }

        public static BindableProperty ActionCommandProperty = BindableProperty.Create(
            nameof(ActionCommand),
            typeof(RelayCommand),
            typeof(ButtonComponent),
            null
        );
        public RelayCommand ActionCommand
        {
            get => (RelayCommand)GetValue(ActionCommandProperty);
            set => SetValue(ActionCommandProperty, value);
        }

        void setNewTintColor(Color color)
        {
            lbl.TextColor = color;
            IconLeftColor.TintColor = color;
            IconRightColor.TintColor = color;
        }
        void setNewBackgroundColor(Color color)
        {
            btnContainer.BackgroundColor = color;
        }
        void updateColors()
        {
            setNewTintColor(vm.GetTintColor());
            setNewBackgroundColor(vm.GetBackgroundColor());
        }

        void OnPointerEntered(object sender, PointerEventArgs e)
        {
            vm.isHover = true;
            updateColors();
        }

        void OnPointerExited(object sender, PointerEventArgs e)
        {
            vm.isHover = false;
            updateColors();
        }

        void OnTapGestureRecognizerTapped(object sender, TappedEventArgs args)
        {
            if (!IsDisable)
            {
                ActionCommand?.Execute(null);
                AsyncActionCommand?.Execute(null);
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentView x:DataType="viewmodel:ConnectionViewModel"
             x:Class="Medali.Views.Components.ButtonComponent"
             xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             xmlns:viewmodel="clr-namespace:Medali.ViewModels.Pages"
             >
    <ContentView.Resources>
        <Style x:Key="NoImage"
               x:Name="NoI"
               TargetType="HorizontalStackLayout"
               >
            <Setter Property="Padding" Value="32,0" />
        </Style>
        <Style x:Key="ImageLeft"
               x:Name="ILeft"
               TargetType="HorizontalStackLayout"
               >
            <Setter Property="Padding" Value="16,0,32,0" />
        </Style>
        <Style x:Key="ImageRight"
               x:Name="IRight"
               TargetType="HorizontalStackLayout"
               >
            <Setter Property="Padding" Value="32,0,16,0" />
        </Style>
        <Style x:Key="ImageLeftRight"
               x:Name="ILeftRight"
               TargetType="HorizontalStackLayout"
               >
            <Setter Property="Padding" Value="16,0" />
        </Style>

        <Style x:Key="FillContainer"
               x:Name="FillC"
               TargetType="Frame">
            <Setter Property="HorizontalOptions" Value="Fill" />
        </Style>
        <Style x:Key="NoFillContainer"
               x:Name="NoFillC"
               TargetType="Frame">
            <Setter Property="HorizontalOptions" Value="Center" />
        </Style>
    </ContentView.Resources>

    <Frame x:Name="btnContainer"
        CornerRadius="10"
           IsClippedToBounds="True"
           Padding="0"
           BorderColor="{StaticResource Black}"
           VerticalOptions="Center"
           HeightRequest="60"
            >
        <Frame
            HorizontalOptions="Fill"
            VerticalOptions="Fill"
            Padding="0"
            BorderColor="Transparent"
            BackgroundColor="Transparent"
            >
            <HorizontalStackLayout
                x:Name="contentContainer"
                HorizontalOptions="Center"
                VerticalOptions="Center"
                Spacing="16">
                <Image x:Name="IconLeft"
                       HeightRequest="55"
                       IsVisible="False"
                       WidthRequest="55"
                       >
                    <Image.Behaviors>
                        <toolkit:IconTintColorBehavior x:Name="IconLeftColor" TintColor="White"/>
                    </Image.Behaviors>
                </Image>

                <Label x:Name="lbl"
                       FontFamily="Inter700"
                       FontSize="24"
                       HorizontalTextAlignment="Center"
                       VerticalTextAlignment="Center"
                       TextColor="White"
                       />

                <Image x:Name="IconRight"
                       HeightRequest="55"
                       IsVisible="False"
                       WidthRequest="55"
                       >
                    <Image.Behaviors>
                        <toolkit:IconTintColorBehavior x:Name="IconRightColor" TintColor="White"/>
                    </Image.Behaviors>
                </Image>
            </HorizontalStackLayout>
        </Frame>
        <Frame.GestureRecognizers>
            <PointerGestureRecognizer PointerEntered="OnPointerEntered" PointerExited="OnPointerExited" />
            <TapGestureRecognizer Tapped="OnTapGestureRecognizerTapped"/>
        </Frame.GestureRecognizers>
    </Frame>
</ContentView>
.net popup maui
1个回答
0
投票

这是框架中的问题。 Frame是Xamarin.Forms中的一个控件,建议在MAUI中将Frame更改为Border。你可以查看这个答案关于Frame和Border之间的区别。 这里还有示例(.Net MAUI Xaml - 调整大小时调整文本和框架)以使用边框解决问题。

© www.soinside.com 2019 - 2024. All rights reserved.