简体   繁体   中英

Issue binding Gridview itemsource to viewmodel property

I'm having some issues binding my collection property in my viewmodel to a GridView. I'm using MVVM light and i believe i have the ViewModelLocator setup correctly and have the DataContext setup in the page's xaml.

Model

public class Base
{
    public ObservableCollection<Downloads> results { get; set; }
}
public class Downloads
{
    public int id { get; set; }
    public string name { get; set; }
    public int trackNumber { get; set; }
    public string mixName { get; set; }
    public string title { get; set; }
    public string slug { get; set; }
    public string releaseDate { get; set; }
    public string publishDate { get; set; }
    public List<Artist> artists { get; set; }
    public string artistNames
    {
        get
        {
            return (artists == null)
                ? string.Empty
                : string.Join(", ", artists.Select(a => a.name));
        }
    }
    public string artistNamesSlug
    {
        get
        {
            return (artists == null)
                ? string.Empty
                : string.Join("_", artists.Select(a => a.name));
        }
    }

    public Release release { get; set; }
    public Label label { get; set; }
    public Image images { get; set; }
    public int downloadId { get; set; }
    public string audioFormat { get; set; }
    public string downloadUrl { get; set; }
}
public class Release
{
    public int id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
    public string slug { get; set; }
}
public class Label
{
    public int id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
    public string slug { get; set; }
    public bool status { get; set; }
}
public class Image
{
    public LargeImage large { get; set; }
}
public class LargeImage
{
    public int id { get; set; }
    public int width { get; set; }
    public int height { get; set; }
    public string url { get; set; }
    public string secureUrl { get; set; }
}

ViewModel

public class AvailableViewModel : ViewModelBase
{

    public AvailableViewModel()
    {

    }

    private Base availableDownloads;
    public Base AvailableDownloads
    {
        get
        {
            if(availableDownloads == null)
            {
                GetData();
            }
            return availableDownloads;
        }
        set
        {
            availableDownloads = value;
            RaisePropertyChanged(() => AvailableDownloads);
        }
    }

    private async void GetData()
    {
        OAuth oauth = new OAuth();

        string httpMethod = "GET";
        string parameters = "status=available";
        string response = await oauth.GetData(OAuth.availDownloadsUrl, httpMethod, parameters);

        Base availableDownloads = JsonConvert.DeserializeObject<Base>(response);
    }
}

XAML

DataContext="{Binding Available, Source={StaticResource Locator}}">

<Page.Resources>
    <DataTemplate x:Key="AvailableGridView">
        <Grid Margin="0,10,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="2*"/>
            </Grid.ColumnDefinitions>
            <Image Source="{Binding AvailableDownloads.images.large.url}" Grid.Column="0" />
            <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="20,0,0,0">
                <TextBlock Text="{Binding AvailableDownloads.title}" Style="{StaticResource BaseTextBlockStyle}" TextWrapping="Wrap"/>
                <TextBlock Text="{Binding AvailableDownloads.release.name}" Style="{StaticResource BaseTextBlockStyle}"/>
                <TextBlock Text="{Binding AvailableDownloads.artistNames}" Style="{StaticResource SubtitleTextBlockStyle}"/>
            </StackPanel>
        </Grid>
    </DataTemplate>
</Page.Resources>


<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <GridView ItemsSource="{Binding AvailableDownloads.results}" SelectionMode="Multiple" ItemTemplate="{StaticResource AvailableGridView}"/>
</Grid>

This might be part of the problem, but when i set the DataContext in the xaml the layout displays an Object Reference error. I don't know why that happens, but application will compile and run. I'm new to MVVM and i can't seem to figure out why my bindings aren't working here.

This might be part of the problem, but when i set the DataContext in the xaml the layout displays an Object Reference error.

Is this "Object Reference error" NullReferenceException error? Since your code it not comprehensive, I can reproduce this problem in several places, but I don't know which exactly causes your problem.

First I changed your XAML code for test here, and I used x:Bind in the DataTemplate of GridView :

  ...
  DataContext="{Binding Available, Source={StaticResource Locator}}"
  xmlns:model="using:[Namespace of your app].Model">
<Page.Resources>
    <DataTemplate x:Key="AvailableGridView" x:DataType="model:Downloads">
        <Grid Margin="0,10,0,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="2*" />
            </Grid.ColumnDefinitions>
            <!--<Image Source="{x:Bind downloadUrl}" Grid.Column="0" />-->
            <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="20,0,0,0">
                <TextBlock Text="{x:Bind title}" Style="{StaticResource BaseTextBlockStyle}" TextWrapping="Wrap" />
                <TextBlock Text="{x:Bind release.name}" Style="{StaticResource BaseTextBlockStyle}" />
                <TextBlock Text="{x:Bind artistNames}" Style="{StaticResource SubtitleTextBlockStyle}" />
            </StackPanel>
        </Grid>
    </DataTemplate>
</Page.Resources>

<Grid>
    <GridView ItemsSource="{Binding AvailableDownloads.results}" SelectionMode="Multiple" ItemTemplate="{StaticResource AvailableGridView}" />
</Grid>

And I changed your Base class like this:

public class Base
{
    public ObservableCollection<Downloads> results { get; set; }

    public Base()
    {
        results = new ObservableCollection<Downloads>();
    }
}

This could be a possible reason if you don't create a new instance of ObservableCollection<Downloads> when you add data.

And I changed your AvailableViewModel() like this, the data added into the result are fake, just for testing:

public AvailableViewModel()
{
    availableDownloads = new Base();
    availableDownloads.results.Add(new Downloads { title = "11111", artistNames = "222", release = new Release(0, "333", "", "") });
    availableDownloads.results.Add(new Downloads { title = "11111" });
    availableDownloads.results.Add(new Downloads { title = "11111" });
    availableDownloads.results.Add(new Downloads { title = "11111" });
    availableDownloads.results.Add(new Downloads { title = "11111" });
}

As you can see, I created a new instance of Base class here.

I noticed that in your xaml code you used release.name , for this, I think you need to modify your Release class like this:

public class Release
{
    public Release()
    {
    }

    public Release(int Id, string Name, string Type, string Slug)
    {
        this.id = Id;
        this.name = Name;
        this.type = Type;
        this.slug = Slug;
    }

    public int id { get; set; }
    public string name { get; set; }
    public string type { get; set; }
    public string slug { get; set; }
}

And you can create the instance of Release class like this:

release = new Release(0, "333", "", "");

I commented the Image control in your DataTemplate , to do this work, you need modify your LargeImage and Image like the Release class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM