更改集合,CollectionChanged 始终为 null
Changing collection, CollectionChanged always null
我正在兜圈子试图解决这个问题。
我正在将集合中的一组数据换成另一组数据。我的显示数据的 UI 在控件加载时显示第一组很好,但是当我更改集合内容时不会更改为新数据集。
我希望 NotifyCollectionChanged 方法中的 CollectionChanged 有订阅,但它没有。
StationName 在加载时显示在我的 UI 上,但在重新加载时不会改变。
StationListOfMovements 在加载时显示在我的 UI 上,但在重新加载时不会改变。
我可以在代码中更改现有集合中的个别项目。我哪里错了?
显示数据的控件
public partial class CisArrivalsPanel : UserControl
{
private ApiDataArrivalsDepartures _theArrivalsDepartures;
public CisArrivalsPanel()
{
InitializeComponent();
_theArrivalsDepartures = new ApiDataArrivalsDepartures();
_theArrivalsDepartures = MakeQuery.LiveTrainArrivals("London Kings Cross"); //load the first set of data into the collection
this.DataContext = _theArrivalsDepartures;
ListBoxArr.ItemsSource = _theArrivalsDepartures.StationMovementList;
}
//this invokes the data collection reload as a test
private void StationHeader_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Reload();
Debug.WriteLine(_theArrivalsDepartures.StationName);
foreach (var a in _theArrivalsDepartures.StationMovementList)
{
Debug.WriteLine(a.OriginName);
Debug.WriteLine(a.BestArrivalEstimateMins);
}
}
//here I am swapping out the collection contents
void Reload()
{
_theArrivalsDepartures = MakeQuery.LiveTrainArrivals("London Paddington"); //load the second set of data into the collection
}
}
合集
public class ApiDataArrivalsDepartures : INotifyPropertyChanged
{
private string _stationName;
[JsonProperty(PropertyName = "station_name")]
public string StationName {
get
{
return _stationName;
}
set
{
_stationName = value;
NotifyPropertyChanged("StationName");
}
}
private DateTime _requestTime;
[JsonProperty(PropertyName = "request_time")]
public DateTime RequestTime {
get
{
return _requestTime;
}
set
{
_requestTime = value;
NotifyPropertyChanged("RequestTime");
}
}
private string _stationCode;
[JsonProperty(PropertyName = "station_code")]
public string StationCode {
get
{
return _stationCode;
}
set
{
_stationCode = value;
NotifyPropertyChanged("StationCode");
}
}
private ObservableCollection<StationListOfMovements> _stationMovementList;
public ObservableCollection<StationListOfMovements> StationMovementList
{
get
{
return _stationMovementList;
}
set
{
_stationMovementList = value;
NotifyCollectionChanged("StationMovementList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void NotifyCollectionChanged(string property)
{
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset,property));
}
}
}
public class StationListOfMovements : INotifyPropertyChanged
{
private string _mode;
[JsonProperty(PropertyName = "mode")]
public string Mode
{
get
{
return _mode;
}
set
{
_mode = value;
NotifyPropertyChanged("Mode");
}
}
private string _service;
[JsonProperty(PropertyName = "service")]
public string Service {
get
{
return _service;
}
set
{
_service = value;
NotifyPropertyChanged("Service");
}
}
private string _trainUid;
[JsonProperty(PropertyName = "train_uid")]
public string TrainUid {
get
{
return _trainUid;
}
set
{
_trainUid = value;
NotifyPropertyChanged("TrainUid");
}
}
private string _originName;
[JsonProperty(PropertyName = "origin_name")]
public string OriginName {
get
{
return _originName;
}
set
{
_originName = value;
NotifyPropertyChanged("OriginName");
}
}
private string _destinationName;
[JsonProperty(PropertyName = "destination_name")]
public string DestinationName {
get
{
return _destinationName;
}
set
{
_destinationName = value;
NotifyPropertyChanged("DestinationName");
}
}
private string _platform;
[JsonProperty(PropertyName = "Platform")]
public string Platform {
get
{
return _platform;
}
set
{
_platform = value;
NotifyPropertyChanged("Platform");
}
}
//This is a long boring class, snipped until....
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
更新1:
/// <summary>
/// Gets train arrivals for a station
/// </summary>
/// <param name="station">The station.</param>
/// <returns>ApiDataArrivalsDepartures</returns>
public static ApiDataArrivalsDepartures LiveTrainArrivals(string station)
{
string crsCode;
OvergroundStations.StationDictionary.TryGetValue(station, out crsCode);
//construct url
var queryUrl = new Uri(string.Format("{0}{1}{2}{3}",ApiBaseUrl,"train/station/",crsCode,"/live_arrivals"));
//get json data from API
var jsonString = GetDataFromApi(queryUrl);
//convert to root arrival object
var arrivals = Deseralise<ApiDataArrivalsDepartures>(jsonString) as ApiDataArrivalsDepartures;
//convert arrivals board data
if (arrivals != null)
arrivals.StationMovementList = Deseralise<ObservableCollection<StationListOfMovements>>(jsonString, "arrivals", "all") as ObservableCollection<StationListOfMovements>;
return arrivals;
}
更新二:
static object Deseralise<T>(string jsonString, string token1, string token2)
{
var deserializeObject = new object();
try
{
var jsonPass1 = JObject.Parse(jsonString).SelectToken(token1).ToString();
var jsonPass2 = JObject.Parse(jsonPass1).SelectToken(token2).ToString();
deserializeObject = JsonConvert.DeserializeObject<T>(jsonPass2);
}
catch (Exception ex) { }
return deserializeObject;
}
ObservableCollection
会自动加注CollectionChanged
,不需要自己加注。它还针对自身而不是您的 VM 提高它。
事实上,UI 没有理由注册它(因此是空事件处理程序),因为您的 VM 甚至没有实现 INotifyCollectionChanged
(不是您应该的)。
相反,在 set
函数中为您的 collection 调用 NotifyPropertyChanged
,并删除 CollectionChanged
。还要确保 每次 设置变量时,都是通过 属性 而不是支持 字段。通过字段设置不会运行属性的set
功能,所以NotifyPropertyChanged
不会运行.
更新
虽然我最初的观察仍然是需要注意的好事,但我现在注意到了实际问题:
//here I am swapping out the collection contents
void Reload()
{
_theArrivalsDepartures = MakeQuery.LiveTrainArrivals("London Paddington"); //load the second set of data into the collection
}
ListBox
的ItemsSource
仍然设置为旧的collection!您所做的只是重新分配您的局部变量, ListBox
根本不受影响。像这样的问题是您通常 不 直接设置 UI 属性的原因。相反,您可以 绑定 ItemsSource
到虚拟机上的 属性,然后 仅更改 属性 而不是换出整个 object.
与此同时,考虑将 ItemsSource
重新分配给新的 collection。
我正在兜圈子试图解决这个问题。
我正在将集合中的一组数据换成另一组数据。我的显示数据的 UI 在控件加载时显示第一组很好,但是当我更改集合内容时不会更改为新数据集。
我希望 NotifyCollectionChanged 方法中的 CollectionChanged 有订阅,但它没有。
StationName 在加载时显示在我的 UI 上,但在重新加载时不会改变。 StationListOfMovements 在加载时显示在我的 UI 上,但在重新加载时不会改变。
我可以在代码中更改现有集合中的个别项目。我哪里错了?
显示数据的控件
public partial class CisArrivalsPanel : UserControl
{
private ApiDataArrivalsDepartures _theArrivalsDepartures;
public CisArrivalsPanel()
{
InitializeComponent();
_theArrivalsDepartures = new ApiDataArrivalsDepartures();
_theArrivalsDepartures = MakeQuery.LiveTrainArrivals("London Kings Cross"); //load the first set of data into the collection
this.DataContext = _theArrivalsDepartures;
ListBoxArr.ItemsSource = _theArrivalsDepartures.StationMovementList;
}
//this invokes the data collection reload as a test
private void StationHeader_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
Reload();
Debug.WriteLine(_theArrivalsDepartures.StationName);
foreach (var a in _theArrivalsDepartures.StationMovementList)
{
Debug.WriteLine(a.OriginName);
Debug.WriteLine(a.BestArrivalEstimateMins);
}
}
//here I am swapping out the collection contents
void Reload()
{
_theArrivalsDepartures = MakeQuery.LiveTrainArrivals("London Paddington"); //load the second set of data into the collection
}
}
合集
public class ApiDataArrivalsDepartures : INotifyPropertyChanged
{
private string _stationName;
[JsonProperty(PropertyName = "station_name")]
public string StationName {
get
{
return _stationName;
}
set
{
_stationName = value;
NotifyPropertyChanged("StationName");
}
}
private DateTime _requestTime;
[JsonProperty(PropertyName = "request_time")]
public DateTime RequestTime {
get
{
return _requestTime;
}
set
{
_requestTime = value;
NotifyPropertyChanged("RequestTime");
}
}
private string _stationCode;
[JsonProperty(PropertyName = "station_code")]
public string StationCode {
get
{
return _stationCode;
}
set
{
_stationCode = value;
NotifyPropertyChanged("StationCode");
}
}
private ObservableCollection<StationListOfMovements> _stationMovementList;
public ObservableCollection<StationListOfMovements> StationMovementList
{
get
{
return _stationMovementList;
}
set
{
_stationMovementList = value;
NotifyCollectionChanged("StationMovementList");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
private void NotifyCollectionChanged(string property)
{
if (CollectionChanged != null)
{
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset,property));
}
}
}
public class StationListOfMovements : INotifyPropertyChanged
{
private string _mode;
[JsonProperty(PropertyName = "mode")]
public string Mode
{
get
{
return _mode;
}
set
{
_mode = value;
NotifyPropertyChanged("Mode");
}
}
private string _service;
[JsonProperty(PropertyName = "service")]
public string Service {
get
{
return _service;
}
set
{
_service = value;
NotifyPropertyChanged("Service");
}
}
private string _trainUid;
[JsonProperty(PropertyName = "train_uid")]
public string TrainUid {
get
{
return _trainUid;
}
set
{
_trainUid = value;
NotifyPropertyChanged("TrainUid");
}
}
private string _originName;
[JsonProperty(PropertyName = "origin_name")]
public string OriginName {
get
{
return _originName;
}
set
{
_originName = value;
NotifyPropertyChanged("OriginName");
}
}
private string _destinationName;
[JsonProperty(PropertyName = "destination_name")]
public string DestinationName {
get
{
return _destinationName;
}
set
{
_destinationName = value;
NotifyPropertyChanged("DestinationName");
}
}
private string _platform;
[JsonProperty(PropertyName = "Platform")]
public string Platform {
get
{
return _platform;
}
set
{
_platform = value;
NotifyPropertyChanged("Platform");
}
}
//This is a long boring class, snipped until....
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(string property)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
}
更新1:
/// <summary>
/// Gets train arrivals for a station
/// </summary>
/// <param name="station">The station.</param>
/// <returns>ApiDataArrivalsDepartures</returns>
public static ApiDataArrivalsDepartures LiveTrainArrivals(string station)
{
string crsCode;
OvergroundStations.StationDictionary.TryGetValue(station, out crsCode);
//construct url
var queryUrl = new Uri(string.Format("{0}{1}{2}{3}",ApiBaseUrl,"train/station/",crsCode,"/live_arrivals"));
//get json data from API
var jsonString = GetDataFromApi(queryUrl);
//convert to root arrival object
var arrivals = Deseralise<ApiDataArrivalsDepartures>(jsonString) as ApiDataArrivalsDepartures;
//convert arrivals board data
if (arrivals != null)
arrivals.StationMovementList = Deseralise<ObservableCollection<StationListOfMovements>>(jsonString, "arrivals", "all") as ObservableCollection<StationListOfMovements>;
return arrivals;
}
更新二:
static object Deseralise<T>(string jsonString, string token1, string token2)
{
var deserializeObject = new object();
try
{
var jsonPass1 = JObject.Parse(jsonString).SelectToken(token1).ToString();
var jsonPass2 = JObject.Parse(jsonPass1).SelectToken(token2).ToString();
deserializeObject = JsonConvert.DeserializeObject<T>(jsonPass2);
}
catch (Exception ex) { }
return deserializeObject;
}
ObservableCollection
会自动加注CollectionChanged
,不需要自己加注。它还针对自身而不是您的 VM 提高它。
事实上,UI 没有理由注册它(因此是空事件处理程序),因为您的 VM 甚至没有实现 INotifyCollectionChanged
(不是您应该的)。
相反,在 set
函数中为您的 collection 调用 NotifyPropertyChanged
,并删除 CollectionChanged
。还要确保 每次 设置变量时,都是通过 属性 而不是支持 字段。通过字段设置不会运行属性的set
功能,所以NotifyPropertyChanged
不会运行.
更新 虽然我最初的观察仍然是需要注意的好事,但我现在注意到了实际问题:
//here I am swapping out the collection contents
void Reload()
{
_theArrivalsDepartures = MakeQuery.LiveTrainArrivals("London Paddington"); //load the second set of data into the collection
}
ListBox
的ItemsSource
仍然设置为旧的collection!您所做的只是重新分配您的局部变量, ListBox
根本不受影响。像这样的问题是您通常 不 直接设置 UI 属性的原因。相反,您可以 绑定 ItemsSource
到虚拟机上的 属性,然后 仅更改 属性 而不是换出整个 object.
与此同时,考虑将 ItemsSource
重新分配给新的 collection。