How can i transmit the sender as an eventarg - c#

Instance X of a class register to the change event of instances Y of the same class.
I want to update X if Y is changed, but i dont want to use the static keyword all over the class. Is there a way to transmit the recipient of the event in the eventargs?
Here is some example code with an NUnit tests to illustrate where my problem lies exactly. I compiled and ran it. Two tests just verify the programming. The failing test illustrates my problem.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
namespace Eventtest
{
public class DependencyChain
{
public static int demonstrationcount = 0;
private String hiddenstring = "";
public String visiblestring
{
get { return hiddenstring; }
set
{
hiddenstring = value;
NotifyOnStringChanged();
}
}
private void NotifyOnStringChanged()
{
if (changed != null)
{
changed(this, EventArgs.Empty);
}
}
public EventHandler changed;
private EventHandler Observer = new EventHandler((o, e) => {
DependencyChain sender = (o as DependencyChain);
demonstrationcount++;
//THE FOLLOWING DOES NOT WORK SINCE "this" IS NOT STATIC
//DependencyChain recipient = this;
//recipient.visiblestring = sender.visiblestring;
});
public DependencyChain(string initialstring)
{
this.visiblestring = initialstring;
}
public DependencyChain(DependencyChain other)
{
this.visiblestring = other.visiblestring;
other.changed += Observer;
}
public override string ToString()
{
return visiblestring;
}
}
[TestFixture]
class Eventtest
{
[SetUp]
public void ResetStaticCounter()
{
DependencyChain.demonstrationcount = 0;
}
[Test]//PASS
public void ShouldInitialiseAndCopyValues()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Assert.AreEqual(X.ToString(), Y.ToString());
}
[Test]//PASS
public void ShouldCallObserverOnChange()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Assert.AreEqual(0, DependencyChain.demonstrationcount);
Y.visiblestring = "changed";
Assert.AreEqual(1, DependencyChain.demonstrationcount);
}
[Test]//FAIL
public void ShouldChangeStringOnChange()
{
DependencyChain Y = new DependencyChain("initial");
DependencyChain X = new DependencyChain(Y);
Y.visiblestring = "changed";
Assert.AreEqual(X.ToString(), Y.ToString());
}
}
}

I think you only have to move the initialization of Observer to a constructor of DependencyChain, so you can capture this.

Related

Threading in unity with C# for optimisation

So here is my code: the idea is that in the input system class we find some data from the user, then listen to this data from the threading class and process it in a new thread, then we return the processed data to the main thread.
It works, but it is slow ... why is this?
I'm new to coding, so hopefully that explains the errors ...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using System.Threading;
public class InputSystem : MonoBehaviour
{
public EventHandler<dataStore> onRequest;
public class dataStore : EventArgs
{
public int[] dataPass;
}
public int[] newData;
void Start()
{
int[] test = new int[] { 6, 6, 6 };
newData = test;
}
void Update()
{
if (Input.GetButtonDown("Fire1"))
{
onRequest?.Invoke(this, new dataStore { dataPass = newData });
}
}
}
public class StartThread : MonoBehaviour
{
void Start()
{
InputSystem input = GetComponent<InputSystem >();
input.onRequest += findPath;
}
requestData pData;
returnData rData;
public void findPath(object sender, InputSystem.dataStore data)
{
pData = data.dataToPass;
RequestPath(method);
}
public static void RequestPath(Action doThing)
{
ThreadStart thread = delegate
{
doThing();
};
thread.Invoke();
}
public Queue<Action> toRun = new Queue<Action>();
public void method()
{
PathAlg test = new PathAlg();
Action toQueue = () =>
{
requestData data = pData;
rData.data = test.method(data);
};
lock (toRun)
{
toRun.Enqueue(toQueue);
}
}
void Update()
{
while (toRun.Count > 0)
{
lock (toRun)
{
Action runThis = toRun.Dequeue();
runThis();
foreach(int n in rData)
{
print(n);
}
}
}
}
}
public struct requestData
{
public int[] data;
}
public struct returnData
{
public int[] data;
}
public class pathAlg
{
public int[] method(requestData data)
{
int[] example = new int[data.Length];
for(int i = 0; i< example.Length; i++)
{
example[i] = i+1;
}
return example;
}
}
Solved this problem by using coroutines rather than threads.

How to test if no event was invoked

