Custom Alert/ActionSheet

Hi All, I'm facing a problem since 2 days. I'm trying to make my own ActionSheet/Alert.
1/ When the content is set, I add a Grid to encapsulate it.
2/ I set this gird as my content of the page
3/ I use the grid created before to display my Alert/Popups.

Let see the code of my HomePage :

public class HomePage : ContentPage
{
    public HomePage()
    {
        Grid = new Grid
        {
            RowDefinitions = new RowDefinitionCollection() { new RowDefinition() { Height = GridLength.Star } },
            ColumnDefinitions = new ColumnDefinitionCollection() { new ColumnDefinition() { Width = GridLength.Star } },
            VerticalOptions = LayoutOptions.FillAndExpand,
            HorizontalOptions = LayoutOptions.FillAndExpand,
            ColumnSpacing = 0,
            RowSpacing = 0,
        };

    }

    Grid Grid { get; set; }
    bool IsGridSet;
    protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        if (propertyName == ContentProperty.PropertyName)
        {
            if (!IsGridSet)
            {
                IsGridSet = true;
                Grid.Children.Add(Content);
                Content = Grid;
            }
        }
        base.OnPropertyChanged(propertyName);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="t"></param>
    /// <returns></returns>
    public async Task ShowLoading(Task t)
    {
        // Put it a grid
        var gridAlert = MakeAlterGrid();

        gridAlert.Children.Add(new LoadingView());
        gridAlert.Opacity = 0;

        gridAlert.Opacity = 0;
        Grid.Children.Add(gridAlert);

        await gridAlert.FadeTo(1, 150);
        await t;
        await gridAlert.FadeTo(0, 150);
        Grid.Children.Remove(gridAlert);
    }


    /// <summary>
    /// Show custom alert
    /// </summary>
    /// <param name="Desc"></param>
    /// <param name="option"></param>
    /// <param name="title"></param>
    /// <returns></returns>
    public async Task DisplayHomeAlert(string title, string Desc, string option)
    {
        var gridAlert = MakeAlterGrid();

        // Make Grid Alert
        var pressed = false;
        var alert = new HomeAlertVIew()
        {
            Description = Desc,
            TextButton = option,
            Title = title,
            ButtonCommand = new Command(() =>
            {
                pressed = true;
            })
        };
        gridAlert.Children.Add(alert);
        Grid.Children.Add(gridAlert);

        var child = (Xamarin.Forms.View)alert.Children[0];
        alert.TranslationY = -(Height / 2) - (child.Height / 2);

        // Make animation and wait button tapped
        await gridAlert.FadeTo(1, 150);
        await alert.TranslateTo(alert.X, 0, 350, Easing.CubicInOut);
        await Task.Run(() =>
        {
            while (!pressed)
            { }
        });
        await gridAlert.FadeTo(0, 150);
        // Back to MainContent
        Grid.Children.Remove(gridAlert);
    }


    /// <summary>
    /// Show custom home action sheet
    /// </summary>
    /// <param name="Desc"></param>
    /// <param name="option1"></param>
    /// <param name="option2"></param>
    /// <param name="title"></param>
    /// <returns></returns>
    public async Task<int> DisplayHomeActionSheet(string title, string Desc, string option1, string option2)
    {
        var gridAlert = MakeAlterGrid();

        var pressed = false;
        int buttonTapped = 0;
        var alert = new HomeActionSheet()
        {
            Title = title,
            Description = Desc,
            TextButton1 = option1,
            TextButton2 = option2,
            Button1Command = new Command(() =>
            {
                buttonTapped = 1;
                pressed = true;
            }),
            Button2Command = new Command(() =>
            {
                buttonTapped = 2;
                pressed = true;
            })
        };
        gridAlert.Children.Add(alert);
        Grid.Children.Add(gridAlert);

        var child = (Xamarin.Forms.View)alert.Children[0];
        alert.TranslationY = -(Height / 2) - (child.Height / 2);

        // Make animation and wait button tapped
        await gridAlert.FadeTo(1, 150);
        await alert.TranslateTo(alert.X, 0, 350, Easing.CubicInOut);
        await Task.Run(() => { while (!pressed) { } });
        await gridAlert.FadeTo(0, 150);
        Grid.Children.Remove(gridAlert);
        return buttonTapped;
    }

