Xamarin.forms Can';无法使InputTransparent在自定义PopOver控件上工作

Xamarin.forms Can';无法使InputTransparent在自定义PopOver控件上工作,xamarin.forms,Xamarin.forms,我有以下Xamarin.Forms TemplatedView: using System; using System.Threading.Tasks; using System.Windows.Input; using Xamarin.Forms; namespace STM.Framework.Controls { [ContentProperty(nameof(Content))] public class PopOverLayout : TemplatedView

我有以下Xamarin.Forms TemplatedView:

using System;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;

namespace STM.Framework.Controls
{
    [ContentProperty(nameof(Content))]
    public class PopOverLayout : TemplatedView
    {
        public PopOverLayout()
        {
        }

        #region BoxViewTapCommand

        public static BindableProperty BoxViewTapCommandProperty = BindableProperty.Create(nameof(BoxViewTapCommand), typeof(ICommand), typeof(PopOverLayout), default(ICommand), defaultValueCreator: BoxViewTapCommandCreator);

        private static object BoxViewTapCommandCreator(BindableObject bindable)
        {
            return new Command(p => BoxViewTappedExecute(bindable as PopOverLayout, p));
        }

        private static void BoxViewTappedExecute(PopOverLayout bindable, object parameter)
        {
            bindable.IsOverlayVisible = !bindable.IsOverlayVisible;
            if (!bindable.IsOverlayVisible)
            {
                bindable.OverlayContent.InputTransparent = true;
            }
        }

        public ICommand BoxViewTapCommand
        {
            get { return (ICommand) GetValue(BoxViewTapCommandProperty); }
            set { SetValue(BoxViewTapCommandProperty, value); }
        }

        #endregion BoxViewTapCommand

        #region OverlayContent

        public static BindableProperty OverlayContentProperty = BindableProperty.Create(nameof(OverlayContent), typeof(VisualElement), typeof(PopOverLayout), default(VisualElement));

        public VisualElement OverlayContent
        {
            get { return (VisualElement) GetValue(OverlayContentProperty); }
            set { SetValue(OverlayContentProperty, value); }
        }

        #endregion OverlayContent

        #region Content

        public static BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(VisualElement), typeof(PopOverLayout), default(VisualElement));

        public VisualElement Content
        {
            get { return (VisualElement) GetValue(ContentProperty); }
            set { SetValue(ContentProperty, value); }
        }

        #endregion Content

        #region IsOverlayVisible

        public static BindableProperty IsOverlayVisibleProperty = BindableProperty.Create(nameof(IsOverlayVisible), typeof(bool), typeof(PopOverLayout), default(bool));

        public bool IsOverlayVisible
        {
            get { return (bool) GetValue(IsOverlayVisibleProperty); }
            set { SetValue(IsOverlayVisibleProperty, value); }
        }

        #endregion IsOverlayVisible
    }
}
App.xaml:

<Style TargetType="{x:Type controls:PopOverLayout}">
            <Setter Property="BackgroundColor" Value="#88000000" />
            <Setter Property="IsOverlayVisible" Value="False" />
            <Setter Property="ControlTemplate">
                <Setter.Value>
                    <ControlTemplate>
                        <Grid BackgroundColor="{TemplateBinding BackgroundColor}" >
                            <Grid.RowDefinitions>
                                <RowDefinition>
                                    <RowDefinition.Height>
                                        <OnIdiom x:TypeArguments="GridLength" Phone="0" Tablet="50" />
                                    </RowDefinition.Height>
                                </RowDefinition>
                                <RowDefinition Height="*" />
                                <RowDefinition>
                                    <RowDefinition.Height>
                                        <OnIdiom x:TypeArguments="GridLength" Phone="0" Tablet="50" />
                                    </RowDefinition.Height>
                                </RowDefinition>
                            </Grid.RowDefinitions>

                            <Grid.ColumnDefinitions>
                                <ColumnDefinition>
                                    <ColumnDefinition.Width>
                                        <OnIdiom x:TypeArguments="GridLength" Phone="0" Tablet="50" />
                                    </ColumnDefinition.Width>
                                </ColumnDefinition>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition>
                                    <ColumnDefinition.Width>
                                        <OnIdiom x:TypeArguments="GridLength" Phone="0" Tablet="50" />
                                    </ColumnDefinition.Width>
                                </ColumnDefinition>
                            </Grid.ColumnDefinitions>
                            <controls:EnhancedContentPresenter Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Grid.ColumnSpan="3"
                                                               Content="{TemplateBinding Content}" />
                            <BoxView Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Grid.ColumnSpan="3" 
                                     InputTransparent="{TemplateBinding IsOverlayVisible, Converter={StaticResource BooleanInversionConverter}, Mode=OneWay}"
                                     IsVisible="{TemplateBinding IsOverlayVisible}" 
                                    BackgroundColor="{TemplateBinding BackgroundColor}">
                                <BoxView.GestureRecognizers>
                                    <TapGestureRecognizer Command="{TemplateBinding BoxViewTapCommand}"></TapGestureRecognizer>
                                </BoxView.GestureRecognizers>
                            </BoxView>
                            <controls:EnhancedContentPresenter Grid.Row="1" Grid.Column="1" Content="{TemplateBinding OverlayContent}"
                                     InputTransparent="{TemplateBinding IsOverlayVisible, Converter={StaticResource BooleanInversionConverter}, Mode=OneWay}"
                                     IsVisible="{TemplateBinding IsOverlayVisible}" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