I am new to UnitTests and therefore to Xunit. I have wrote some tests, but I am stuck with the testing of events.
Is it possible to test that no event was invoked with xunit?
I used this example for preparing my tests.
The first test works fine. For the second test, I expected something like 'Assert.RaisesNoEvent'; However, that method is not available.
Is there another way to test that no event was invoked?
Code Sample
Class where Event is Raised when Property2 is Set
public class Class
{
private int _property2;
public event EventHandler RelevantPropertyChanged;
public void OnRelevantPropertyChanged(EventArgs args){
RelevantPropertyChanged?.Invoke(this, args);
}
public int Property1 { get; set; }
public int Property2 {
get { return _property2; }
set {
OnRelevantPropertyChanged(new EventArgs());
_property2 = value;
}
}
}
TestClass defines unit tests for Class
public class TestClass
{
[Fact]
public void ChangeProperty2_RaisesEvent()
{
var cl = new Class();
var args = new EventArgs();
var evt = Assert.RaisesAny<EventArgs>(
h => cl.RelevantPropertyChanged += h,
h => cl.RelevantPropertyChanged -= h,
() => cl.Property2 = 5);
Assert.NotNull(evt);
Assert.Equal(cl, evt.Sender);
Assert.Equal(args, evt.Arguments);
}
[Fact]
public void ChangeProperty1_RaisesNoEvent()
{
var cl = new Class();
Action code = () => cl.Property1 = 5;
Assert.RaisesNoEvent(code); //this is what I want to do
}
}
You can check that the event was not raised by checking that the EventHandler was not invoked:
[Fact]
public void ChangeProperty1_RaisesNoEvent()
{
var instance = new Class();
bool isInvoked = false;
instance.RelevantPropertyChanged += (s, e) => isInvoked = true;
Assert.False(isInvoked);
instance.Property1 = 5;
Assert.False(isInvoked);
}
This technique works with any unit testing framework.

Unit test and code coverage on EventHandlers

I'm trying to do a unit test on the eventHandler in the class and I'm not exactly sure how to get valid data to put in the tests. Thanks in advance!
public class BriefAssociation
{
public static event EventHandler<AssociationEventArgs> BriefAssociationChanged;
public static event EventHandler<AssociationEventArgs> BriefAssociationChangedEvent;
public static void OnBriefAssociationChanged(AssociationEventArgs e)
{
BriefAssociationChanged(null, e);
}
public static bool HasListener(EventHandler<AssociationEventArgs> TestCheck)
{
if ((BriefAssociationChangedEvent != null))
if ((BriefAssociationChangedEvent.GetInvocationList().Length > 0))
{
return true;
}
return false;
}
}
public class AssociationEventArgs
{
public int CustomerID;
}
CHANGES The following edit is for an error which is discussed in the comments
public class BriefAssociation
{
public static event EventHandler<AssociationEventArg> BriefAssociationChanged;
public static event EventHandler<AssociationEventArg> BriefAssociationChangedEvent;
public static void OnBriefAssociationChanged(AssociationEventArg e)
{
BriefAssociationChanged(null, e);
}
public static bool HasListener(EventHandler<AssociationEventArg> TestCheck)
{
if ((BriefAssociationChangedEvent != null))
if ((BriefAssociationChangedEvent.GetInvocationList().Length > 0))
{
return true;
}
return false;
}
}
public class AssociationEventArg
{
public int CustomerID;
}
For the second method "HasListener" I have a test that gives it a null value to test the if statement but I need to give it something that has a value of length grater than 0 to test the rest of the function. I hope it makes sense.
This is a simple test that might help
[Test]
public void should_raise_event()
{
BriefAssociation.BriefAssociationChangedEvent += BriefAssociationChanged;
bool result = BriefAssociation.HasListener(null);
Assert.True(result);
}
public void BriefAssociationChanged(Object obj, AssociationEventArgs associationEventArgs)
{ }
Here's all the test you need for the 1st method:
[Test]
public void OnBriefAssociationCHanged_ShouldRaiseBriefAssociationChangedEvent()
{
// Data
object resultSender = null;
AssociationEventArgs resultArgs = null;
AssociationEventArgs testArgs = new AssociationEventArgs();
// Setup
BriefAssociation.BriefAssociationChanged += (sender, args) =>
{
resultSender = sender;
resultArgs = args;
};
// Test
BriefAssociation.OnBriefAssociationChanged(testArgs);
// Analysis
Assert.IsNull(resultSender);
Assert.AreSame(resultArgs, testArgs);
}

