Forum Xamarin.Forms

Access views from ControlTemplate during runtime

OlcodOlcod AUMember
edited May 2016 in Xamarin.Forms

Hi.
In my ControlTemplate I have an AbstractLayout that contains a loading container that is to be displayed while the http request returns the data.
The issue is that I cannot access the layout from the MainPage that is using that template and hence, I am not able to set ActivityIndicator to be visible.

Here is my code:
App.xaml
`
<Application.Resources>



... Template Definition ...

      <!-- LOADING Screen -->
      <AbsoluteLayout VerticalOptions="Fill"
                HorizontalOptions="Fill"
                AbsoluteLayout.LayoutFlags="All"
                AbsoluteLayout.LayoutBounds="0,0,1,1"
                IsVisible="{TemplateBinding BindingContext.Busy}"
                BackgroundColor="#CF000000"
                      x:Name="LoadingContainer">
        <StackLayout VerticalOptions="FillAndExpand"
                     HorizontalOptions="FillAndExpand"
                     AbsoluteLayout.LayoutFlags="All"
                     AbsoluteLayout.LayoutBounds="0,0.55,1,0.25">
          <ActivityIndicator IsRunning="True" />
          <Label Text="{TemplateBinding BindingContext.Status}"
                 HorizontalOptions="Center"
                 VerticalOptions="Center"
                 FontSize="18"
                 x:Name="LoadingStatus"/>

        </StackLayout>
      </AbsoluteLayout>

    </AbsoluteLayout>



  </ControlTemplate>
</ResourceDictionary>

</Application.Resources>
`

MainPage.xaml
`<?xml version="1.0" encoding="utf-8" ?>

<StackLayout Padding="0,20,0,20"
             Spacing="20"
             VerticalOptions="Center">
  <Entry x:Name="ElemEntry_Username"
         Placeholder="Username"
         Text="[email protected]"/>
  <Entry x:Name="ElemEntry_Password"
         Placeholder="Password"
         IsPassword="True"
         Text="password"/>

  <!-- SUBMIT BUTTON -->
  <StackLayout Padding="10,20,10,20"
               VerticalOptions="FillAndExpand"
               HorizontalOptions="FillAndExpand">
    <Button Text="Submit"
            Clicked="submitUserCreds"
            x:Name="ElemButton_Submit"/>
  </StackLayout>
</StackLayout>

`

MainPage.xaml.cs
`namespace XamarinTut.Pages
{
public partial class MainPage : ContentPage
{
PageStatus Status = new PageStatus();

    public MainPage()
    {
        Status.Name = "Log In";

        InitializeComponent();

        BindingContext = Status;
        NavigationPage.SetHasNavigationBar(this, false);

        Status.toggleBusy();
    }

    private async void submitUserCreds(object sender, EventArgs args)
    {
        Status.toggleBusy("Authenticating...");

        Globals.gv_Admin = new User(ElemEntry_Username.Text, ElemEntry_Password.Text);

        if (Globals.gv_Admin._Token != null)
        {
             Navigation.PushAsync(new Pages.Users());
         }
         else
         {
             DisplayAlert("Error", "Failed to authenticate...", "OK");
         }

        // Status.toggleBusy();
    }
}

}
`

PageStatus.cs
`class PageStatus : BindableObject
{
public static readonly BindableProperty NameProperty = BindableProperty.Create("Name", typeof(string), typeof(PageStatus), "ROLF", BindingMode.TwoWay);
public static readonly BindableProperty BusyProperty = BindableProperty.Create("Busy", typeof(bool), typeof(PageStatus), false, BindingMode.TwoWay);
public static readonly BindableProperty StatusProperty = BindableProperty.Create("Status", typeof(string), typeof(PageStatus), "Initializing...", BindingMode.TwoWay);

    public string Name {
        get { return (string)GetValue(NameProperty); }
        set { SetValue(NameProperty, value); }
    }
    public bool Busy {
        get { return (bool)GetValue(BusyProperty); }
        set { SetValue(BusyProperty, value); }
    }
    public string Status {
        get { return (string)GetValue(StatusProperty); }
        set { SetValue(StatusProperty, value); }
    }

    public PageStatus()
    {
        this.Name = "ROLF";
        this.Busy = true;
        this.Status = "Initializing";
    }



    public void toggleBusy(string message)
    { this.Status = message; this.Busy = true; }
    public void toggleBusy()
    { this.Busy = false; }
}`

What I am trying to achieve is so that the user doesn't stare at the screen while the http is doing it's thing.
The DataBinding does the it's thing and the Loading container evetualy appears, but only after the submitUserCreds function has finished the execution.

So accessing the LoadingContainer and LoadingStatus views during the runtime would solve my propblem.
Is there such a possibility?

Thank you in advance!!!

Best Answer

Answers

  • AdamPAdamP AUUniversity ✭✭✭✭✭

    @Olcod - using TemplateBinding and Binding can both refer to the same Bindable property. Hence I normally have an IsBusy property I bind to.

    The IsBusy property can also be attached to the IsVisible property or IsRunning property of an ActivityIndicator and hence switch it on and off with the changing of the IsBusy property.

  • OlcodOlcod AUMember
    edited May 2016

    Well, yes.
    What happens in the code is when the Submit button is clicked the submitUserCreds function is fired.
    Status.toggleBusy("Authenticating..."); - is setting the Status.Busy to true (which is bound to AbsoluteLayout.IsVisible)
    Globals.gv_Admin = new User(ElemEntry_Username.Text, ElemEntry_Password.Text); - is doing the http requests
    Finally at the end of the function there is Status.toggleBusy();, which sets Status.Busy to false (it's commented out just to test if the AbsoluteLayout is even getting the value it needs).

    The problem is that the AbsoluteLayout from the App.xaml gets the Status.Busy value only when the function is terminated. Or at least that what I think.
    Because the AbsoluteLayout appears only after the function exits.
    I guess while the thread is busy with the submitUserCreds function AbsoluteLayout is not getting the Status object.

  • OlcodOlcod AUMember

    So I tried to breakdown the issue to the basics and reduced my function to:
    private void submitUserCreds(object sender, EventArgs args) { Int64 i = 10000; while (i > 0) { i = i - 1; Label.Text = i.ToString(); } }

    What happens now is that the Label.Text gets assigned to 0 after the function is terminated.
    The line Label.Text = i.ToString(); form the while loop has no effect while the function is working.
    Is there a way around this? Can I somehow reload a view or something???

Sign In or Register to comment.