adospace / reactorui-maui

MauiReactor is a MVU UI framework built on top of .NET MAUI
MIT License
552 stars 45 forks source link

Changing state on CommunityToolkit Popup OnClosed method doesn't update the view #203

Closed cris-m closed 5 months ago

cris-m commented 5 months ago

I was working on a Popup that contains a CollectionView. The collection view contains a list of countries. When choose a country, and click on Done Button, the selected country is returned as the result of the Popup. I update the Result State but it doesn't update on the view and the Button to show the Popup doesn't work when clicked.

https://github.com/adospace/reactorui-maui/assets/29815096/d5340d03-5b87-4c6c-8eb9-83cf8a93b150

Here is the project: Project37.zip

adospace commented 5 months ago

Hi @cris-m, sorry for the late reply. I've verified that the PopupHost you used was not updated with the latest version of MauiReactor and your specific use case (I'm about to update the Popup control on the test app of the MauiReactor solution).

Please remove the PopupHost class as it's not required but directly create the Popup control as follows:

class MainPageState
{
    //this is only required to prevent opening the popup twice on user double tap
    public bool IsShown { get; set; }

    public ObservableCollection<CountryInfo> Countries { get; set; } = [];

    //SelectedCountry must be a state property here (not a field of the class) because we want it maintained
    //after a SetState call
    public CountryInfo? SelectedCountry {get; set;} 
}

partial class MainPage : Component<MainPageState>
{
    private CommunityToolkit.Maui.Views.Popup? _popup;

    [Inject]
    private ICountryInfoService _countryService;

    protected override void OnMounted()
    {
        State.Countries = new ObservableCollection<CountryInfo>(_countryService.GetCountriesInfo());
        State.Result = _countryService.GetRegionInfoByName("Congo - Kinshasa");

        base.OnMounted();
    }

    public override VisualNode Render()
        => ContentPage(
                Grid([
                    Label(State.Result?.EnglishName)
                        .HorizontalTextAlignment(TextAlignment.Center),

                    Button("Choose Country")
                        .HCenter()
                        .VCenter()
                        .GridRow(1)
                        .OnClicked(ShowPopup),

                    new Controls.Popup(r => _popup = r)
                    {
                        Grid([
                            Grid([
                                Button("Cancel", () => _popup?.Close())
                                    .CornerRadius(0),
                                Button("Done", () => _popup?.Close(State.SelectedCountry))
                                    .CornerRadius(0)
                                    .GridColumn(1)
                            ])
                            .ColumnSpacing(10)
                            .Rows("*")
                            .Columns("* *")
                            .Padding(10),
                            new CollectionView()
                                .GridRow(1)
                                .OnSelected<CollectionView, CountryInfo>(OnSelectedItem)
                                .SelectionMode(MauiControls.SelectionMode.Single)
                                .ItemsSource(State.Countries, RenderItem)

                        ])
                        .Rows("Auto *")
                        .Columns("*")

                    }
                    .OnClosed((s,e) => SetState(s =>
                    {
                        s.IsShown = false;
                        s.SelectedCountry = (CountryInfo?)e.Result;
                    }))
                ])
                .Rows("* *")
                .Columns("*")
                .RowSpacing(20)
                .VCenter()
            );

    void ShowPopup()
    {
        if (ContainerPage != null && _popup != null && !State.IsShown)
        {
            State.IsShown = true;
            ContainerPage.ShowPopup(_popup);
        }
    }

    VisualNode RenderItem(CountryInfo? country)
        => Border(
            Label(country?.EnglishName)
            .TextColor(Colors.Black)
            .HorizontalTextAlignment(TextAlignment.Center)
        )
        .Padding(5);

    void OnSelectedItem(CountryInfo? selectedCountry)
    {
        SetState(s => s.SelectedCountry = selectedCountry);
    }
}

Let me know if it's now working for you too.

cris-m commented 5 months ago

I have remove the PopupHost and test the solution. The solution work, the state is update but I got the following error: 'Popup' does not contain a definition for 'OnClosed' and no accessible extension method 'OnClosed' accepting a first argument of type 'Popup' could be found (are you missing a using directive or an assembly reference?).

When the Popup is closed, the button OnClicked doesn't work.

adospace commented 5 months ago

this is working for me: Project37.zip

cris-m commented 5 months ago

Thanks you for the support, I had problem of namespaces. the problem have been fixed