Cannot bind ListView to viewmodel observablecollection, but can bind to commands just fine?

Goobs1284Goobs1284 USMember ✭✭
edited March 2017 in Xamarin.Forms

How does this even happen?

So I've spent hours upon hours trying to get this to work, looking at 2 separate examples of how to bind an ObservableCollection to a listview. I can bind to the viewmodel just fine as on hour 3 I created a message dialog to make sure that the list was completely empty by getting some information out of this list. Here is what I've got so far:

XAML
    <ListView ItemsSource="{Binding icitems}">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <StackLayout x:Name="ViewCellStackLayout"
                                     Orientation="Horizontal">
                    <Label x:Name="NameLabel"
                                   Text="{Binding itemname}"/>
                    <Label x:Name="ItemNumLabel"
                                   Text="{Binding itemnum}"/>
                    <Label x:Name="ClassLabel"
                                   Text="{Binding classIcitem}"/>
                    <Label x:Name="LookupLabel"
                                   Text="{Binding lookup1}"/>
                    <Label x:Name="UPCNumLabel"
                                   Text="{Binding upcnum}"/>
                    <Label x:Name="BarcodeLabel"
                                   Text="{Binding barcode}"/>
                    <Label x:Name="BuyQTYLabel"
                                   Text="{Binding buyqty_mult}"/>
                    <Label x:Name="ConvLabel"
                                   Text="{Binding conv}"/>
                </StackLayout>
                </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

THE ICITEM CLASS
    public IcItem() { }

    [SQLite.PrimaryKey, SQLite.AutoIncrement]
    public int ID { get; set; }
    public string itemnum { get; set; }
    public string itemname { get; set; }
    public string classIcitem { get; set; }
    public string lookup1 { get; set; }
    public string upcnum { get; set; }
    public string barcode { get; set; }
    public int buyqty_mult { get; set; }
    public int conv { get; set; }
    public DateTime syncDate { get; set; }

VIEWMODEL
private ObservableCollection<IcItem> _icItems;
    public ObservableCollection<IcItem> icitems
    {
        get { return _icItems; }
        set { Set(() => icitems, ref _icItems, value); }
    }
Tagged:

Best Answer

