How to override/modify the Content property of Frame to accept multiple Views in Xamarin.Forms?

房东的猫 提交于 2021-01-02 05:17:35

问题


Here's the C# template code I have:

public class PopupFrame : Frame
{
    public PopupFrame()
    {
        this.SetDynamicResource(BackgroundColorProperty, "PopUpBackgroundColor");
        this.SetDynamicResource(CornerRadiusProperty, "PopupCornerRadius");
        HasShadow = true;
        HorizontalOptions = LayoutOptions.FillAndExpand;
        Padding = 0;
        VerticalOptions = LayoutOptions.Center;
    }
}

I am using it like this:

<t:PopupFrame>
   <StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
         <t:PopupHeader Text="Copy Deck" />
         <t:PopupEntryHeader Text="New Deck Name" />
                
                More XAML here
   </StackLayout>
</t:PopupFrame>

Is there some way that I can code PopupFrame so that the StackLayout is part of it and it takes content.

Here's what I would like to code:

<t:PopupFrame>
   <t:PopupHeader Text="Copy Deck" />
   <t:PopupEntryHeader Text="New Deck Name" />
                
       More XAML here

</t:PopupFrame>

回答1:


If i am right, you could achieve this by setting the ContentProperty attribute to your PopupFrame class to a property that is itself a collection. This would override the ContentProperty of Frame which is Content to allow you to set multiple views as the contents instead of just one which is the default for Frame...

So, if all this sounds good to you, keep on reading.

The HowTo

You could define a ContentProperty for your PopupFrame class, like this:

[Xamarin.Forms.ContentProperty("Contents")]
class PopupFrame : Frame
{
    StackLayout contentStack { get; } = new StackLayout();

    public IList<View> Contents { get => contentStack.Children; }


    public PopupFrame()
    {
        Content = contentStack;

        HasShadow = true;
        HorizontalOptions = LayoutOptions.FillAndExpand;
        Padding = 0;
        VerticalOptions = LayoutOptions.Center;
    }
}

Then your are able to do something like what you want:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:t="clr-namespace:popupframe"
             x:Class="popupframe.MainPage">

    <StackLayout>
        <t:PopupFrame>
            <t:PopupHeader Text="Test header"/>
            <Label Text="Test content"/>
        </t:PopupFrame>
    </StackLayout>

</ContentPage>

Which on my side works showing both the PopupHeader and the Label:

And finally a bit of theory on ContentProperty

What follows is taken literally from the book of Ch. Petzold on Xamarin.Forms.

Every class used in XAML is allowed to define one property as a content property (sometimes also called the class’s default property). For this content property, the property-element tags are not required, and any XML content within the start and end tags is automatically assigned to this property. Very conveniently, the content property of ContentPage is Content, the content property of StackLayout is Children, and the content property of Frame is Content.

These content properties are documented, but you need to know where to look. A class specifies its content property by using the ContentPropertyAttribute. If this attribute is attached to a class, it appears in the online Xamarin.Forms API documentation along with the class declaration. Here’s how it appears in the documentation for ContentPage:

[Xamarin.Forms.ContentProperty("Content")]
public class ContentPage : TemplatedPage

If you say it aloud, it sounds a bit redundant: "The Content property is the content property of ContentPage."

The declaration for the Frame class is similar:

[Xamarin.Forms.ContentProperty("Content")]
public class Frame : ContentView

StackLayout doesn’t have a ContentProperty attribute applied, but StackLayout derives from Layout<View>, and Layout<T> has a ContentProperty attribute:

[Xamarin.Forms.ContentProperty("Children")]
public abstract class Layout<T> : Layout, IViewContainer<T>
where T : View

The ContentProperty attribute is inherited by the classes that derive from Layout<T>, so Children is the content property of StackLayout.




回答2:


PopupFrame.cs

public class PopupFrame : Frame
{
    StackLayout PopupContent;
    public IList<View> Body
    {
        get => PopupContent.Children;
    }
    public PopupFrame()
    {

        PopupContent = new StackLayout();

        SetDynamicResource(Frame.BackgroundColorProperty, "PopUpBackgroundColor");
        SetDynamicResource(Frame.CornerRadiusProperty, "PopupCornerRadius");
        HasShadow = true;
        HorizontalOptions = LayoutOptions.FillAndExpand;
        Padding = 0;
        VerticalOptions = LayoutOptions.Center;

        Content = PopupContent;
    }

Now you can use

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:t="clr-namespace:popupframe"
             x:Class="popupframe.MainPage">

    <StackLayout>
       <t:PopupFrame>
         <t:PopupFrame.Body>
             <t:PopupHeader Text="Test header"/>
             <Label Text="Test content"/>
           </t:PopupFrame.Body>
        </t:PopupFrame>
    </StackLayout>

</ContentPage>


来源:https://stackoverflow.com/questions/64843323/how-to-override-modify-the-content-property-of-frame-to-accept-multiple-views-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!