I'm running the following code, and I'm expecting a different outcome.
According to my intent, I would not expect to encounter the firing of my callback function when setting a value.
I would only expect to see my callback fire when checking the value of my field and that field's criteria were met to fire the event.
Could somebody breathe some understanding into this for me?
using System.Collections;
public static class CollectionHandler {
private static List<string> _origFileList = new List<string>();
public static List<string> origFileList {
get {
if (_origFileList.Count < 1) {
//Fire a Callback Function Call Here
myTestCallback();
}
return _origFileList;
}
set {
_origFileList = value;
}
}
private static void myTestCallback() {
Console.WriteLine("origFileList - Is now empty");
}
}
CollectionHandler.origFileList.Add("Value 1");
CollectionHandler.origFileList.Add("Value 2");
CollectionHandler.origFileList.RemoveAt(1);
CollectionHandler.origFileList.RemoveAt(0);
//Output> origFileList - Is now empty
CollectionHandler.origFileList.Add("Test Value #1 - Should not fire the callback !!! But it does");
//Output> origFileList - Is now empty
CollectionHandler.origFileList.Add("Test Value #2 - Should not fire the callback --- And it doesn't");
To understand what's going on you have to modify your code a little bit:
void Main()
{
CollectionHandler.origFileList.Add("Value 1");
CollectionHandler.origFileList.Add("Value 2");
CollectionHandler.origFileList.RemoveAt(1);
CollectionHandler.origFileList.RemoveAt(0);
//Output> origFileList - Is now empty
CollectionHandler.origFileList.Add("Test Value #1 - Should not fire the callback !!! But it does");
//Output> origFileList - Is now empty
CollectionHandler.origFileList.Add("Test Value #2 - Should not fire the callback --- And it doesn't");
}
public static class CollectionHandler
{
private static List<string> _origFileList = new List<string>();
public static List<string> origFileList
{
get
{
myTestCallback(_origFileList);
if (_origFileList.Count < 1)
{
//Fire a Callback Function Call Here
myTestCallback(_origFileList.Count());
}
return _origFileList;
}
set
{
_origFileList = value;
}
}
private static void myTestCallback(object s)
{
Console.WriteLine(s.ToString());
Console.WriteLine("========");
}
private static void myTestCallback(List<string> s)
{
foreach (var str in s)
Console.WriteLine(str);
Console.WriteLine("========");
}
}
Now you will be able to see the content of the list every time a getter is called.
Basically when this line is executed:
CollectionHandler.origFileList.Add("Test Value #1 - Should not fire the callback !!! But it does");
the getter is called prior to the Add() method when the origFileList is actually empty, that why _origFileList.Count < 1 condition is satisfied.
As stated, the problem is in the moment the property is accessed. This is before the action on it has taken place.
To add an alternate solution, which was a bit too long as a comment: you can wrap whichever list is set inside something like a (System.ComponentModel)BindingList. The BindingList exposes events to detect changes made to it. (not if the original list itself is a basic list and it is changed by outside sources though).
Example:
public static class CollectionHandler {
private static BindingList<string> _origFileList;
public static IList<string> origFileList
{
get=> _origFileList;
set
{
if(value == null) throw new ArgumentNullException();
if(_origFileList != null)
_origFileList.ListChanged -= OnListChanged;
_origFileList = new BindingList<string>(value);
_origFileList.ListChanged += OnListChanged;
}
}
static void OnListChanged(object sender, ListChangedEventArgs e)
{
if(_origFileList.Count== 0)
myTestCallback();
}
static CollectionHandler()
{
origFileList = new List<string>();
}
private static void myTestCallback() {
Console.WriteLine("origFileList - Is now empty");
}
}
After removing the last item, the count is less than one, so the next time you access CollectionHandler.origFileList, the get function is executed and the condition around the callback is checked.
This is effectively the same code, but will illustrate what #ckuri is referring to:
CollectionHandler.origFileList.Add("Value 1");
CollectionHandler.origFileList.Add("Value 2");
CollectionHandler.origFileList.RemoveAt(1);
CollectionHandler.origFileList.RemoveAt(0);
var theList = CollectionHandler.origFileList; // myCallBack will be called as the "get" method is called here
theList.Add("Test Value #1 - Should not fire the callback !!! But it does"); // call back will not be called here
var theListAgain = CollectionHandler.origFileList; // the get method is called again, but the count == 1 so the callback is not called
theListAgain.Add("Test Value #2 - Should not fire the callback --- And it doesn't");
I wanted to post my implementation regarding this.
I know that there is a lot of improvement to be made on this code (eg. exposing delegates to subscribe to, etc...), but for the purposes of gaining simple control over the adding and removing of items from the list, I simply wrapped it up and defined my own Add / RemoveAt methods (per Bradley Uffner's Comment on my OP).
class Program {
static void Main(string[] args) {
CollectionHandler.origFileList.Add("Value 1");
CollectionHandler.origFileList.Add("Value 2");
CollectionHandler.origFileList.RemoveAt(1);
CollectionHandler.origFileList.RemoveAt(0);
CollectionHandler.origFileList.Add("Test Value #1");
CollectionHandler.origFileList.Add("Test Value #2");
Console.Read();
}
}
public static class CollectionHandler {
private static rrList _origFileList = new rrList();
public static rrList origFileList {
get {
return _origFileList;
}
set {
_origFileList = value;
}
}
}
public class rrList {
private List<string> _origFileList = new List<string>();
private void myTestCallback() {
Console.WriteLine("List Is now empty");
}
private void ListChanged() {
Console.WriteLine("List Size: " + _origFileList.Count);
}
public void RemoveAt(int i) {
_origFileList.RemoveAt(i);
checkList();
}
public void Add(string stringToAdd) {
_origFileList.Add(stringToAdd);
checkList();
}
private void checkList() {
if (_origFileList.Count == 0) {
myTestCallback();
} else {
ListChanged();
}
}
}
Related
I have a form that has a button to get a method executed in another class.
Code on the form:
public delegate void CustomPreviewCreate();
public static event CustomPreviewCreate CustomPreviewCreate_Do;
private void CreatePreview()
{
if (CustomPreviewCreate_Do !=null)
{
CustomPreviewCreate_Do();
}
}
This event then gets handled in another class. What I would like to achieve is that I can feed back to the form some form of return value if the method correctly executed.
What I tried so far does not get me the result.
Here is the code:
public void Initialize()
{
SubAsstViewPartControl.CustomPreviewCreate_Do += SubAsstViewPartControl_CustomPreviewCreate_Do;
// this gives me a the compiler error that the return type is wrong
}
private bool SubAsstViewPartControl_CustomPreviewCreate_Do()
{
// do stuff
return false;
}
Is there any direct way to return value from an event handler or I need to use a separate static field to store the event result in?
Update:
Per #Jon's comment, which seemed the simplest to me, I added an answer below demonstrating the simplest approach.
The common approach is to encapsulate your value in the type of EventArgs your event expects. For example, the Framework's CancelEventArgs contains a settable bool Cancel property, allowing each CancelEventHandler to assign a value. The sender can then read the property after the event has been invoked. You could also use a container-like EventArgs class if you want to collect separate values from individual event handlers. For example:
using System;
using System.Collections.Generic;
namespace ConsoleApplication1
{
public class SingleValueEventArgs : EventArgs
{
public int Value { get; set; }
}
public class MultiValueEventArgs : EventArgs
{
private List<int> _values = new List<int>(); // Private to prevent handlers from messing with each others' values
public IEnumerable<int> Values
{
get { return _values; }
}
public void AddValue(int value) { _values.Add(value); }
}
public class Exposer
{
public event EventHandler<SingleValueEventArgs> WantSingleValue;
public event EventHandler<MultiValueEventArgs> WantMultipleValues;
public void Run()
{
if (WantSingleValue != null)
{
var args = new SingleValueEventArgs();
WantSingleValue(this, args);
Console.WriteLine("Last handler produced " + args.Value.ToString());
}
if (WantMultipleValues != null)
{
var args = new MultiValueEventArgs();
WantMultipleValues(this, args);
foreach (var value in args.Values)
{
Console.WriteLine("A handler produced " + value.ToString());
}
}
}
}
public class Handler
{
private int _value;
public Handler(Exposer exposer, int value)
{
_value = value;
exposer.WantSingleValue += exposer_WantSingleValue;
exposer.WantMultipleValues += exposer_WantMultipleValues;
}
void exposer_WantSingleValue(object sender, SingleValueEventArgs e)
{
Console.WriteLine("Handler assigning " + _value.ToString());
e.Value = _value;
}
void exposer_WantMultipleValues(object sender, MultiValueEventArgs e)
{
Console.WriteLine("Handler adding " + _value.ToString());
e.AddValue(_value);
}
}
class Program
{
static void Main(string[] args)
{
var exposer = new Exposer();
for (var i = 0; i < 5; i++)
{
new Handler(exposer, i);
}
exposer.Run();
}
}
}
Per Jon Skeet's comment, which seemed the simplest to me, the simplest approach seems to be as follows:
public delegate bool CustomPreviewCreate(); // here we declare a return type
public static event CustomPreviewCreate CustomPreviewCreate_Do;
private void CreatePreview()
{
if (CustomPreviewCreate_Do !=null)
{
bool returnval = CustomPreviewCreate_Do();
}
}
And then:
// the method is declared to return the same type
bool SubAsstViewPartControl_CustomPreviewCreate_Do()
{
// do stuff
return true; // return the value of the type declared
}
I need to add my list to my listbox. I searched through all the questions on this site but none work I always get things like listbox1.spelers in my listbox.
Here is the code I have now.
private void btnAdd_Click(object sender, EventArgs e)
{
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
List<Speler> spelers = new List<Speler>();
spelers.Add(speler1);
listBox1.DataSource = spelers;
}
Also tried with the ToArray but it still didn't work.
SOLVED
You're re-binding the control to a list of exactly one element every time. So the control will only ever have one element.
Keep the list in a higher scope. For example, if this class is persistent in memory (that is, not a web application) then make it a class-level member:
private List<Speler> spelers = new List<Speler>();
private void btnAdd_Click(object sender, EventArgs e)
{
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
spelers.Add(speler1);
listBox1.DataSource = spelers;
// maybe call listBox1.DataBind() here? it's been a while since I've had to use forms
}
That way you're always adding another element to the same list, instead of creating a new list every time.
If you are using Windows Forms application, you can use a BindingDource:
Speler speler1 = new Speler(tbNaam.Text, tbAge.Text);
List<Speler> spelers = new List<Speler>();
spelers.Add(speler1);
var bs = new BindingSource();
bs.DataSource = spelers;
listBox1.DataSource = bs;
Good example is here : Console App
using System;
namespace Enumeration
{
using System;
using System.Collections;
// implements IEnumerable
class ListBoxTest : IEnumerable
{
private string[] strings;
private int ctr = 0;
// private nested implementation of ListBoxEnumerator
private class ListBoxEnumerator : IEnumerator
{
// member fields of the nested ListBoxEnumerator class
private ListBoxTest currentListBox;
private int index;
// public within the private implementation
// thus, private within ListBoxTest
public ListBoxEnumerator(ListBoxTest currentListBox)
{
// a particular ListBoxTest instance is
// passed in, hold a reference to it
// in the member variable currentListBox.
this.currentListBox = currentListBox;
index = -1;
}
// Increment the index and make sure the
// value is valid
public bool MoveNext()
{
index++;
if (index >= currentListBox.strings.Length)
return false;
else
return true;
}
public void Reset()
{
index = -1;
}
// Current property defined as the
// last string added to the listbox
public object Current
{
get
{
return(currentListBox[index]);
}
}
} // end nested class
// Enumerable classes can return an enumerator
public IEnumerator GetEnumerator()
{
return (IEnumerator) new ListBoxEnumerator(this);
}
// initialize the listbox with strings
public ListBoxTest(params string[] initialStrings)
{
// allocate space for the strings
strings = new String[8];
// copy the strings passed in to the constructor
foreach (string s in initialStrings)
{
strings[ctr++] = s;
}
}
// add a single string to the end of the listbox
public void Add(string theString)
{
strings[ctr] = theString;
ctr++;
}
// allow array-like access
public string this[int index]
{
get
{
if (index < 0 || index >= strings.Length)
{
// handle bad index
}
return strings[index];
}
set
{
strings[index] = value;
}
}
// publish how many strings you hold
public int GetNumEntries()
{
return ctr;
}
}
public class EnumerationTester
{
public void Run()
{
// create a new listbox and initialize
ListBoxTest currentListBox =
new ListBoxTest("Hello", "World");
// add a few strings
currentListBox.Add("Who");
currentListBox.Add("Is");
currentListBox.Add("John");
currentListBox.Add("Galt");
// test the access
string subst = "Universe";
currentListBox[1] = subst;
// access all the strings
foreach (string s in currentListBox)
{
Console.WriteLine("Value: {0}", s);
}
}
[STAThread]
static void Main()
{
EnumerationTester t = new EnumerationTester();
t.Run();
}
}
}
Given the following code:
public delegate void Signal();
public static class SignalExtensions
{
public static void SafeInvoke(this Signal signal)
{
Signal copy = signal;
if (copy != null)
{
copy();
}
}
}
public class RootEventSource
{
public event Signal RootEvent;
public void Raise()
{
this.RootEvent.SafeInvoke();
}
}
public class EventForwarder
{
private readonly RootEventSource rootEventSource;
public EventForwarder(RootEventSource rootEventSource)
{
this.rootEventSource = rootEventSource;
// this is the critical part
this.rootEventSource.RootEvent
+= () => this.AnotherEvent.SafeInvoke();
}
public event Signal AnotherEvent;
// just an example of another method which is using the root event source
public override string ToString()
{
return this.rootEventSource.ToString();
}
}
class Program
{
static void Main(string[] args)
{
var rootEventSource = new RootEventSource();
var eventForwarder = new EventForwarder(rootEventSource);
eventForwarder.AnotherEvent += HandleAnotherEvent;
rootEventSource.Raise();
Console.WriteLine("done");
Console.ReadKey();
}
private static void HandleAnotherEvent()
{
Console.WriteLine("received AnotherEvent");
}
}
This results in the output:
received AnotherEvent
done
Now I make a slight change to the implementation of EventForwarder to use a method group for forwarding the event:
public EventForwarder(RootEventSource rootEventSource)
{
this.rootEventSource = rootEventSource;
this.rootEventSource.RootEvent += this.AnotherEvent.SafeInvoke;
}
The output becomes:
done
So AnotherEvent is not raised.
Until now i would have considered the two lines:
this.rootEventSource.RootEvent += this.AnotherEvent.SafeInvoke;
this.rootEventSource.RootEvent += () => this.AnotherEvent.SafeInvoke();
as being equivalent. It seems they're not.
So what is the difference? Plus why is the event not being raised?
PS: while usually R# suggests to replace () => this.AnotherEvent.SafeInvoke(); by this.AnotherEvent.SafeInvoke it doesn't do so here. So apparently it knows that it should not do it here.
When you assign a method group to event like this:
this.rootEventSource.RootEvent += this.AnotherEvent.SafeInvoke;
you in fact create a delegate from method SignalExtensions.SafeInvoke which as a parameter takes your this.AnotherEventdelegate object. Since it is initially null, you create a delegate with null parameter. This null value will of course never change, since delegates are immutable.
If you want to forward an event you should maybe do it like this:
public class EventForwarder
{
private readonly RootEventSource rootEventSource;
public EventForwarder(RootEventSource rootEventSource)
{
this.rootEventSource = rootEventSource;
}
public event Signal AnotherEvent
{
add { this.rootEventSource.RootEvent += value; }
remove { this.rootEventSource.RootEvent -= value; }
}
}
I have an issue with data seemingly being reset to its default values.
The class is as follows (objectIDs is a simple enumeration):
public class Output_args: EventArgs {
public objectIDs outputtype;
public int internalID;
public int verdict;
public int outputID;
public long entrytime;
public Output_args Copy() {
Output_args args = new Output_args();
args.entrytime = this.entrytime;
args.internalID = this.internalID;
args.outputID = this.outputID;
args.outputtype = this.outputtype;
args.verdict = this.verdict;
return args;
}
}
The following code creates the object. It runs in a specific thread, let's say Thread1.
class Class1 {
EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset);
public event EventHandler<Output_args> newOutput;
public void readInput(){
List<Output_args> newoutputlist = new List<Output_args>();
/*
* code to determine the outputs
*/
Output_args args = new Output_args();
args.outputtype = objectIDs.stepID;
args.internalID = step[s].ID;
args.verdict = verdict;
args.entrytime = System.DateTime.Now.Ticks;
newoutputlist.Add(args.Copy());
if (newOutput != null && newoutputlist.Count > 0) {
// several outputs are being sent sequentially but for simplicity i've removed the for-loop and decision tree
try {
newOutput(null, newoutputlist[0].Copy());
} catch (Exception) { }
}
}
}
1 of the subscribers to this event has the following code. The processor method runs on a thread of a camerafeed. The newOutput event handler is being run on Thread1.
class Class2: Form {
private Output_args lastoutput = new Output_args();
public void newOutput(object sender, Output_args args) {
lock (lastoutput) {
lastoutput = args.Copy();
}
}
public void processor(){
lock (lastoutput) {
if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
// do something
}
}
}
}
When the eventhandler 'newOutput' of Class2 is being called, the debugger shows that the copy works as expected and 'entrytime' is given the expected number of ticks.
However, when the processor method wants to read the 'entrytime', its value is 0. All other fields also have their default value assigned.
I've tried replacing the object 'lastoutput' with a simple field of the type long and removed the locks but the results are the same: it gets assigned properly in 'newOutput' but has its default value (0) in the processor method.
Any ideas on why this is happening?
you should not lock on the object lastoutput, but on another object, because you reassign the field.
The processor start and lock on the default field instance new Output_args() initialized with default values
class Class2: Form {
private object mylock = new object();
private Output_args lastoutput;
public void newOutput(object sender, Output_args args) {
lock (mylock) {
lastoutput = args.Copy();
}
}
public void processor(){
lock (mylock) {
if (lastoutput == null) {
//nothing to consume yet
}
else if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
// do something
}
}
}
}
but this discard lastouput if consumer is slower than producer. You can use a queue ( or another collection ) as buffer if needed.
class Class2 {
private Queue<Output_args> outputs = new Queue<Output_args>();
public void newOutput(object sender, Output_args args) {
lock (outputs) {
outputs.Enqueue(args.Copy());
}
}
public void processor(){
lock (outputs) {
if (outputs.Count > 0) {
var lastoutput = outputs.Dequeue();
if (lastoutput.entrytime + 10000000 > System.DateTime.Now.Ticks) {
// do something
}
}
}
}
}
demo: https://dotnetfiddle.net/daHVD1
I am trying to create a thread which will continuously check for changes to a value, then visually show that change in a PictureBox located in my GUI.
What I actually wrote is a bit more complicated, so I simplified it while keeping the basic idea, I would be happy to provide clarification if this isn't enough:
public class CheckPictures
{
PictureBox update;
List<String> check;
public CheckPictures(PictureBox anUpdate, List<String> aCheck)
{
update = anUpdate;
check = aCheck;
}
public void start()
{
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
}
}
static int Main(string[] args)
{
List<String> picturesList = new List<String>();
CheckPictures thread1 = new CheckPictures(PictureBox1, picturesList);
Thread oThread1 = new Thread(thread1.start));
}
What I want it to do is dynamically change the picture in PictureBox1 if I were to add the string "Me" to pictureList. The above code isn't working like I'd hoped. I had thought that by passing the actual PictureBox and List, any changes to the List elsewhere is the program would be caught by the thread. So my first question is: Is this possible? And if so, what change would I need to make to my code to achieve it?
You might want to use events. You register an eventhandler and when something changes in one thread it calls an event handler in the other to do the work. Busy waiting wastes cpu.
You definetely do not want to do an infinite loop, this will just consume cpu:
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
I think you should look into the CountdownLatch class.
public class CountdownLatch
{
private int m_remain;
private EventWaitHandle m_event;
public CountdownLatch(int count)
{
m_remain = count;
m_event = new ManualResetEvent(false);
}
public void Signal()
{
// The last thread to signal also sets the event.
if (Interlocked.Decrement(ref m_remain) == 0)
m_event.Set();
}
public void Wait()
{
m_event.WaitOne();
}
}
The basic idea here is that you need to stop execution on your thread for some time and resume whenever a certain condition has been met (perhaps on another thread).
In other words, you will have a counter, decrement its value on certain condition and whenever it goes to zero you fire your event, execute some code and then start over (stop execution and wait for the counter to go to zero).
In your case you could set the counter to 1 and decrement its value whenever you've set aCheck[0] = "Me"; This way you don't waste CPU.
Pseudo code:
Initialize counter:
CountdownLatch latch = new CountdownLatch(1);
Make thread wait:
public void start()
{
while(true)
{
latch.Wait(); //execution stops
{
//execution resumes once the latch counter is zero.
if (aCheck[0] == "Me") //double check you have what you need
{
update.Image = Image.fromFile("");
latch = new CountdownLatch(1); //reset if you need to do it again
}
}
}
}
Whenever your condition is met (i.e. aCheck[0] = "Me";) signal your latch:
latch.Signal();
this last line will make the thread resume execution. Good stuff.
Create some object, which will raise event, when new picture was added. E.g. class representing pictures collection:
public class PicturesCollection
{
public event EventHandler<PictureAddedEventArgs> PictureAdded;
private List<string> _pictures = new List<string>();
public void Add(string name)
{
_pictures.Add(name);
if (PictureAdded != null)
PictureAdded(this, new PictureAddedEventArgs(name));
}
public IEnumerable<string> Pictures
{
get { return _pictures; }
}
}
If you want to provide some additional data to event, create custom EventArgs:
public class PictureAddedEventArgs : EventArgs
{
public PictureAddedEventArgs(string name)
{
Name = name;
}
public string Name { get; private set; }
}
All you need now - create pictures collection and subscribe to that event:
static int Main(string[] args)
{
PicturesCollection pictures = new PicturesCollection();
pictures.PictureAdded += Pictures_PictureAdded;
}
static void Pictures_PictureAdded(object sender, PictureAddedEventArgs e)
{
if (e.Name == "Me")
PictureBox1.Image = Image.fromFile("");
}
If you add somewhere in your application new picture to collection, it will raise PictureAdded event, which you can handle and update PictureBox. CPU is not wasted in this case.