Answers

  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭

    @Goobs1284

    There is nothing here showing your commands etc. Did you submit the post before you were done, by accident, because it seems to not describe the rest of the issue. You say you can bind to the collection.

    I can bind to the viewmodel just fine

    but.... {looking for the rest of the explanation}

    So I'm a little lost on the actual issue.

    Cannot bind ListView from viewmodel

    I'm hoping this is just a typo or bad wording and not what you're really trying to do. You can't really bind to the ListView from the ViewModel. The ViewModel doesn't have any knowledge of the view(s) that may or may not exist and may or may not be using it as the binding context.

    99% of the time these issues turn out to be BindingContext not being what we first think it is. We forget that BindingContext is inherited from containing elements etc. If it helps this tutorial does a pretty decent job of spelling out some of those little things we sometimes forget.
    https://redpillxamarin.com/2017/01/28/206-reusable-controls/

  • Goobs1284Goobs1284 USMember ✭✭

    @ClintStLaurent

    You are correct, as I am trying to bind the listview to the viewmodel's icitem collection.

    Here is some more info:

    BINDING CONTEXT:
        [XamlCompilation(XamlCompilationOptions.Compile)]
        public partial class PhysicalCountPage : IPageLifeTime
        {
            public PhysicalCountPage()
            {
                InitializeComponent();
                ((PhysicalCountViewModel)BindingContext).RefreshCommand.Execute(null);
            }
        }
    
    XAML FOR BUTTON:
            <Button VerticalOptions="End"
                    HorizontalOptions="Fill"
                    Text="test command"
                    Command="{Binding testCommand}"/>
    
    VIEWMODEL COMMANDS (includes botht the Refresh Command and test Command)
        public RelayCommand RefreshCommand
        {
            get
            {
                return _refreshCommand
                       ?? (_refreshCommand = new RelayCommand(
                           async () =>
                           {
                               try
                               {
                                   //Getting IcItems from a database
                                   //List<IcItem> items = await _barcodeDb.GetIcItems();
                                   //_icItems = new ObservableCollection<IcItem>(items);
                                   _icItems = new ObservableCollection<IcItem>();
                                   _icItems.Add(new IcItem { ID = 0, itemnum = "100", itemname = "test item 1", classIcitem = "class a", lookup1 = "lookup val", upcnum = "123456789", barcode = "987654321", buyqty_mult = 0, conv = 0 });
                                   await Task.Delay(0);
                               }
                               catch (Exception ex)
                               {
                                   var result = _dialog.ShowMessage(ex.Message,
                                         ResourceConstants.PopupDialogGeneralError,
                                         ResourceConstants.PopupDialogOkButton,
                                         null);
                               }
    
                           }));
            }
        }
    
        public RelayCommand testCommand
        {
            get
            {
                return _testCommand
                       ?? (_testCommand = new RelayCommand(
                           async () =>
                           {
                               try
                               {
                                   _icItems.Add(new IcItem { ID = 0, itemnum = "100", itemname = "test item 1", classIcitem = "class a", lookup1 = "lookup val", upcnum = "123456789", syncDate=DateTime.Now,barcode = "987654321", buyqty_mult = 0, conv = 0 });
                                   await _dialog.ShowMessage(icitems.Count.ToString()+"\n" + icitems[0].itemname, "totally");
                               }
                               catch (Exception ex)
                               {
                                   var result = _dialog.ShowMessage(ex.Message,
                                         ResourceConstants.PopupDialogGeneralError,
                                         ResourceConstants.PopupDialogOkButton,
                                         null);
                               }
    
                           }));
            }
        }
    
  • Goobs1284Goobs1284 USMember ✭✭

    @ClintStLaurent

    Other comment was somehow deleted, and would like to fix this before work ends, however:

    You are correct, I am trying to bind the icitems ObservableCollection from the viewmodel to that listview. I have a command attached to the button that displays the count/first element name in a dialog box to show that I at least have something to show and add items to trigger that the list grew. Here is all the rest:

    XAML:
            <Button VerticalOptions="End"
                    HorizontalOptions="Fill"
                    Text="test command"
                    Command="{Binding testCommand}"/>
    
    COMMANDS:
                public RelayCommand RefreshCommand
            {
                get
                {
                    return _refreshCommand
                           ?? (_refreshCommand = new RelayCommand(
                               async () =>
                               {
                                   try
                                   {
                                       //Getting IcItems from a database
                                       //List<IcItem> items = await _barcodeDb.GetIcItems();
                                       //_icItems = new ObservableCollection<IcItem>(items);
                                       _icItems = new ObservableCollection<IcItem>();
                                       _icItems.Add(new IcItem { ID = 0, itemnum = "100", itemname = "test item 1", classIcitem = "class a", lookup1 = "lookup val", upcnum = "123456789", barcode = "987654321", buyqty_mult = 0, conv = 0 });
                                       await Task.Delay(0);
                                   }
                                   catch (Exception ex)
                                   {
                                       var result = _dialog.ShowMessage(ex.Message,
                                             ResourceConstants.PopupDialogGeneralError,
                                             ResourceConstants.PopupDialogOkButton,
                                             null);
                                   }
    
                               }));
                }
            }
    
            public RelayCommand testCommand
            {
                get
                {
                    return _testCommand
                           ?? (_testCommand = new RelayCommand(
                               async () =>
                               {
                                   try
                                   {
                                       _icItems.Add(new IcItem { ID = 0, itemnum = "100", itemname = "test item 1", classIcitem = "class a", lookup1 = "lookup val", upcnum = "123456789", syncDate=DateTime.Now,barcode = "987654321", buyqty_mult = 0, conv = 0 });
                                       await _dialog.ShowMessage(icitems.Count.ToString()+"\n" + icitems[0].itemname, "totally");
                                   }
                                   catch (Exception ex)
                                   {
                                       var result = _dialog.ShowMessage(ex.Message,
                                             ResourceConstants.PopupDialogGeneralError,
                                             ResourceConstants.PopupDialogOkButton,
                                             null);
                                   }
    
                               }));
                }
            }
    
    BINDING CONTEXT:
            [XamlCompilation(XamlCompilationOptions.Compile)]
            public partial class PhysicalCountPage : IPageLifeTime
            {
                public PhysicalCountPage()
                {
                    InitializeComponent();
                    ((PhysicalCountViewModel)BindingContext).RefreshCommand.Execute(null);
                }
    
                public void CleanupPage()
                {
                }
            }
    
  • ClintStLaurentClintStLaurent USUniversity ✭✭✭✭✭
    edited March 2017

    @Goobs1284

    You are correct, I am trying to bind the icitems ObservableCollection from the viewmodel to that listview.

    Well... That's the problem. ViewModels by design don't know anything about views. They aren't supposed to. The problem here is architectural in nature. In other words, your design of trying to do this is turned around 180°.

  • Goobs1284Goobs1284 USMember ✭✭

    @ClintStLaurent then how do i set the itemsource for my list in xaml? The viewmodel is set to the binding context for the vview, but the listview still cant bind to the list in my viewmodel

  • JamesLaveryJamesLavery GBBeta, University ✭✭✭✭✭

    @Goobs1284 I think we need to see all your code, rather than just snippets. Can you attach a zip with a basic project exhibiting the problem?

Sign In or Register to comment.