内容演示者:

public class EnhancedContentPresenter : ContentPresenter
{
    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();
        if (BindingContext != null && this.Content != null)
            SetInheritedBindingContext(this.Content, BindingContext);
    }
}
由于控件的性质,我想这很明显是我想要做的:如果覆盖是隐藏的,我不希望覆盖捕获点击(或其他)事件,而是表现得好像它根本不存在一样

然而,我似乎无法让它工作,因为有些东西一直在捕捉触摸事件,即使覆盖是隐藏的,InputTransparent设置为true


这个问题是否给任何人敲响了警钟?

我不确定templatedView是否仍有问题(因为它们确实缺少很多wpf功能),但这样做效果很好:

[ContentProperty(nameof(Content))]
public class PopOverLayout : RelativeLayout
{
    #region OverlayContent

    public static BindableProperty OverlayContentProperty = BindableProperty.Create(nameof(OverlayContent), typeof(View), typeof(PopOverLayout), default(View), propertyChanged: OverlayContentChanged);

    private static void OverlayContentChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var layout = bindable as PopOverLayout;
        if (layout == null)
            return;

        layout.UpdateOverlayContent();
    }

    public View OverlayContent
    {
        get { return (View) GetValue(OverlayContentProperty); }
        set { SetValue(OverlayContentProperty, value); }
    }

    #endregion OverlayContent

    #region Content

    public static BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(PopOverLayout), default(View), propertyChanged: ContentChanged);

    private static void ContentChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var layout = bindable as PopOverLayout;
        if (layout == null)
            return;

        layout.UpdateDisplayContent();
    }

    public View Content
    {
        get { return (View) GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    #endregion Content

    #region IsOverlayVisible

    public static BindableProperty IsOverlayVisibleProperty = BindableProperty.Create(nameof(IsOverlayVisible), typeof(bool), typeof(PopOverLayout), default(bool), propertyChanged: IsOverlayVisibleChanged);

    private static void IsOverlayVisibleChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var layout = bindable as PopOverLayout;
        if (layout == null)
            return;

        bool newState = (bool) newvalue;
        if (newState)
        {
            layout.ShowPopup();
        }
        else
        {
            layout.HidePopup();
        }
    }

    public bool IsOverlayVisible
    {
        get { return (bool) GetValue(IsOverlayVisibleProperty); }
        set { SetValue(IsOverlayVisibleProperty, value); }
    }

    #endregion IsOverlayVisible

    protected override void OnParentSet()
    {
        base.OnParentSet();
        UpdateDisplayContent();
        UpdateOverlayContent();
    }

    private View content;
    private RelativeLayout popup;

    private void UpdateDisplayContent()
    {
        if (content != null)
            this.Children.Remove(content);

        if (Content != null)
        {
            content = Content;
            this.Children.Add(content,
                Constraint.Constant(0),
                Constraint.Constant(0),
                Constraint.RelativeToParent(layout => layout.Width),
                Constraint.RelativeToParent(layout => layout.Height));

            Content.InputTransparent = IsOverlayVisible;
        }
    }

    private void UpdateOverlayContent()
    {
        if (popup != null)
            this.Children.Remove(popup);

        if (OverlayContent != null && IsOverlayVisible)
        {
            ShowPopup();
        }
    }

    private void HidePopup()
    {
        if (popup != null)
            this.Children.Remove(popup);

        OverlayContent.InputTransparent = true;
        Content.InputTransparent = false;
    }

    private void ShowPopup()
    {
        if (popup != null)
            this.Children.Remove(popup);

        popup = new RelativeLayout();
        popup.GestureRecognizers.Add(new TapGestureRecognizer() {Command = new Command(PopUpTapped)});
        popup.BackgroundColor = BackgroundColor;

        this.Children.Add(popup,
            Constraint.Constant(0),
            Constraint.Constant(0),
            Constraint.RelativeToParent(layout => layout.Width),
            Constraint.RelativeToParent(layout => layout.Height));

        popup.Children.Add(OverlayContent,
            Constraint.RelativeToParent(layout => layout.X + 20),
            Constraint.RelativeToParent(layout => layout.Y + 20),
            Constraint.RelativeToParent(layout => layout.Width - 40),
            Constraint.RelativeToParent(layout => layout.Height - 40));

        OverlayContent.InputTransparent = false;
        Content.InputTransparent = true;
    }

    private void PopUpTapped(object o)
    {
        this.IsOverlayVisible = !IsOverlayVisible;
    }
}

