muak / AiForms.Effects

AiForms.Effects for Xamarin.Forms
MIT License
245 stars 27 forks source link

Border disappears on the second call of the NavigationPage. #41

Closed Tum4ik closed 5 years ago

Tum4ik commented 5 years ago

I have two pages in my application: MainPage and SettingsPage. MainPage has a button to open the SettingsPage. I use Autofac as IoC container. Both my pages are singletons. My App class looks like:

public partial class App
{
  private IContainer _container;

  public App()
  {
    InitializeComponent();
    ConfigureServices();

    MainPage = new NavigationPage(_container.Resolve<MainPage>());
  }

  private void ConfigureServices()
  {
    var builder = new ContainerBuilder();

    builder.RegisterType<MainPage>().SingleInstance();
    builder.RegisterType<SettingsPage>().SingleInstance();

    _container = builder.Build();
  }
}

The MainPage code to show SettingsPage looks like:

[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage
{
  private readonly SettingsPage _settingsPage;

  public MainPage(SettingsPage settingsPage)
  {
    InitializeComponent();
    _settingsPage = settingsPage;
  }

  private async void SettingsButton_OnClicked(object sender, EventArgs e)
  {
    await Navigation.PushAsync(_settingsPage);
  }
 }

In the SettingsPage I've added some kind of a frame using AiForms.Effects:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:ef="clr-namespace:AiForms.Effects;assembly=AiForms.Effects"
             x:Class="Tum4ik.RemoteControl.Client.SettingsPage"
             Title="Settings">

  <ef:Floating.Content>
    <ef:FloatingLayout>
      <ef:FloatingView VerticalLayoutAlignment="Fill" HorizontalLayoutAlignment="Fill">
        <StackLayout ef:Border.On="True"
                     ef:Border.Width="4"
                     ef:Border.Color="Red"/>
      </ef:FloatingView>
    </ef:FloatingLayout>
  </ef:Floating.Content>

  <ContentPage.Content>
    <ScrollView>
      <StackLayout>
        <Entry x:Name="ClientIdEntry" Placeholder="Client ID" />
        <Entry x:Name="ServerIpEntry" Placeholder="Server IP" />
        <Entry x:Name="ServerPortEntry" Placeholder="Server Port" />
        <Entry x:Name="UsernameEntry" Placeholder="Username" />
        <Entry x:Name="PasswordEntry" Placeholder="Password" />
      </StackLayout>
    </ScrollView>
  </ContentPage.Content>

</ContentPage>

So, when I go to the SettingsPage I see the frame. But if I go back to the MainPage and then again go to the SettingPage the frame disappears. ezgif com-video-to-gif

Is that a bug or I am doing something wrong?

muak commented 5 years ago

@Tum4ik Thank you for your report.

AiForms.Effects removes each effect when the page has been popped. When a page is a singleton, once the page is popped, each effect will be not active when the page is pushed again.

If you want to active each effect each time page is pushed, you should use non-singleton instance or use bindings to notify true for "On" property when the page is pushed.

Tum4ik commented 5 years ago

Ok, I've understood, thanks for your clarification!

Tum4ik commented 5 years ago

hm... but actually I can't access the StackLayout element in the FloatingView. I guess it is because the StackLayout is not inside the ContentPage content.

Tum4ik commented 5 years ago

I still can't get the expected behavior. In some reason it doesn't work even if I use non-singleton pages. Because I never dispose the MainPage means never dispose SettingsPage.

muak commented 5 years ago

@Tum4ik

FloatingView's children can also be accessed by "x:Name" attribute. In the above code, attach "x:Name" attribute to the StackLayout.

About the issue of singleton, I think that it is solved by using "OnAppearing" and "OnDisappearing" methods:

<StackLayout x:Name="stacklayout">
...
protected override void OnAppearing()
{
    base.OnAppearing();
    AiForms.Effects.Border.SetOn(stacklayout, true);
}
protected override void OnDisappearing()
{
    base.OnDisappearing();
    AiForms.Effects.Border.SetOn(stacklayout, false);
}
Tum4ik commented 5 years ago

Hi @muak ,

Unfortunately your suggestion is not working. When I use just OnAppearing() method it has the same behavior (the frame disappears on the second settings page opening). When I add OnDisappearing() method it crashes the app when I try to open settings page second time.

Since you wrote "AiForms.Effects removes each effect when the page has been popped." I guess AiForms.Effects removes also the StackLayout element, because it is inside "ef:Floating.Content -> ef:FloatingLayout -> ef:FloatingView"

It seems only one way exists: create a new Settings page on every push. But in this case the DI is impossible what is not the purpose.

Tum4ik commented 5 years ago

Is it possible to implement functionality to avoid removing each effect when the page has been popped? I also use "AddTouch" feature and it also stops to work when I switch between different pages in my app.

Tum4ik commented 5 years ago

Ok, I've reconfigured the lifetime scopes for the pages. Now it works good.

muak commented 5 years ago

@Tum4ik I'm sorry for the delay of reply. It was good to resolve it.