I'm trying to display a list of alarms in a WPF ListVieuw. To accomplish this I databinded the Listbox to a property containing the list of alarms. Since I use the MVC programming paradigm the property is located in the controller, and the datacontext of the view is set to that controller.
I noticed that when I added an alarm to the list, the view didn't display the new alarm. After some research I found I need to use the ObservableCollection class to do this correctly.
However, displaying the list of alarms isn't the only thing that needs to be done with it, so I can't / don't want to change the variable type of the list to ObservableCollection.
I now tried to make a property of the type ObservableCollection, but this doesn't work either. This is pretty normal, since I don't add the alarm to the property, I add it to the variable, which is still of the type List.
Is there a way to tell the property when the List is updated, or an other/better way to display my alarms and keep them easy to use for other parts of the program?
Edit:
My workaround: I trigger the PropertyChanged
event by clearing my property FutureEvents in the eventhandler of the PropertyChanged
event from my alarms variable.
My code: class cMain { private static volatile cMain instance; private static object syncRoot = new Object();
ObservableCollection<Alarm> alarms;
#region properties
/// <summary>
/// Returns the list of alarms in the model. Can't be used to add alarms, use the AddAlarm method
/// </summary>
public ObservableCollection<Alarm> Alarms
{
get
{
return alarms;
}
}
/// <summary>
/// Returns the ObservableCollection of future alarms in the model to be displayed by the vieuw.
/// </summary>
public ObservableCollection<Alarm> FutureAlarms
{
get
{
//Only show alarms in the future and alarm that recure in the future
var fAlarms = new ObservableCollection<Alarm>(alarms.Where(a => a.DateTime > DateTime.Now || (a.EndRecurrency != null && a.EndRecurrency > DateTime.Now)));
return fAlarms;
}
}
/// <summary>
/// Returns a desctription of the date and time of the next alarm
/// </summary>
public String NextAlarmDescription
{
get
{
if (alarms != null)
{
return alarms.Last().DateTimeDescription;
}
else
{
return null;
}
}
}
#endregion //properties
#region public
/// <summary>
/// Returns the instance of the singleton
/// </summary>
public static cMain Instance
{
get
{
if (instance == null) //Check if an instance has been made before
{
lock (syncRoot) //Lock the ability to create instances, so this thread is the only thread that can excecute a constructor
{
if (instance == null) //Check if another thread initialized while we locked the object class
instance = new cMain();
}
}
return instance;
}
}
/// <summary>
/// Shows a new intance of the new alarm window
/// </summary>
public void NewAlarmWindow()
{
vNewAlarm newAlarm = new vNewAlarm();
newAlarm.Show();
}
public void AddAlarm(Alarm alarm)
{
alarms.Add(alarm);
}
public void RemoveAlarm(Alarm alarm)
{
alarms.Remove(alarm);
}
public void StoreAlarms()
{
mXML.StoreAlarms(new List<Alarm>(alarms));
}
#endregion //public
#region private
//Constructor is private because cMain is a singleton
private cMain()
{
alarms = new ObservableCollection<Alarm>(mXML.GetAlarms());
alarms.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(alarms_CollectionChanged);
}
private void alarms_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
FutureAlarms.Clear(); //Needed to trigger the CollectionChanged event of FutureAlarms
StoreAlarms();
}
#endregion //private
}