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"/>
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");
}
}
}