    /// <summary>
    /// Make a opac backgrdoun to show an alert
    /// </summary>
    /// <returns></returns>
    Grid MakeAlterGrid()
    {
        var gridAlert = new Grid
        {
            RowDefinitions = new RowDefinitionCollection() { new RowDefinition() { Height = GridLength.Star } },
            ColumnDefinitions = new ColumnDefinitionCollection() { new ColumnDefinition() { Width = GridLength.Star } },
            VerticalOptions = LayoutOptions.FillAndExpand,
            HorizontalOptions = LayoutOptions.FillAndExpand
        };

        var box = new BoxView
        {
            HorizontalOptions = LayoutOptions.FillAndExpand,
            VerticalOptions = LayoutOptions.FillAndExpand,
            BackgroundColor = (Color)Application.Current.Resources["BlackAlpha50"]
        };
        gridAlert.Children.Add(box);
        gridAlert.Opacity = 0;
        return gridAlert;
    }

}

So what is the problem ? Because my page is display as I design it ... but it seems to be deactivate. I cannot click on button, on entry or any other component .... I thought that another element was over my content, but no only one Children.

More surprising one when i try to do the same exactly code which is OnPropertyChanged(), but after that the page is loaded and by a action from a button ..... It's work.

It probably came from lifecycle of my page or something I missing ... I tried many of many ideas but nothing made it works.

Please help !

Best Answer

  • MaxenceMaxMaxenceMax ✭✭
    Accepted Answer

    I finally get a solution :smile:
    public class HomePage : ContentPage
    {
    public HomePage()
    {
    Grid = new Grid
    {
    RowDefinitions = new RowDefinitionCollection() { new RowDefinition() { Height = GridLength.Star } },
    ColumnDefinitions = new ColumnDefinitionCollection() { new ColumnDefinition() { Width = GridLength.Star } },
    VerticalOptions = LayoutOptions.FillAndExpand,
    HorizontalOptions = LayoutOptions.FillAndExpand,
    ColumnSpacing = 0,
    RowSpacing = 0,
    };
    }

        public static BindableProperty HomeContentProperty = BindableProperty.Create(nameof(HomeContent), typeof(Xamarin.Forms.View), typeof(HomePage));
        public Xamarin.Forms.View HomeContent
        {
            get => (Xamarin.Forms.View)GetValue(HomeContentProperty);
            set => SetValue(HomeContentProperty, value);
        }
    
        Grid Grid { get; set; }
        protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);
            if (HomeContentProperty.PropertyName == propertyName)
            {
                if (HomeContent != null)
                {
                    Grid.Children.Add(HomeContent);
                    Content = Grid;
                }
            }
        }
    

    And I can show my alert from anywhere I want.

Answers

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    Can you upload a demo for this issue. You can add a break point in your Button or Entry code, when you click on it, If you code executed? I cannot reproduce this by your posted code.

  • MaxenceMaxMaxenceMax Member ✭✭

    Thanks @LeonLu for you answer. Here is a sample with a simplify HomePage, and what I want to achieve. Thank's a lot if you found a way to do that, or a different way.

    https://github.com/MaxenceMax/TestAlerts

  • LeonLuLeonLu Member, Xamarin Team Xamurai

    You demo just have a Button, can this demo that reproduce your issue? :'( , If you want to execute the click event for Button , you should add the <Button Text="Oui" Clicked="Button_Clicked" /> , If you use MVVM, you should use <Button Command="{Binding ChangeValueCommand}"/> then add the public ICommand ChangeValueCommand { protected set; get; } in your viewModel, in the achieve it in your constructor

       ChangeValueCommand = new Command<Person>((key) =>
            {
                persons[0].Name = "ssssssssssss";
                persons[0].Changed = true;
    
            });
    

    Do not want to bindingContext for your viewModel.

  • MaxenceMaxMaxenceMax Member ✭✭
    Accepted Answer

    I finally get a solution :smile:
    public class HomePage : ContentPage
    {
    public HomePage()
    {
    Grid = new Grid
    {
    RowDefinitions = new RowDefinitionCollection() { new RowDefinition() { Height = GridLength.Star } },
    ColumnDefinitions = new ColumnDefinitionCollection() { new ColumnDefinition() { Width = GridLength.Star } },
    VerticalOptions = LayoutOptions.FillAndExpand,
    HorizontalOptions = LayoutOptions.FillAndExpand,
    ColumnSpacing = 0,
    RowSpacing = 0,
    };
    }

        public static BindableProperty HomeContentProperty = BindableProperty.Create(nameof(HomeContent), typeof(Xamarin.Forms.View), typeof(HomePage));
        public Xamarin.Forms.View HomeContent
        {
            get => (Xamarin.Forms.View)GetValue(HomeContentProperty);
            set => SetValue(HomeContentProperty, value);
        }
    
        Grid Grid { get; set; }
        protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            base.OnPropertyChanged(propertyName);
            if (HomeContentProperty.PropertyName == propertyName)
            {
                if (HomeContent != null)
                {
                    Grid.Children.Add(HomeContent);
                    Content = Grid;
                }
            }
        }
    

    And I can show my alert from anywhere I want.

Sign In or Register to comment.