I have built a heart rate monitoring device, from which I intend to send data to my mobile application.
In my mobile application, I want to show a cardiogram as a dynamic curve which updates corresponding to the real-time data that the device sends to it.
Currently, I'm though concerned with preparing the data that I intend to append to my graph, and for that sake, I've written a code that reads the data from the peripheral and adds it to an observable collection:
MyDevice.Characteristic.ValueUpdated += (sender, e) =>
{
HrData = new ObservableCollection<string>();
HrData.Add(System.Text.Encoding.Default.GetString(e.Characteristic.Value));
};
Now, since the device is reading a lot of data in a very small timespan, I intend to only show 20 data points in the graph, meaning that the list should be updated according to the FIFO principle.
I know, that I could just make a loop and move every entity in my collection and thus achieve the principle. I do however feel that it would be a "pathcy" way of doing this.
Do there exist any convenient way to do this? i.e. an observable stack class.
I think what you're fundamentally looking for is a queue. A queue is a First In, First Out mechanism (as opposed to a Stack, which is First In, Last Out mechanism.)
ObservableCollection does not support this scenario. What you can do:
create your own implementation of INotifyCollectionChanged
or: subclass ObservableCollection, suspend notifications while you update the contents and then raise a Reset event
or: re-create the collection each time
or: create two separate collections, and switch between them: you expose A while updating B, then you expose B while updating A
class ObservableQueue<T> : Queue<T>, INotifyCollectionChanged
{
public ObservableQueue()
{
}
public ObservableQueue(int capacity) : base(capacity)
{
}
public ObservableQueue(IEnumerable<T> collection) : base(collection)
{
}
public event NotifyCollectionChangedEventHandler CollectionChanged;
public new void Clear()
{
base.Clear();
if(this.CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
public new void Enqueue(T item)
{
base.Enqueue(item);
if (this.CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add));
}
public new T Dequeue()
{
T item = base.Dequeue();
if (this.CollectionChanged != null)
CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove));
return item;
}
}
Related
I have made the following Dictionary, and I would like to be able to subscribe to the event fired from any of its' elements, in order to know which dictionary elements' properties were changed.
Here is my class:
public class BlockInput : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string PropertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
private int _value;
public int Value
{
get
{
return _value;
}
set
{
_value = Value;
NotifyPropertyChanged("Value");
}
}
}
I create a concurrent dictionary like the following:
public ConcurrentDictionary<string, BlockInput> Inputs;
How would this be achieved, in order for me to find every time that one of the BlockInput values were changed/event for each element fired?
Thanks for your time.
I don't believe you have another way than manually subscribing to all events yourself:
foreach (BlockInput item in Inputs.Values) {
item.PropertyChanged += BlockInput_PropertyChanged;
}
private void BlockInput_PropertyChanged(object sender, PropertyChangedEventArgs e) {
var blockInput = sender as BlockInput; // Get the item that was changed
// Do stuff
}
You would have to subscribe to all added items and unsubscribe from removed ones as well if you plan to add or remove items from the Dictionary.
In practical use of this Interface (wich is primarily MVVM) usually this is enough. You have the GUI classes do all the plumbing work of subscribing to events. You only need to provide 3 Change Notifications:
The one of each property of BlockInput. You did that in your example code.
The one if something is added or removed from the Collection. That is what ObservableCollection<BlockInput> will take care off. It is also the only thing the OC will take care off.
The one on the property exposing the ObservableCollection<BlockInput>. The OC is notoriously bad at bulk modifications, so often you need to prepare a new instance in code, with Exposing being the last step.
If you do not have a MVVM use case, please leave a comment. I can think of 2 ways on top of manually subscribing to each Event.
Fairly new to C# and WPF, so apologies if this is obvious.
I have converted a console app into a WPF application, and what I wanted to do was pass all the Console.WriteLine lines to an observable collection, to then write the newly added lines to a text box, to show the progress in the UI.
The issue I have is that there are multiple classes that I want to write to this ObservableCollection from, and this is the point I am stuck at.
Here is how I have approached this so far...
Model - I have the observable collection defined:
public class Progress
{
private ObservableCollection<string> _GGProgress = new ObservableCollection<string>();
public ObservableCollection<string> GGProgress
{
get { return _GGProgress; }
set { _GGProgress = value; }
}
}
MainWindow.xaml.cs - Create instance of the progress class and attach a CollectionChanged event to it:
//Initiage the Progress class
Progress prog = new Progress();
public MainWindow()
{
InitializeComponent();
prog.GGProgress.CollectionChanged += GGProgress_CollectionChanged;
}
private void GGProgress_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null && e.NewItems.Count > 0)
{
GGImportProgress.Text += e.NewItems[0];
}
}
I can then call this within the MainWindow.xaml.cs:
prog.GGProgress.Add("Text added");
And it will update the textbox as expected. From the MainWindow.xaml.cs however, I will initiate further classes, and within those classes, I could initiate further classes, and it is from all these classes I want to be able to update the observable collection and have it update that text box in the UI.
I tried initiating the Progress class, and then accessing it through the class I initiated it from, but I soon hit circular references.
I can look at rewriting the whole thing, but I wondered if I was missing something and there is an elegant solution for me to implement to be able to update that observable collection from different nested classes?
I am not using MVVM at present, as I presumed that this would be an small 'easy' app, but will happily switch if it makes life easier.
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
}
WPF reacts on the PropertyChanged event of the INotifyPropertyChanged interface, so you should implement this interface and raise the event when you change properties in your model.
If you do this, you don't need to use ObservableCollection<T> at all. But be aware that if your property is a List and the only thing you have done is add or remove items, WPF will still think it's the same list and do nothing. Therefore, before you raise the PropertyChanged event, you need to set you property to a new instance of a list, which is easily done like this:
MyList.add(newItem);
MyList = new List<something>(MyList);
#raise the event
Instead of recreating the ObservableCollection with the future alarms on every get, try to update the collection directly when the list changes:
public ObservableCollection<Alarm> FutureAlarms { get; private set;} // initialize in constructor
private void UpdateFutureAlarms() {
fAlarms.Clear();
fAlarms.AddRange(
alarms.Where(
a => a.DateTime > DateTime.Now
|| (a.EndRecurrency != null && a.EndRecurrency > DateTime.Now)
)
)
}
//... somewhere else in the code...
public void Foo () {
// change the list
alarms.Add(someAlarm);
UpdateFutureAlarms();
}
You could also register UpdateFutureAlarms as an event handler, if you had an event fired when the List changes.
You would be better off deriving your own class from ObservableCollection<T> and using that instead of trying to encapsulate both existing classes in a combination as you did. As to why:
first, it will be much less painful, since ObservableCollection<T> already implements all interfaces that List<T> supports, so you only need to implement the methods you actually need directly from List<T> and WPF data binding will just work;
second, the only realistic other alternative, the INotifyPropertyChanged approach is cumbersome to implement (you'll effectively rewrite ObservableCollection<T>) or it will result in bad performance with larger collections if you replace them with a new one after every change just to get the binding to update.
Add a property to Alarm
public bool Future
{ get return (DateTime > DateTime.Now
|| (EndRecurrency != null && EndRecurrency > DateTime.Now));
}
When up update Alarms call NotifyPropertyChanged on Future for all (or an appropriate subset).
Then use a DataTrigger or CollectionViewSource Filter to hide it
<DataTrigger Binding="{Binding Path=Future, Mode=OneWay}" Value="False">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
Filtering or hiding is kind of at the presentation level so it should leave you Alarm class and Alarms collection whole for for business and data layers.
Since ObservableCollection implements iList is should be compatible.
With you current model FurtureAlarms might as well be a List. Can shorten the syntax
(alarms.Where(a => a.DateTime > DateTime.Now || (a.EndRecurrency != null && a.EndRecurrency > DateTime.Now))).toList();
In WPF, binding to collections correctly needs that the collection bound to implements INotifyCollectionChanged which has the CollectionChanged Event that should be fired whenever an item is added or removed from the collection.
So you're advised to use the ObservableCollection<T> class which already implements that interface for you. And concerning the List<T> variables you use I think it's better that you switch them to the interface type IList<T> instead which is implemented also by ObservableCollection and as an additional benefit the parts of your application that don't need the ObservableCollection notification won't need to add additional references or know about the Observable collection.
Hey, I'm currently creating a program where I have several lists of information. When the entries in list 1 is processed, they'll be removed from list 1 and added to list 2. When the entries in list 2 is processed, they'll be removed and added to list 3 and so forth. When a list is processed, all the items present when the processing started will be removed from the list. Entries will be added to all the lists continuously as long as the program is running, and in no predictable manner. New entries will have to be processed fairly fast.
I figured that the best way to achieve this is to have each list fire an event whenever something is added and execute an Action. To make my life easier I created a custom list class that takes an Action as a constructor parameter, and invoke that Action whenever the event is fired (see code). However, the way I implemented it, where the event is fired when something is added to the list, is horridy inefficient with many new entries in a short timespan.
So basically I'm wondering if it's possible to create an events that fires whenever a list is not empty. In addition, is there any good way to assure that an event won't fire again as long as it has already been fired and is still "active" (in lack of a better explaination).
If anything is unclear, say so, and I'll try to clarify. Thanks!
public class EventDrivenList<T> : List<T>
{
private Action action_on_list_change;
private delegate void ListChangedDelegate(object sender, EventArgs e);
private event ListChangedDelegate ListChangedEvent;
private List<T> unprocessed_items;
public List<T> List
{
get
{
lock (unprocessed_items)
{
return unprocessed_items;
}
}
}
public EventDrivenList(Action action, int size)
{
action_on_list_change = action;
unprocessed_items = new List<T>(size);
ListChangedEvent += new ListChangedDelegate(OnChangeMethod);
}
public EventDrivenList(Action action)
{
action_on_list_change = action;
unprocessed_items = new List<T>();
ListChangedEvent += new ListChangedDelegate(OnChangeMethod);
}
~EventDrivenList()
{
ListChangedEvent -= new ListChangedDelegate(OnChangeMethod);
}
private void OnChange(EventArgs e)
{
if (ListChangedEvent != null)
ListChangedEvent(this, e);
}
private void OnChangeMethod(object sender, EventArgs e)
{
action_on_list_change.Invoke();
}
new public void Add(T item)
{
lock (unprocessed_items)
{
unprocessed_items.Add(item);
}
OnChange(EventArgs.Empty);
}
new public void Remove(T item)
{
lock (unprocessed_items)
{
unprocessed_items.Remove(item);
}
}
new public int Count()
{
lock (unprocessed_items)
{
return unprocessed_items.Count;
}
}
}
Regarding your concern about duplicate/overlapping firings, an option: create a handler which "unwires" all handlers while it's handling (and then re-wires them when it's finished handling).
Have you had a look at the ObservableCollection? It has default een CollectionChanged event which fires when there is something changed in the list. http://msdn.microsoft.com/en-us/library/ms653375.aspx
If I understood this correctly, your problem could be solved by using a ManualResetEvent. The event would fire and stay active when an item is added, and items continue to be present in the list (i.e. non-empty). When the list is empty you could simply reset the event...
An ObservableCollection is another option... however this would fire a CollectionChanged event every time an item is added or removed, which would be the same as what you're currently doing manually...
Was considering the System.Collections.ObjectModel ObservableCollection<T> class. This one is strange because
it has an Add Method which takes one item only. No AddRange or equivalent.
the Notification event arguments has a NewItems property, which is a IList (of objects.. not T)
My need here is to add a batch of objects to a collection and the listener also gets the batch as part of the notification. Am I missing something with ObservableCollection ? Is there another class that meets my spec?
Update: Don't want to roll my own as far as feasible. I'd have to build in add/remove/change etc.. a whole lot of stuff.
Related Q:
https://stackoverflow.com/questions/670577/observablecollection-doesnt-support-addrange-method-so-i-get-notified-for-each
It seems that the INotifyCollectionChanged interface allows for updating when multiple items were added, so I'm not sure why ObservableCollection<T> doesn't have an AddRange. You could make an extension method for AddRange, but that would cause an event for every item that is added. If that isn't acceptable you should be able to inherit from ObservableCollection<T> as follows:
public class MyObservableCollection<T> : ObservableCollection<T>
{
// matching constructors ...
bool isInAddRange = false;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
// intercept this when it gets called inside the AddRange method.
if (!isInAddRange)
base.OnCollectionChanged(e);
}
public void AddRange(IEnumerable<T> items)
{
isInAddRange = true;
foreach (T item in items)
Add(item);
isInAddRange = false;
var e = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
items.ToList());
base.OnCollectionChanged(e);
}
}
Well the idea is same as that of fryguybob - kinda weird that ObservableCollection is kinda half-done. The event args for this thing do not even use Generics.. making me use an IList (that's so.. yesterday :)
Tested Snippet follows...
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
namespace MyNamespace
{
public class ObservableCollectionWithBatchUpdates<T> : ObservableCollection<T>
{
public void AddRange(ICollection<T> obNewItems)
{
IList<T> obAddedItems = new List<T>();
foreach (T obItem in obNewItems)
{
Items.Add(obItem);
obAddedItems.Add(obItem);
}
NotifyCollectionChangedEventArgs obEvtArgs = new NotifyCollectionChangedEventArgs(
NotifyCollectionChangedAction.Add,
obAddedItems as System.Collections.IList);
base.OnCollectionChanged(obEvtArgs);
}
}
}
Not only is System.Collections.ObjectModel.Collection<T> a good bet, but in the help docs there's an example of how to override its various protected methods in order to get notification. (Scroll down to Example 2.)
If you use any of the above implementations that send an add range command and bind the observablecolletion to a listview you will get this nasty error.
NotSupportedException
at System.Windows.Data.ListCollectionView.ValidateCollectionChangedEventArgs(NotifyCollectionChangedEventArgs e)
at System.Windows.Data.ListCollectionView.ProcessCollectionChanged(NotifyCollectionChangedEventArgs args)
at System.Collections.Specialized.NotifyCollectionChangedEventHandler.Invoke(Object sender, NotifyCollectionChangedEventArgs e)
at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
The implementation I have gone with uses the Reset event that is more evenly implemented around the WPF framework:
public void AddRange(IEnumerable<T> collection)
{
foreach (var i in collection) Items.Add(i);
OnPropertyChanged("Count");
OnPropertyChanged("Item[]");
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
I have seen this kind of question many times, and I wonder why even Microsoft is promoting ObservableCollection everywhere where else there is a better collection already available thats..
BindingList<T>
Which allows you to turn off notifications and do bulk operations and then turn on the notifications.
If you're wanting to inherit from a collection of some sort, you're probably better off inheriting from System.Collections.ObjectModel.Collection because it provides virtual methods for override. You'll have to shadow methods off of List if you go that route.
I'm not aware of any built-in collections that provide this functionality, though I'd welcome being corrected :)
Another solution that is similar to the CollectionView pattern:
public class DeferableObservableCollection<T> : ObservableCollection<T>
{
private int deferLevel;
private class DeferHelper<T> : IDisposable
{
private DeferableObservableCollection<T> owningCollection;
public DeferHelper(DeferableObservableCollection<T> owningCollection)
{
this.owningCollection = owningCollection;
}
public void Dispose()
{
owningCollection.EndDefer();
}
}
private void EndDefer()
{
if (--deferLevel <= 0)
{
deferLevel = 0;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}
public IDisposable DeferNotifications()
{
deferLevel++;
return new DeferHelper<T>(this);
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (deferLevel == 0) // Not in a defer just send events as normally
{
base.OnCollectionChanged(e);
} // Else notify on EndDefer
}
}
Inherit from List<T> and override the Add() and AddRange() methods to raise an event?
Take a look at Observable collection with AddRange, RemoveRange and Replace range methods in both C# and VB.
In VB: INotifyCollectionChanging implementation.
For fast adding you could use:
((List<Person>)this.Items).AddRange(NewItems);