adospace / reactorui-maui

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

Issue updating State #123

Closed MattePozzy closed 1 year ago

MattePozzy commented 1 year ago

Hi, I have a page that have as content a "base render" controls that includes an alert made with SfPopup.

The text of this alert is bound to a State property (State._AlertState.MsgAlert).

To set the text I have made the method SetText like this:

public VolosPopUp SetText(Func<string> textFunc)
        {
            Init();

            this.Set(Syncfusion.Maui.Popup.SfPopup.ContentTemplateProperty,
                new MauiControls.DataTemplate(() => TemplateHost.Create(DefaultLabelText(textFunc)).NativeElement));

            return this;
        }

Then I have created the method "ApriAlert" that set the bounded property to true in order to open the popup and set its text:

public void ApriAlert(string messaggio, string headerText = "", Action callbackOk = null)
        {
            MainThread.BeginInvokeOnMainThread(() =>
            {
                SetState(s =>
                {
                    s._AlertState = new BaseAlertState
                    {
                        HeaderAlert = headerText,
                        MsgAlert = messaggio,
                        CallbackAlertOk = callbackOk,
                        ApriAlertOk = true
                    };
                }, false);
            });
        }

The issue occurs when I set false to SetState to avoid re-render the full page. If I leave the SetState to re-render the page all works fine, but if I set false the invalidateComponent, the text of the popup is not updated.

Here a sample where the label on the page is bounded to the same property used to set the text of the popup; the label text is correctly update but the popup text doesn't.

How can I fix this issue?

image

Thank you.

adospace commented 1 year ago

Hi, if you don't invalidate the component (set invalidateComponent: false) only the properties fed with a function (i.e. : .Text(()=>State.MyText)) are updated.

I've looked at your code but sorry I can't get the point of creating such overlaying complex structures that are really hard to follow.

Maybe you can just let me know what you're trying to do and I'll be happy to show you the MauiReactor way to do it.

MattePozzy commented 1 year ago

Thank you for the reply. In my application I need to have a ready to use alert dialog (implemented with SfPopup) because am I moving an enterprise app from xamarin to maui and I have choose to use MauiReactor to do so.

In the xamarin forms app there was a single instance of a SfPopup that was shown\hide at runtime, so I need to reproduce the same beahavior here.

I have understood that in MauiReactor all is based on State, so I thought to add an alert to all my pages (the baserender function basically do this) and create a function (ApriAlert) that set to TRUE the state's property bounded to IsOpen method of the popup. Also I have bounded the Text and HeaderText to others state properties but them doesn't change correctly.

EDIT: In the previous xamarin forms application I could create an instance of SfPopup at runtime and then open it. In MauiReactor, if I have understand correctly, the instance of SfPopup must be created and already present on page if I want to show it later, so the baserender method come to add the instance in every pages.

EDIT 2:

Hi, if you don't invalidate the component (set invalidateComponent: false) only the properties fed with a function (i.e. : .Text(()=>State.MyText)) are updated.

About this, the property to set the text is created in this way: .SetText(() => State._AlertState.MsgAlert)

I think that the issue is because the SetText method is created by me and is bounded to a DataTemplate.. its possible?

EDIT 3: I also tried to move the whole popup creation code from BaseRender inside the page, but the content and header text are not updated even so.

adospace commented 1 year ago

Regarding the state not being updated yes the problem could be that you created it using a custom DataTemplate.

Maybe I get your point, I think this is the case where the imperative approach works better than the declarative approach: so you have just to call a method like ShowPopup("My message") instead of declaring a new Popup() inside the render method and manage its state with an IsShown-like boolean property.

So to sum up, in your case I suggest creating a simple helper static class where you directly instantiate and manage the popup, without MauiReactor wrappers:

static class Utils
{
  public static void ShowPopup(string message)
  {
     //create a native syncfusion popup 
     var popup = new SfPopup();
     //customize popup (https://help.syncfusion.com/maui/popup/getting-started?cs-save-lang=1&cs-lang=csharp)
     //....
     popup.Show();

  }
}

and use it in your components when you need it:

Utils.ShowPopup("Hello!");

MattePozzy commented 1 year ago

Regarding the state not being updated yes the problem could be that you created it using a custom DataTemplate.

Maybe I get your point, I think this is the case where the imperative approach works better than the declarative approach: so you have just to call a method like ShowPopup("My message") instead of declaring a new Popup() inside the render method and manage its state with an IsShown-like boolean property.

So to sum up, in your case I suggest creating a simple helper static class where you directly instantiate and manage the popup, without MauiReactor wrappers:

static class Utils
{
  public static void ShowPopup(string message)
  {
     //create a native syncfusion popup 
     var popup = new SfPopup();
     //customize popup (https://help.syncfusion.com/maui/popup/getting-started?cs-save-lang=1&cs-lang=csharp)
     //....
     popup.Show();

  }
}

and use it in your components when you need it:

Utils.ShowPopup("Hello!");

Thank you!

I have re-used the template used for the "MauiReactor" version and use it with TemplateHost.Create(MyTemplate).NativeElement (so I don't need to rewrite the template) and now works.