Translating C# code with delegate to Java, to use with Android

I'm in the process of diving into Android development. Most of the projects I was involved with, were in C#. Delegates were elements of C# I did use very often, I've used also stuff like passing data using class that extends EventArgs or properties with set and get. With my programming knowledge I think I will be able to get started with Android development pretty smoothly. The thing is I have completly no idea how to approach an implementing mechanism similar to C# delagte in Java.
Below I present some exemplary class that works in C# just fine and contains some elements of C# language that I would like to use in my future Android projects. Can someone provide me with a translation of this code? I would prefer that 'cos working with my own example and its conversion would allow me to catch it all faster. Also, any valuable resources on the topic (not only delegates but genereal topic of converting C# into Java) would be apreciated.
CountdownTimer.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SampleDelegateApp
{
public class CountdownTimer
{
Timer tmrTicks = new Timer();
int secondsLeft = 0;
int numberOfSecondsToCountdown = 0;
public bool IsWorking
{
get { return tmrTicks.Enabled; }
}
public CountdownTimer(int seconds)
{
if (secondsLeft < 0) secondsLeft = 0;
numberOfSecondsToCountdown = seconds;
secondsLeft = seconds;
tmrTicks.Interval = 1000;
tmrTicks.Tick += new EventHandler(tmrTicks_Tick);
tmrTicks.Enabled = false;
}
void tmrTicks_Tick(object sender, EventArgs e)
{
secondsLeft--;
if (secondsLeft >= 1)
WhenCountdownTimerTick(new CountdownTimerEventArgs(secondsLeft, numberOfSecondsToCountdown, false));
else
{
Stop();
WhenCountdownTimerTick(new CountdownTimerEventArgs(secondsLeft, numberOfSecondsToCountdown, true));
}
}
public void Reset()
{
Stop();
secondsLeft = numberOfSecondsToCountdown;
if (secondsLeft < 0) secondsLeft = 0;
WhenCountdownTimerTick(new CountdownTimerEventArgs(secondsLeft, numberOfSecondsToCountdown, false));
}
public void Stop()
{
tmrTicks.Enabled = false;
}
public void Start()
{
if (secondsLeft <= 0)
{
secondsLeft = 0;
WhenCountdownTimerTick(new CountdownTimerEventArgs(secondsLeft, numberOfSecondsToCountdown, true));
}
else
{
tmrTicks.Enabled = true;
}
}
public delegate void CountdownTimerTickEventHandler(object sender, CountdownTimerEventArgs ea);
public event CountdownTimerTickEventHandler CountdownTimerTick;
protected virtual void WhenCountdownTimerTick(CountdownTimerEventArgs ea)
{
if (CountdownTimerTick != null)
{
CountdownTimerTick(this, ea);
}
}
}
public class CountdownTimerEventArgs : EventArgs
{
public string timeString = "";
public float procentOfTimeLeft = 0.0f;
public bool countdownFinished = false;
public CountdownTimerEventArgs(int secondsLeft, int SecondsToCountdown, bool isfinished)
{
countdownFinished = isfinished;
timeString = string.Format("{0:00}:{1:00}", secondsLeft / 60, secondsLeft % 60);
}
}
}
frmTest.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace SampleDelegateApp
{
public partial class frmTest : Form
{
CountdownTimer ctmrTest;
public frmTest()
{
InitializeComponent();
ctmrTest = new CountdownTimer(-44);
ctmrTest.CountdownTimerTick += new CountdownTimer.CountdownTimerTickEventHandler(ctmrTest_CountdownTimerTick);
}
void ctmrTest_CountdownTimerTick(object sender, CountdownTimerEventArgs ea)
{
lblTimer.Text = ea.timeString;
if (ea.countdownFinished) countdownEnd();
}
private void btnStart_Click(object sender, EventArgs e)
{
ctmrTest.Reset();
ctmrTest.Start();
}
void countdownEnd()
{
MessageBox.Show("Finish");
}
}
}
This is all about the observer pattern really. In .NET this has been made easy with delegates and stuff, in Java you must implement it by hand, using interfaces for the handlers and plain objects for the args. Look it up, you will find plenty of info.
I apparently used some words in my question that made it all unclear and/or persons who tried to help me completly missunderstood my needs as for this question. Putting word "delegate" here and there made it even more complexed. After one more question asked in other way i got my answer that made me able to answer my question:
How to achieve c# event behavior in java (Android)
I'm not saying that code below is up to the best coding standards, and example shown here got any use in real life project, but this is exactly what i was looking for. Below working example:
tester.java
public class tester{
public static void main(String[] args) {
test test1 = new test();
test1.start();
}
}
test.java
public class test implements CountdownTextTickListener {
public test() { }
public void start() {
CountdownText ctx = new CountdownText(100);
ctx.setListener(this);
ctx.Start();
}
#Override
public void CountdownTextTickEventFired(Object sender,
CountdownTextTickEventArgs eventArgs) {
System.out.println(eventArgs.TimeString);
if(eventArgs.isStopped) System.out.println("- END -");
}
}
CountdownTextTickListener.java
public interface CountdownTextTickListener {
void CountdownTextTickEventFired(Object sender, CountdownTextTickEventArgs eventArgs);
}
CountdownTextTickEventArgs.java
public class CountdownTextTickEventArgs {
public String TimeString = "";
public boolean isStopped = false;
public CountdownTextTickEventArgs(int seconds, boolean isStoppedState) {
TimeString = String.format("%02d:%02d",seconds/60, seconds % 60);
isStopped = isStoppedState;
}
}
CountdownText.java
import java.util.Timer;
import java.util.TimerTask;
public class CountdownText {
Timer tmrTicks = new Timer();
int secondsLeft = 0;
int numberOfSecondsToCountdown = 0;
boolean isWorking = false;
private CountdownTextTickListener listener = null;
public boolean getIsWorking(){
return isWorking;
}
public CountdownText(int seconds) {
if (secondsLeft < 0) secondsLeft = 0;
numberOfSecondsToCountdown = seconds;
secondsLeft = seconds;
}
void startTimer() {
isWorking = true;
fireEvent(secondsLeft, false);
tmrTicks = new Timer();
tmrTicks.scheduleAtFixedRate( new TimerTask(){
#Override
public void run(){
tickTimer();
}
}, 1000, 1000);
}
private void stopTimer() {
isWorking = false;
tmrTicks.cancel();
}
private void tickTimer() {
secondsLeft--;
if (secondsLeft >= 1)
{
fireEvent(secondsLeft, false);
}
else
{
Stop();
fireEvent(secondsLeft, true);
}
}
public void Reset() {
Stop();
secondsLeft = numberOfSecondsToCountdown;
fireEvent(secondsLeft, false);
}
public void Stop() {
stopTimer();
}
public void Start() {
if (secondsLeft <= 0)
{
secondsLeft = 0;
fireEvent(secondsLeft, true);
}
else
{
startTimer();
}
}
protected void fireEvent(int seconds, boolean isStoppedState) {
if (listener != null) {
Object sender = this;
CountdownTextTickEventArgs eventArgs = new CountdownTextTickEventArgs(seconds, isStoppedState);
listener.CountdownTextTickEventFired(sender, eventArgs);
}
}
public void setListener(CountdownTextTickListener listener) {
this.listener = listener;
}
}
From what I understand, there are actually ways to get your C# code to work in Android. I suggest looking at Mono for Android if your situation allows you to do your work in C#. Not only do you get to leave your code in C#, but you can also port it over to MonoTouch for iOS and .NET 4.5 for Windows Phone more easily. If not, I can't help you, but I'm sure someone more knowledgeable will.

