Search code examples
c#mvvmwindows-phone-8.1jump-list

Cannot assign void to an implicitly-typed local variable in WP 8.1


I am developing a music player app in WP 8.1 & I am trying to implement Jump List feature into it. To implement jump list, I am following the sample given here.

I am making some necessary changes to the available code & that's how I am implementing the desired feature as my knowledge in C#, MVVM & WP 8.1 is minimal.

But I am facing an error in my ViewModel at line

var items = ContactModel.CreateSampleData();

and the error is:

Cannot assign void to an implicitly-typed local variable

What could be the possible reason???? Can anyone help me understand where I went wrong.

using System.Collections;
using Windows.UI.Xaml.Data;
using JumpListSample.Common.JumpList;
using System.Collections.Generic;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using System;
using Windows.Storage;
using Windows.Storage.Search;
using System.Collections.ObjectModel;

namespace JumpListSample.ViewModels
{
    public class ContactsViewModel
    {
        private IList data;
        public IList Data
        {
            get
            {
                if (data == null)
                {
                    var items = ContactModel.CreateSampleData();
                    data = items.ToAlphaGroups(x => x.Name);
                }
                return data;
            }
        }
        private CollectionViewSource collection;

        public CollectionViewSource Collection
        {
            get
            {
                if (collection == null)
                {
                    collection = new CollectionViewSource();
                    collection.Source = Data;
                    collection.IsSourceGrouped = true;
                }
                return collection;
            }
        }
    }

    public class ContactModel
    {
        // constructor
        public ContactModel()
        {
            Name = "name";
            Albumart = new BitmapImage(new Uri("ms-appx:///Assets/Logo.scale-240.png"));
        }

        public async  static void CreateSampleData()
        {
            ObservableCollection<ContactModel> data = new ObservableCollection<ContactModel>();

            try
            {
                IReadOnlyList<IStorageItem> MusicLibrary = await KnownFolders.MusicLibrary.GetFoldersAsync(CommonFolderQuery.GroupByAlbum);
                foreach (IStorageItem item in MusicLibrary)
                {
                    ContactModel obj = new ContactModel();
                    IStorageItem musicItem = item;
                    obj.Name = musicItem.Name;
                    obj.Albumart = new BitmapImage(new Uri("ms-appx:///Assets/Logo.scale-240.png"));
                    data.Add(obj);
                }
            }
            catch
            {
            }
            finally
            {
            } 
        }

        public string Name { get; set; }
        public ImageSource Albumart { get; set; }
    }
}

Demo code can be downloaded from here.


Solution

  • I concur with commenter Clint Good's suggestion. Your CreateSampleData() method appears to be responsible for initializing a collection of ContactModel instances. Presumably, you are calling this from the Data property because these are the items you want to use to initialize the data field.

    That said, you have a serious problem: C# properties do not support the async/await pattern. One idiom for addressing this is to asynchronously initialize the backing field, and then raise a property-changed event when the initialization has completed. Unfortunately, your ContactsViewModel class does not implement INotifyPropertyChanged or inherit DependencyObject (the two ways XAML-based programs handle property-change notification).

    Taking all that together and making the necessary changes to your code, you'd wind up with something like this:

    ContactsViewModel:

    public class ContactsViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
    
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    
        private IList data;
        public IList Data
        {
            get
            {
                if (data == null)
                {
                    // Ignore the returned Task...we're not going to do anything with it
                    var _ = InitData();
                }
    
                // Caller should handle null. If not, need to return "new Data[0]" here instead
                return data;
            }
        }
    
        private async Task InitData()
        {
            // Catch _specific_ exceptions here, if necessary
    
            var items = await ContactModel.CreateSampleData();
            data = items.ToAlphaGroups(x => x.Name);
            OnPropertyChanged("Data");
        }
    
        private CollectionViewSource collection;
    
        public CollectionViewSource Collection
        {
            get
            {
                if (collection == null)
                {
                    collection = new CollectionViewSource();
                    collection.Source = Data;
                    collection.IsSourceGrouped = true;
                }
                return collection;
            }
        }
    }
    

    ContactModel:

    public class ContactModel
    {
        // constructor
        public ContactModel()
        {
            Name = "name";
            Albumart = new BitmapImage(new Uri("ms-appx:///Assets/Logo.scale-240.png"));
        }
    
        public async static Task<ObservableCollection<ContactModel>> CreateSampleData()
        {
            ObservableCollection<ContactModel> data = new ObservableCollection<ContactModel>();
    
            IReadOnlyList<IStorageItem> MusicLibrary = await KnownFolders.MusicLibrary.GetFoldersAsync(CommonFolderQuery.GroupByAlbum);
            foreach (IStorageItem item in MusicLibrary)
            {
                ContactModel obj = new ContactModel();
                IStorageItem musicItem = item;
                obj.Name = musicItem.Name;
                obj.Albumart = new BitmapImage(new Uri("ms-appx:///Assets/Logo.scale-240.png"));
                data.Add(obj);
            }
    
            return data;
        }
    
        public string Name { get; set; }
        public ImageSource Albumart { get; set; }
    }
    

    Note that I have also removed your try/catch entirely. It is very bad to simply swallow exceptions. If you think you need to handle any exceptions, handle them in the caller (i.e. ContactsViewModel.InitData()) where you can do something useful and notify the user if necessary (but only handle specific exceptions, ones you know how to respond to).