Несколько ContentPresenters в одном ControlTemplate - PullRequest
1 голос
/ 20 сентября 2019

Возможно ли иметь несколько ContentPresenters в ControlTemplate?

Я создал CustomControl с двумя BindableProperties типа View: ReadonlyContent и WritableContent.ControlTemplate оборачивает два ContentPresenters, где Content связан либо с ReadonlyContent, либо с WritableContent.

. Он загадочным образом отображает содержимое только одного ContentPresenter, в этом случае всегда ReadonlyContent независимо от порядка ContentPresenters или чего-либо еще.

Итак, вопрос снова: возможно ли иметь два или более ContentPresenters в ControlTemplate?

ControlTemplate выглядит следующим образом:

<ContentView.ControlTemplate>
    <ControlTemplate>
        <Grid HorizontalOptions="Fill" VerticalOptions="Fill" RowSpacing="0" Margin="0" Padding="0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="40" />
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="40" />
            </Grid.ColumnDefinitions>

            <Button
                Grid.Column="2"
                ImageSource="{TemplateBinding IsReadonly, Converter={StaticResource BooleanToImageSourceConverter}}"
                BackgroundColor="Transparent"
                WidthRequest="40"
                HeightRequest="25"
                Padding="0"
                Clicked="OnToggleIsReadonly"
                x:Name="btnToggleEditMode"
                Margin="0" />
            <StackLayout Grid.Column="1" Orientation="Vertical">
                <ContentPresenter Content="{TemplateBinding ReadonlyContent, Mode=OneWay}" />
                <ContentPresenter Content="{TemplateBinding WriteableContent, Mode=OneWay}" />
            </StackLayout>
        </Grid>
    </ControlTemplate>
</ContentView.ControlTemplate>

, тогда как код позадиэлемент управления выглядит так:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ActivatableContent : ContentView
{
    public static readonly BindableProperty IsReadonlyProperty = BindableProperty.Create(
        "IsReadonly",
        typeof(bool),
        typeof(ActivatableContent),
        true,
        BindingMode.TwoWay,
        propertyChanged: OnIsReadonlyChanged);

    public static readonly BindableProperty ReadonlyContentProperty = BindableProperty.Create(nameof(ReadonlyContent), typeof(View), typeof(ActivatableContent), propertyChanged: OnReadonlyContentChanged);

    public static readonly BindableProperty WritableContentProperty = BindableProperty.Create(nameof(WritableContent), typeof(View), typeof(ActivatableContent), propertyChanged: OnWritableContentChanged);

    public bool IsReadonly
    {
        get { return (bool)GetValue(IsReadonlyProperty); }
        set
        {
            SetValue(IsReadonlyProperty, value);
        }
    }

    public View ReadonlyContent
    {
        get { return (View)GetValue(ReadonlyContentProperty); }
        set { SetValue(ReadonlyContentProperty, value); }
    }

    public View WritableContent
    {
        get  { return (View)GetValue(WritableContentProperty); }
        set { SetValue(WritableContentProperty, value); }
    }

    public ActivatableContent()
    {
        InitializeComponent();
    }

    private static void OnIsReadonlyChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        ((ActivatableContent)bindable).IsReadonly = (bool)newvalue;
    }

    private static void OnReadonlyContentChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var readonlyContent = (View)newvalue;
        ((ActivatableContent)bindable).ReadonlyContent = readonlyContent;
        SetInheritedBindingContext(readonlyContent, bindable.BindingContext);
    }

    private static void OnWritableContentChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var writableContent = (View)newvalue;
        ((ActivatableContent)bindable).WritableContent = writableContent;
        SetInheritedBindingContext(writableContent, bindable.BindingContext);
    }

    private void OnToggleIsReadonly(object sender, EventArgs e)
    {
        IsReadonly = !IsReadonly;
    }

    /// <summary>Method that is called when the binding context changes.</summary>
    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();

        var controlTemplate = ControlTemplate;
        if (ReadonlyContent != null && controlTemplate != null)
        {
            SetInheritedBindingContext(ReadonlyContent, BindingContext);
        }

        if (WritableContent != null && controlTemplate != null)
        {
            SetInheritedBindingContext(WritableContent, BindingContext);
        }
    }
}

1 Ответ

0 голосов
/ 23 сентября 2019

ContentPresenter всегда указывает на содержимое элемента управления, по умолчанию вы не можете определить два разных содержимого.

Однако мы можем сделать это в пользовательском элементе управления.Вы можете скачать папку ContentPresenterDemo с GitHub для справки.https://github.com/WendyZang/Test.git

Сначала определите два различных привязываемых свойства в вашем пользовательском элементе управления

public static readonly BindableProperty ReadonlyContentProperty = BindableProperty.Create(nameof(ReadonlyContent), typeof(View), typeof(CustomContentView));
    public View ReadonlyContent
    {
        get { return (View)GetValue(ReadonlyContentProperty); }
        set { SetValue(ReadonlyContentProperty, value); }
    }

    public static readonly BindableProperty WritableContentProperty = BindableProperty.Create(nameof(WritableContent), typeof(View), typeof(CustomContentView));
    public View WritableContent
    {
        get { return (View)GetValue(WritableContentProperty); }
        set { SetValue(WritableContentProperty, value); }
    }

Обратите внимание, не забудьте изменить ContentPage на ContentView в xaml.

Изатем определите два представления с шаблоном в Application.Resources.

<Application.Resources>
    <ControlTemplate x:Key="MyTemplate">
        <StackLayout>
            <ContentView Content="{TemplateBinding WritableContent}"/>
            <ContentView Content="{TemplateBinding ReadonlyContent}"/>
        </StackLayout>
    </ControlTemplate>

    <ContentView x:Key="MyContentView">
        <StackLayout>
            <Label Text="MyContentView" BackgroundColor="Red"></Label>
            <!--code here...-->
        </StackLayout>
    </ContentView>

    <ContentView x:Key="MyContentView2">
        <StackLayout>
            <Label Text="MyContentView2" BackgroundColor="Green"></Label>
            <!--code here...-->
        </StackLayout>
    </ContentView>

И затем используйте его на странице.

 <StackLayout>
        <local:CustomContentView ReadonlyContent="{StaticResource MyContentView}" 
                        WritableContent="{StaticResource MyContentView2}" 
                        ControlTemplate="{StaticResource MyTemplate}" />
    </StackLayout>

enter image description here

Или вы можете использовать Picker для создания нескольких ContentPresenters.

Определить Picker с несколькими ContentPresenters.

<Picker x:Name="picker" Title="Select a template" SelectedIndexChanged="SelectedIndexChanged">
      <Picker.ItemsSource>
        <x:Array Type="{x:Type x:String}">
          <x:String>Template 1</x:String>
          <x:String>Template 2</x:String>
          <x:String>Template 3</x:String>
          <x:String>Template 4</x:String>
        </x:Array>
      </Picker.ItemsSource>
    </Picker>

Вы можете загрузить с GitHub.https://github.com/CrossGeeks/ControlTemplateSample

enter image description here

...