BindingList not updating bound ListBox

I have a ListBox that is bound to a BindingList. The BindingList is built up when a third party application raises an event. I can see the BindingList being bound correctly... but nothing enters the ListBox. I have used the exact same logic with some of my own custom types and it usually works very well.
Form class
private Facade.ControlFacade _controlFacade;
public UavControlForm()
{
InitializeComponent();
_controlFacade = new UavController.Facade.ControlFacade();
UpdateEntityListBox();
}
private void UpdateEntityListBox()
{
lsbEntities.DataSource = _controlFacade.GetEntityTally();
lsbEntities.DisplayMember = "InstanceName";
}
Facade class
private Scenario _scenario;
public ControlFacade()
{
_scenario = new Scenario();
}
public BindingList<AgStkObject> GetEntityTally()
{
BindingList<AgStkObject> entityTally = _scenario.EntityTally;
return entityTally;
}
Scenario class
private static BindingList<IAgStkObject> _entityTally = new BindingList<AgStkObject>();
public Scenario()
{
if (UtilStk.CheckThatStkIsAvailable())
{
UtilStk.StkRoot.OnStkObjectAdded += new IAgStkObjectRootEvents_OnStkObjectAddedEventHandler(TallyScenarioObjects);
UtilStk.StkRoot.OnStkObjectDeleted += new IAgStkObjectRootEvents_OnStkObjectDeletedEventHandler(TallyScenarioObjects);
}
}
private void TallyScenarioObjects(object sender)
{
List<AgStkObject> tallyOfStkObjects = UtilStk.GetRunningTallyOfAllStkObjects();
List<string> stkObjectNames = UtilStk.GetInstanceNamesOfStkObjects(tallyOfStkObjects);
foreach (string stkObjectName in stkObjectNames)
{
if (!SearchFlightUavTallyByName(stkObjectName))
{
if (!SearchLoiterUavTallyByName(stkObjectName))
{
if (!SearchEntityTallyByName(stkObjectName))
{
int i = stkObjectNames.IndexOf(stkObjectName);
_entityTally.Add(tallyOfStkObjects[i]);
}
}
}
}
}
I can see the event fire from the third-party application - this adds an entity to _entityList as desired, but noothing is added to lsbEntities - why?
(jump right to the last example if you want to see it fixed etc)
Threads and "observer" patterns (such as the data-binding on winforms) are rarely good friends. You could try replacing your BindingList<T> usage with the ThreadedBindingList<T> code I used on a previous answer - but this combination of threads and UI is not an intentional use-case of winforms data-binding.
The listbox itself should support binding via list notification events (IBindingList / IBindingListView), as long as they arrive form the right thread. ThreadedBindingList<T> attempts to fix this by thread-switching on your behalf. Note that for this to work you must create the ThreadedBindingList<T> from the UI thread, after it has a sync-context, i.e. after it has started displaying forms.
To illustrate the point that listbox does respect list-change notifications (when dealing with a single thread):
using System;
using System.ComponentModel;
using System.Windows.Forms;
class Foo
{
public int Value { get; set; }
public Foo(int value) { Value = value; }
public override string ToString() { return Value.ToString(); }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using(var form = new Form())
using (var lst = new ListBox())
using (var timer = new Timer())
{
var data = new BindingList<Foo>();
form.Controls.Add(lst);
lst.DataSource = data;
timer.Interval = 1000;
int i = 0;
timer.Tick += delegate
{
data.Add(new Foo(i++));
};
lst.Dock = DockStyle.Fill;
form.Shown += delegate
{
timer.Start();
};
Application.Run(form);
}
}
}
and now with added threading / ThreadedBindingList<T> (it doesn't work with the regular BindingList<T>):
using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
class Foo
{
public int Value { get; set; }
public Foo(int value) { Value = value; }
public override string ToString() { return Value.ToString(); }
}
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
using(var form = new Form())
using (var lst = new ListBox())
{
form.Controls.Add(lst);
lst.Dock = DockStyle.Fill;
form.Shown += delegate
{
BindingList<Foo> data = new ThreadedBindingList<Foo>();
lst.DataSource = data;
ThreadPool.QueueUserWorkItem(delegate
{
int i = 0;
while (true)
{
data.Add(new Foo(i++));
Thread.Sleep(1000);
}
});
};
Application.Run(form);
}
}
}
public class ThreadedBindingList<T> : BindingList<T>
{
private readonly SynchronizationContext ctx;
public ThreadedBindingList()
{
ctx = SynchronizationContext.Current;
}
protected override void OnAddingNew(AddingNewEventArgs e)
{
SynchronizationContext ctx = SynchronizationContext.Current;
if (ctx == null)
{
BaseAddingNew(e);
}
else
{
ctx.Send(delegate
{
BaseAddingNew(e);
}, null);
}
}
void BaseAddingNew(AddingNewEventArgs e)
{
base.OnAddingNew(e);
}
protected override void OnListChanged(ListChangedEventArgs e)
{
if (ctx == null)
{
BaseListChanged(e);
}
else
{
ctx.Send(delegate
{
BaseListChanged(e);
}, null);
}
}
void BaseListChanged(ListChangedEventArgs e)
{
base.OnListChanged(e);
}
}

Categories

Resources