Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Binding a ListView

SmartmanAppsSmartmanApps AUMember ✭✭✭
edited April 2019 in Xamarin.Forms

I'm trying to display the images returned from a Bing image search, and there's something not quite right somewhere. I was able to get it working with a single image, but this is my first time using a ListView. As far as I can tell the VM code is working ok - i.e. not getting any error messages - just not seeing anything in the UI. Here's the relevant code...

VIEW
ListView ImageList;
ImageList=new ListView{};
ImageList.SetBinding( ListView.ItemsSourceProperty,new Binding("ImageResults",source: vm) );
(ImageList added to UI stack)

VM
private List<ImageObject> _imageResults;
public List<ImageObject> ImageResults
{
get { return _imageResults;}
set {
if (_imageResults != value) {
_imageResults=value;
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("ImageResults"));
}
}
}

ImageResults=(List<ImageObject>) client.Images.SearchAsync(query: searchterm).Result.Value;

thanks,
Donald.

Answers

  • jezhjezh Member, Xamarin Team Xamurai
    edited April 2019

    Are you achieving this app based on C#?If yes , you should add the listview to the ContentPage;

      Content = ImageList;
    
  • SmartmanAppsSmartmanApps AUMember ✭✭✭

    Thanks, but as noted in brackets, I'm adding it to a stack in the UI.

    @jezh said:
    Are you achieving this app based on C#?If yes , you should add the listview to the ContentPage;

      Content = ImageList;
    
    
     
    
  • NMackayNMackay GBInsider, University admin

    Host the Listview in a grid to ensure the StackLayout can fill so the Listview can calculate it's height. Doesn't work as you might expect otherwise. Also you Listview needs a DataTemplate.

  • SmartmanAppsSmartmanApps AUMember ✭✭✭

    @NMackay said:
    Host the Listview in a grid to ensure the StackLayout can fill so the Listview can calculate it's height. Doesn't work as you might expect otherwise. Also you Listview needs a DataTemplate.

    Well, having not used it before, I wasn't sure what to expect, :-) I only know it's not working yet (as usual, the doco/blogs on this topic don't cover what I'm trying to achieve - present all returned images so that the user can select from them - so I'm trying to put the pieces together as to how to make it work for my scenario). I'll check out those things you mentioned and let you know how I go. Thanks!

  • SmartmanAppsSmartmanApps AUMember ✭✭✭

    Well, maybe that's an issue with an ambiguous title. It says "Customizing ListView Cell Appearance", and since I don't want to do any "customizing" yet - juts get the basic view working first - I hadn't looked at that. If this is necessary for it to work to begin with, then perhaps "initializing" or similar might be a better wording (though that's not your issue). I think now this may be why it's not working, so thanks for pointing that out! :-)

  • SmartmanAppsSmartmanApps AUMember ✭✭✭

    So I've added some code for a DataTemplate to the best of my understanding of how it works from the MS DataTemplate doco (having never used one before), but still nothing coming through on the UI. Not sure what I'm missing here (or if I need both SetBinding statements)...? Here's all my code from the UI...

    ListView ImageList;
    var pictureTemplate=new DataTemplate(()=>{
    var grid=new Grid();
    var picture=new Image();
    picture.SetBinding(Image.SourceProperty,new Binding("ImageResults",source:vm));
    grid.Children.Add(picture);
    return new ViewCell{ View=grid};
    });
    ImageList=new ListView{ItemTemplate=pictureTemplate};
    ImageList.SetBinding( ListView.ItemsSourceProperty,new Binding("ImageResults",source: vm) );

  • jezhjezh Member, Xamarin Team Xamurai
    edited April 2019

    I couldn't test your code since I don't have the whole code,but you can try to define the ColumnDefinitions property, for example(define 2 columns):

     var grid=new Grid();
      grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.5, GridUnitType.Star) });
      grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.5, GridUnitType.Star) });
    

    Besides, where is your source data? and I couldn't understand why the the rest of the following two line codes is the same.

    // here you should bind the value of the  Object Model (e.g. ImageObject)
     picture.SetBinding(Image.SourceProperty,new Binding("ImageResults",source:vm));
    

    and

     ImageList.SetBinding( ListView.ItemsSourceProperty,new Binding("ImageResults",source: vm) );
    

    You can also binding the data source like this

    ImageList=new ListView{ItemsSource = myImageResults, ItemTemplate=pictureTemplate};
    

    Note: Let's say the data source is as follows :

     pulic ObservableCollection<ImageObject>  myImageResults  = new ObservableCollection<ImageObject>();
    

    Note: you can refer to the following document and it contains a sample you can check:
    https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/templates/data-templates/creating

    please check class WithDataTemplatePageCS.cs
    https://github.com/xamarin/xamarin-forms-samples/blob/master/Templates/DataTemplates/DataTemplates/CS/WithDataTemplatePageCS.cs

  • SmartmanAppsSmartmanApps AUMember ✭✭✭
    edited April 2019

    @jezh said:
    I couldn't test your code since I don't have the whole code,but you can try to define the ColumnDefinitions property, for example(define 2 columns):

     var grid=new Grid();
      grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.5, GridUnitType.Star) });
      grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0.5, GridUnitType.Star) });
    

    That didn't change anything. :-(

    Besides, where is your source data?

    I'm doing a Bing image search and assigning the results to ImageResults in my vm, which has been cast to a List. I'll include the full list of relevant code at the end (I know the data is ok, because I was able to successfully bind a single image - just can't get it working for the full set of images).

    and I couldn't understand why the the rest of the following two line codes is the same.

    // here you should bind the value of the  Object Model (e.g. ImageObject)
     picture.SetBinding(Image.SourceProperty,new Binding("ImageResults",source:vm));
    

    and

    ImageList.SetBinding( ListView.ItemsSourceProperty,new Binding("ImageResults",source: vm) );

    Because I don't know how to bind a ListView and I'm trying different things to get it to work. Do you bind to the list itself, or to the objects within? (I also tried both of those individually, also didn't work) I'm not sure what you mean by bind the value of the object model?

    You can also binding the data source like this

    ImageList=new ListView{ItemsSource = myImageResults, ItemTemplate=pictureTemplate};

    I tried ImageList=new ListView{ItemTemplate=pictureTemplate,ItemsSource=vm.ImageResults}; but that also didn't work.

    Note: Let's say the data source is as follows :

    pulic ObservableCollection myImageResults = new ObservableCollection();

    When I try to cast to ObservableCollection I get "Unable to cast object of type 'System.Collections.Generic.List1[Microsoft.Azure.CognitiveServices.Search.ImageSearch.Models.ImageObject]' to type 'System.Collections.ObjectModel.ObservableCollection1[Microsoft.Azure.CognitiveServices.Search.ImageSearch.Models.ImageObject]'.", whereas the vm code seems to be happy when it's cast to a List (builds and runs with no exceptions or other issues).

    Here's all the code as it stands right now (except my API key of course :-) )...

    MAINPAGE
    StackLayout MainStack
    ListView ImageList;
    Viewmodel vm;
    Grid MainGrid=new Grid();
    vm=new Viewmodel();
    var pictureTemplate=new DataTemplate(()=>{
    var grid=new Grid();
    grid.ColumnDefinitions.Add(new ColumnDefinition{ Width=new GridLength(0.5,GridUnitType.Star)});
    grid.ColumnDefinitions.Add(new ColumnDefinition{ Width=new GridLength(0.5,GridUnitType.Star)});
    var picture=new Image();
    picture.SetBinding(Image.SourceProperty,new Binding("ImageResults",source:vm));
    grid.Children.Add(picture);
    return new ViewCell{ View=grid};
    });
    ImageList=new ListView{
    ItemTemplate=pictureTemplate
    // ,ItemsSource=vm.ImageResults
    };
    //ImageList.SetBinding( ListView.ItemsSourceProperty,new Binding("ImageResults",source: vm) );
    MainStack=new StackLayout{VerticalOptions=LayoutOptions.Center};
    MainGrid.Children.Add(MainStack);
    MainStack.Children.Add(ImageList);
    Content=MainGrid;

    VIEWMODEL
    private List<ImageObject> _imageResults;
    public List<ImageObject> ImageResults
    {
    get { return _imageResults;}
    set {
    if (_imageResults != value) {
    _imageResults=value;
    PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("ImageResults"));
    }
    }
    }

    string searchterm=800897143558;
    using(var client=new ImageSearchClient(new ApiKeyServiceClientCredentials(AzureKey))){
    client.Endpoint="https://australiaeast.api.cognitive.microsoft.com/";
    ImageResults=(List<ImageObject>) client.Images.SearchAsync(query: searchterm).Result.Value;
    }

  • SmartmanAppsSmartmanApps AUMember ✭✭✭

    I think I may be onto why this isn't working - an annoying red herring. Please see https://forums.xamarin.com/discussion/155770/images-from-a-variable-not-loading-displaying/p1?new=1

Sign In or Register to comment.