Question

Working on an windows store app, I try to update/refresh a listView when some data is updated. But despite all samples and documentations I read, it doesn't work...

Here my code behind : (I do not provide my xaml files, it's just a sample listView).

So the class which implements the INotifyPropertyChanged interface:

public class Download : INotifyPropertyChanged
    {
        public enum DownloadState
        {
            Running,
            Waiting,
            Pausing,
            Paused,
            Cancelling,
            Cancelled
        };

        private String Uri;
        private StorageFile storageFile;
        private String tempFileName;



        private String fileName;
        private String version ;

        private long totalSize ;
        private long downloadedBytes;

        private DownloadState state;
        private Protocol protocol;


        public Download(String Uri, StorageFile file, String fileName, String version, long totalSize, Protocol protocol)
        {
            this.Uri = Uri;
            this.storageFile = file;
            this.tempFileName = "";
            this.fileName = fileName;
            this.version = version;

            this.totalSize = totalSize;
            this.downloadedBytes = 0;

            this.state = DownloadState.Waiting;

            this.protocol = protocol;


        }


        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            System.Diagnostics.Debug.WriteLine("Update!"); //ok
            if (PropertyChanged != null)
            {
                //PropertyChanged is always null and shouldn't.
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
           public DownloadState State
        {
            get{return this.state;}
            set { 
                this.state = value;
                NotifyPropertyChanged();
            }
        }

        //+some others methods

    }
}

And the main page of the metro app :

// The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237

namespace ClientAirNavLight_WS
{
    /// <summary>
    /// A basic page that provides characteristics common to most applications.
    /// </summary>
    public sealed partial class MainPage : ClientAirNavLight_WS.Common.LayoutAwarePage
    {
        /// <summary>
        /// Represent a Web Service proxy.
        /// </summary>
        private AirNavLight_WSClientClient proxyWS;

        /// <summary>
        /// Initiialize the component of the application's main page.
        /// </summary>
        public MainPage()
        {
            this.InitializeComponent();          

        }



        /// <summary>
        /// Populates the page with content passed during navigation.  Any saved state is also
        /// provided when recreating a page from a prior session.
        /// </summary>
        /// <param name="navigationParameter">The parameter value passed to
        /// <see cref="Frame.Navigate(Type, Object)"/> when this page was initially requested.
        /// </param>
        /// <param name="pageState">A dictionary of state preserved by this page during an earlier
        /// session.  This will be null the first time a page is visited.</param>
        protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)
        {
        }

        /// <summary>
        /// Preserves state associated with this page in case the application is suspended or the
        /// page is discarded from the navigation cache.  Values must conform to the serialization
        /// requirements of <see cref="SuspensionManager.SessionState"/>.
        /// </summary>
        /// <param name="pageState">An empty dictionary to be populated with serializable state.</param>
        protected override void SaveState(Dictionary<String, Object> pageState)
        {
        }


        //Simulate data update.
        private async void Button_Click(object sender, RoutedEventArgs e)
        {

            object selected = this.ListResult.SelectedItem;
            if (selected != null)
            {
                //simulate an update in data.
                // ListView should be refresh in order to reflect changes made here.
                Download dl = (Download)selected;
                if (dl.State == Download.DownloadState.Paused)
                {
                    dl.State = Download.DownloadState.Running;
                }
                else
                {
                    dl.State = Download.DownloadState.Paused;
                }

            }
            else
            {
                //Just add an item to the list view.
                StorageFile file = await this.getStorageFile("test");
                Download dl = new Download("192.128.2.14", file, "test", "1.2", 100, Protocol.HTTP);
                this.ListResult.Items.Add(dl);


                this.ListResult.DataContext = dl;// Does not work.


            }
        }


        private async Task<StorageFile> getStorageFile(String suggestedFileName)
        {
            FileSavePicker savePicker = new FileSavePicker();
            savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
            // Dropdown of file types the user can save the file as
            savePicker.FileTypeChoices.Add("Application/pdf", new List<string>() { ".pdf" });
            savePicker.FileTypeChoices.Add("Archive", new List<string>() { ".zip", ".rar", ".7z" });
            savePicker.FileTypeChoices.Add("Plain-text", new List<string>() { ".txt" });
            // Default file name if the user does not type one in or select a file to replace
            savePicker.SuggestedFileName = suggestedFileName;
            return await savePicker.PickSaveFileAsync();
        }


    }
}

So How am I supposed to use listView.DataContext? Am I misunderstanding how use INotifyPropertyChanged?

EDIT :

How my listView is define :

 <ListView x:Name="ListResult" HorizontalAlignment="Left" Height="200" Margin="10,56,0,0" VerticalAlignment="Top" Width="653" SelectionMode="Single"/>
Was it helpful?

Solution

Why are you setting this.ListResult.DataContext = dl? When dealing with ListViews, the ItemsSource is the collection for the all the objects that get iterated, not the DataContext. Furthermore, ItemsSource should be a collection and not one item. So if you're binding to a property, that property should exist as an item's property in the ItemsSource collection.

However, it looks like you don't have a collection so you're adding the dl directly to the ListView with this.ListResult.Items.Add(dl). That approach should work, however take out the this.ListResult.DataContext = dl or set this.ListResult.ItemsSource to a collection and add dl to that collection

I'm not familiar with [CallerMemberName] but if you're having problems with propertyName being null, try the following

    public DownloadState State
    {
        get{return this.state;}
        set {
            if( this.state != value )
            {
                this.state = value;
                NotifyPropertyChanged("State");
            }
        }
    }

Furthermore, all properties that you want to bind to should be public and call NotifyPropertyChanged, like the following

    private long totalSize ;

    public long TotalSize
    {
        get{return this.totalSize;}
        set {
            if( this.totalSize != value )
            {
                this.totalSize = value;
                NotifyPropertyChanged("TotalSize");
            }
        }
    }

OTHER TIPS

In your Download class, the only Property that will update in the UI is State, since it has a getter and setter.

Without your XAML it's not possible to see what you are trying to display, but normally, you would bind properties of your DataContext object (dl in this case) to different controls in a datatemplate that the listview could then display.

But these properties need to be public and have getters and setters for INotifyPropertyChanged to update the UI that these properties are bound to.

For instance, if you wanted the filename to show up in the ListView, you would need, as a minimum, to declare the filename property like this:

public String fileName {get; set; }

Zangdak -- One way around that problem is each time the items change in your collection just set set the ItemSource of the ListView to null and then set it back to your collection. If you do this the UI will update and you will see your new items added to your collection.

Paige Ake

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top