您确定模板绑定有效吗?“我以为没有。”丹尼尔说,根据调试,它确实有效,是的
[ContentProperty(nameof(Content))]
public class PopOverLayout : RelativeLayout
{
    #region OverlayContent

    public static BindableProperty OverlayContentProperty = BindableProperty.Create(nameof(OverlayContent), typeof(View), typeof(PopOverLayout), default(View), propertyChanged: OverlayContentChanged);

    private static void OverlayContentChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var layout = bindable as PopOverLayout;
        if (layout == null)
            return;

        layout.UpdateOverlayContent();
    }

    public View OverlayContent
    {
        get { return (View) GetValue(OverlayContentProperty); }
        set { SetValue(OverlayContentProperty, value); }
    }

    #endregion OverlayContent

    #region Content

    public static BindableProperty ContentProperty = BindableProperty.Create(nameof(Content), typeof(View), typeof(PopOverLayout), default(View), propertyChanged: ContentChanged);

    private static void ContentChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var layout = bindable as PopOverLayout;
        if (layout == null)
            return;

        layout.UpdateDisplayContent();
    }

    public View Content
    {
        get { return (View) GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    #endregion Content

    #region IsOverlayVisible

    public static BindableProperty IsOverlayVisibleProperty = BindableProperty.Create(nameof(IsOverlayVisible), typeof(bool), typeof(PopOverLayout), default(bool), propertyChanged: IsOverlayVisibleChanged);

    private static void IsOverlayVisibleChanged(BindableObject bindable, object oldvalue, object newvalue)
    {
        var layout = bindable as PopOverLayout;
        if (layout == null)
            return;

        bool newState = (bool) newvalue;
        if (newState)
        {
            layout.ShowPopup();
        }
        else
        {
            layout.HidePopup();
        }
    }

    public bool IsOverlayVisible
    {
        get { return (bool) GetValue(IsOverlayVisibleProperty); }
        set { SetValue(IsOverlayVisibleProperty, value); }
    }

    #endregion IsOverlayVisible

    protected override void OnParentSet()
    {
        base.OnParentSet();
        UpdateDisplayContent();
        UpdateOverlayContent();
    }

    private View content;
    private RelativeLayout popup;

    private void UpdateDisplayContent()
    {
        if (content != null)
            this.Children.Remove(content);

        if (Content != null)
        {
            content = Content;
            this.Children.Add(content,
                Constraint.Constant(0),
                Constraint.Constant(0),
                Constraint.RelativeToParent(layout => layout.Width),
                Constraint.RelativeToParent(layout => layout.Height));

            Content.InputTransparent = IsOverlayVisible;
        }
    }

    private void UpdateOverlayContent()
    {
        if (popup != null)
            this.Children.Remove(popup);

        if (OverlayContent != null && IsOverlayVisible)
        {
            ShowPopup();
        }
    }

    private void HidePopup()
    {
        if (popup != null)
            this.Children.Remove(popup);

        OverlayContent.InputTransparent = true;
        Content.InputTransparent = false;
    }

    private void ShowPopup()
    {
        if (popup != null)
            this.Children.Remove(popup);

        popup = new RelativeLayout();
        popup.GestureRecognizers.Add(new TapGestureRecognizer() {Command = new Command(PopUpTapped)});
        popup.BackgroundColor = BackgroundColor;

        this.Children.Add(popup,
            Constraint.Constant(0),
            Constraint.Constant(0),
            Constraint.RelativeToParent(layout => layout.Width),
            Constraint.RelativeToParent(layout => layout.Height));

        popup.Children.Add(OverlayContent,
            Constraint.RelativeToParent(layout => layout.X + 20),
            Constraint.RelativeToParent(layout => layout.Y + 20),
            Constraint.RelativeToParent(layout => layout.Width - 40),
            Constraint.RelativeToParent(layout => layout.Height - 40));

        OverlayContent.InputTransparent = false;
        Content.InputTransparent = true;
    }

    private void PopUpTapped(object o)
    {
        this.IsOverlayVisible = !IsOverlayVisible;
    }
}