Mr_LinDowsMac
Mr_LinDowsMac

Reputation: 2702

Can't bind IsBusy property

I have Page with an Activity Indicator with the following code:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyApp.ClientSearch" Title="Search">
  <ContentPage.Content>
    <StackLayout Orientation="Vertical">
      <StackLayout.Children>
        <SearchBar x:Name="txtSearchClient" TextChanged="OnTextChanged"></SearchBar>
        <ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" x:Name="indicadorCargando" />
        <ListView x:Name="lstClients"></ListView>
      </StackLayout.Children>
    </StackLayout>  
  </ContentPage.Content>
</ContentPage>

In the partial class associated to this xaml, I have:

namespace MyApp
{
    public partial class ClientSearch: ContentPage
    {
        public BusquedaClientes()
        {
            InitializeComponent();
        }

        async void OnTextChanged(object sender, TextChangedEventArgs e)
        {

            if (this.txtSearchClient.Text.Length >= 3)
            {
                var list_clients = App.ClientsManager.GetTasksAsync(txtSearchClient.Text);
                this.IsBusy = true;

                var template = new DataTemplate(typeof(TextCell));

                template.SetBinding(TextCell.DetailProperty, "name_ct");
                template.SetBinding(TextCell.TextProperty, "cod_ct");

                lstClients.ItemTemplate = template;
                lstClients.ItemsSource = await list_clients;

                this.IsBusy = false;

            }
        }
    }
}

As you can see, this.IsBusy is setting the Page property, so tried to bind to that property in the XAML. Unfortunetly it doesn't work:

<ActivityIndicator IsVisible="{Binding IsBusy}" IsRunning="{Binding IsBusy}" x:Name="indicadorCargando" />

How can I bind the values of the ActivityIndicator to the IsBusy page property? I already know that setting the values like this:

this.IsBusy = true;
indicadorCargando.IsVisible=true; 
indicadorCargando.IsRunning=true;

But I don't want to do that, I want to set one value instead of three.

Upvotes: 2

Views: 1863

Answers (3)

You need to give your page a name (x:Name="myPage") and then declare the binding using a reference to it using {Binding Source={x:Reference myPage}, Path=IsBusy} for the ActivityIndicator's IsVisible and IsRunning values. More info on this answer.

Upvotes: 2

DavidS
DavidS

Reputation: 2934

You certainly could go the route of a separate view model, which is not a bad idea. However for the specific question, it doesn't look like you're setting the BindingContext anywhere, so it isn't going to get the IsBusy property that you want.

I haven't tried setting the BindingContext for a control to itself, but something like this ought to work:

<ActivityIndicator
  IsVisible="{Binding IsBusy}"
  IsRunning="{Binding IsBusy}"
  x:Name="indicadorCargando"
  BindingContext="{x:Reference indicadorCargando}" />

Upvotes: 1

Fran&#231;ois
Fran&#231;ois

Reputation: 3274

Here is how I would rewrite it:

public class ClientSearch : ContentPage
    {
        public ClientSearch()
        {
            BindingContext = new ClientSearchViewModel();
            var stack = new StackLayout();
            var searchBar = new SearchBar();
            searchBar.SetBinding<ClientSearchViewModel>(SearchBar.TextProperty, x => x.Text);
            var actInd = new ActivityIndicator();
            actInd.SetBinding<ClientSearchViewModel>(ActivityIndicator.IsVisibleProperty, x => x.IsBusy);
            actInd.SetBinding<ClientSearchViewModel>(ActivityIndicator.IsRunningProperty, x => x.IsBusy);
            var lv = new ListView
            {
                ItemTemplate = new DataTemplate(() =>
                {
                    var txtCell = new TextCell();
                    txtCell.SetBinding<MyItemModel>(TextCell.TextProperty, x => x.Name_Ct);
                    txtCell.SetBinding<MyItemModel>(TextCell.TextProperty, x => x.Cod_Ct);
                    return txtCell;
                })
            };
            lv.SetBinding<ClientSearchViewModel>(ListView.ItemsSourceProperty, x => x.items);
            stack.Children.Add(searchBar);
            stack.Children.Add(actInd);
            stack.Children.Add(lv);
            Content = stack;
        }
    }

    public class ClientSearchViewModel : BaseViewModel
    {
        public string Text { get; set; }
        public bool IsBusy { get; set; }
        public IEnumerable<MyItemModel> items { get; set; }

        protected override async void OnPropertyChanged(string propertyName = null)
        {
            if (propertyName != nameof(Text) || Text.Length < 3) return;
            IsBusy = true;
            items = await App.ClientsManager.GetTasksAsync(Text);
            IsBusy = false;
        }
    }

    [ImplementPropertyChanged]
    public abstract class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

Upvotes: 0

Related Questions