Zafeer Ul Haq
Zafeer Ul Haq

Reputation: 13

Binding ViewModel Property with ListView in View in Xamarin

I am just new to Xamarin. I am trying to bind the properties values with the ListView but not getting any success. Tried searching on the internet but it didnt worked. Also the property changed event is null always. This is my ViewModel

namespace DemoApp.ViewModels
{
    class MainViewModel : INotifyPropertyChanged
    {
        private ObservableCollection<ShippingDetail> ShippingDetailList { get; set; }

    public ObservableCollection<ShippingDetail> ShippingDetails

        {
            get { return ShippingDetailList; }
            set
            {
                ShippingDetailList = value;
                OnPropertyChanged("Changed");
            }
        }

         public async Task GetShippingDataAsync(string TrackID)
    {
        GenericRestClient<ShippingDetail> client = new GenericRestClient<ShippingDetail>();

        ShippingDetails = await client.GetAsyncByID(TrackID);

    }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string property)
        {
            var changed = PropertyChanged;

            if (changed == null)
                return;

            changed(this, new PropertyChangedEventArgs(property));
        }

    }
}

This is my View Xaml 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="DemoApp.TrackByID"
               Title="Mex World Wide"
             xmlns:local="clr-DemoApp"
             xmlns:ViewModels="clr-DemoApp.ViewModels">



    <ContentPage.BindingContext>
        <ViewModels:MainViewModel/>
    </ContentPage.BindingContext>

    <ContentPage.Content>
        <AbsoluteLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">

            <StackLayout AbsoluteLayout.LayoutFlags="All" AbsoluteLayout.LayoutBounds="0,0,1,1">
                <ScrollView>
                    <StackLayout>
                        <StackLayout Padding="30" Spacing="2" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
                            <Entry x:Name="TrackIDText"  HorizontalTextAlignment="Center" Placeholder="Enter Your Shipment Tracking ID" TextChanged="TrackID_TextChanged"></Entry>

                        </StackLayout>
                        <StackLayout Padding="30" VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
                            <Button x:Name="TrackBtn" Text="Track" IsEnabled="False" BackgroundColor="Olive" Clicked="TrackBtn_Clicked"/>
                            <Button x:Name="ScanBtn" Text="Scan Barcode" IsEnabled="True" BackgroundColor="Azure" Clicked="ScanBtn_Clicked"/>
                        </StackLayout>
                    </StackLayout>
                </ScrollView>
                <StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="FillAndExpand">
                    <ListView  x:Name="ShippingLV"
                  RowHeight="60"
                               ItemsSource="{Binding ShippingDetails}"/>
                </StackLayout>
            </StackLayout>

            <StackLayout x:Name="ActivityIndsL" IsVisible="False" Padding="12"
                 AbsoluteLayout.LayoutFlags="PositionProportional"
                 AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">

                <ActivityIndicator x:Name="TrackingActivity" Color ="#FF4081"/>

                <Label Text="Please Wait while Details are being fetched..." HorizontalOptions="Center" TextColor="#FF4081"/>

            </StackLayout>

        </AbsoluteLayout>


    </ContentPage.Content>


</ContentPage>

I am trying to bind the ShippingDetails with ListView as its ItemSource, which is called on button click event. Following is the code of XAML View

private async void TrackBtn_Clicked(object sender, EventArgs e)
    {
        MainViewModel obj = new MainViewModel();

        ActivityIndsL.IsVisible = true;
        TrackingActivity.IsRunning = true;

        TrackingActivity.IsVisible = true;
        TrackBtn.IsEnabled = false;
        ScanBtn.IsEnabled = false;

        await obj.GetShippingDataAsync(TrackIDText.Text);

        ActivityIndsL.IsVisible = false;
        TrackingActivity.IsRunning = false;
        TrackingActivity.IsVisible = false;
        TrackBtn.IsEnabled = true;
        ScanBtn.IsEnabled = true;



    }

Please Correct me where i am doing wrong. Thanks

Upvotes: 1

Views: 2858

Answers (1)

Timo Salom&#228;ki
Timo Salom&#228;ki

Reputation: 7189

A couple of things wrong with your code. First of all, you're calling OnPropertyChanged with a wrong value. It's supposed to be the name of the property that has changed, like this:

public ObservableCollection<ShippingDetail> ShippingDetails
{
    get { return ShippingDetailList; }
    set
    {
        ShippingDetailList = value;
        OnPropertyChanged("ShippingDetails");
    }
}

Also, you already set MainViewModel as your BindingContext in the XAML:

<ContentPage.BindingContext>
    <ViewModels:MainViewModel/>
</ContentPage.BindingContext>

There's no need to do it again in the button's clicked event. Instead of creating a new instance every time the button is clicked, I'd reference the already existing view model like this:

private async void TrackBtn_Clicked(object sender, EventArgs e)
{
    MainViewModel vm = this.BindingContext as MainViewModel;
    await vm.GetShippingDataAsync(TrackIDText.Text);
}

Edit: There's one more thing I'd fix in your code. I'd define ShippingDetailList as a private instance field since ShippingDetails property is used to expose it to the outside world. This won't really affect how your code works but it's closer to a proper C# way.

private ObservableCollection<ShippingDetail> shippingDetailList;

Here's some good reading material about fields, if you're interested.

Upvotes: 1

Related Questions