I have created a test app for my first Windows IoT project with raspberry pi and an ultrasonic sensor.
I have placed some sample code in it. Visual Studio tells me that I am missing a curly bracket in "public void run…", but that doesn't seem to be the problem.
Is it because of the public class within the BackgroundTaskInstance?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using Windows.ApplicationModel.Background;
using Windows.Devices.Gpio;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics;
// The Background Application template is documented at http://go.microsoft.com/fwlink/?LinkID=533884&clcid=0x409
namespace IoTtest
{
public sealed class StartupTask : IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
public class HCSR04
{
private GpioPin triggerPin { get; set; }
private GpioPin echoPin { get; set; }
private Stopwatch timeWatcher;
public HCSR04(int triggerPin, int echoPin)
{
GpioController controller = GpioController.GetDefault();
timeWatcher = new Stopwatch();
//initialize trigger pin.
this.triggerPin = controller.OpenPin(triggerPin);
this.triggerPin.SetDriveMode(GpioPinDriveMode.Output);
this.triggerPin.Write(GpioPinValue.Low);
//initialize echo pin.
this.echoPin = controller.OpenPin(echoPin);
this.echoPin.SetDriveMode(GpioPinDriveMode.Input);
}
public double GetDistance()
{
ManualResetEvent mre = new ManualResetEvent(false);
mre.WaitOne(500);
timeWatcher.Reset();
//Send pulse
this.triggerPin.Write(GpioPinValue.High);
mre.WaitOne(TimeSpan.FromMilliseconds(0.01));
this.triggerPin.Write(GpioPinValue.Low);
return this.PulseIn(echoPin, GpioPinValue.High);
}
private double PulseIn(GpioPin echoPin, GpioPinValue value)
{
var t = Task.Run(() =>
{
//Recieve pusle
while (this.echoPin.Read() != value)
{
}
timeWatcher.Start();
while (this.echoPin.Read() == value)
{
}
timeWatcher.Stop();
//Calculating distance
double distance = timeWatcher.Elapsed.TotalSeconds * 17000;
return distance;
});
bool didComplete = t.Wait(TimeSpan.FromMilliseconds(100));
if (didComplete)
{
return t.Result;
}
else
{
return 0.0;
}
}
}
}
}
I took the code and reformatted it for you. Please change the namespace to the value you would like
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace MyIotNamespace
{
public sealed class StartupTask :IBackgroundTask
{
public void Run(IBackgroundTaskInstance taskInstance)
{
}
}
public class HCSR04
{
private GpioPin triggerPin { get; set; }
private GpioPin echoPin { get; set; }
private Stopwatch timeWatcher;
public HCSR04(int triggerPin, int echoPin)
{
GpioController controller = GpioController.GetDefault();
timeWatcher = new Stopwatch();
//initialize trigger pin.
this.triggerPin = controller.OpenPin(triggerPin);
this.triggerPin.SetDriveMode(GpioPinDriveMode.Output);
this.triggerPin.Write(GpioPinValue.Low);
//initialize echo pin.
this.echoPin = controller.OpenPin(echoPin);
this.echoPin.SetDriveMode(GpioPinDriveMode.Input);
}
public double GetDistance()
{
ManualResetEvent mre = new ManualResetEvent(false);
mre.WaitOne(500);
timeWatcher.Reset();
//Send pulse
this.triggerPin.Write(GpioPinValue.High);
mre.WaitOne(TimeSpan.FromMilliseconds(0.01));
this.triggerPin.Write(GpioPinValue.Low);
return this.PulseIn(echoPin, GpioPinValue.High);
}
private double PulseIn(GpioPin echoPin, GpioPinValue value)
{
var t = Task.Run(() =>
{
//Recieve pusle
while(this.echoPin.Read() != value)
{
}
timeWatcher.Start();
while(this.echoPin.Read() == value)
{
}
timeWatcher.Stop();
//Calculating distance
double distance = timeWatcher.Elapsed.TotalSeconds * 17000;
return distance;
});
bool didComplete = t.Wait(TimeSpan.FromMilliseconds(100));
if(didComplete)
{
return t.Result;
}
else
{
return 0.0;
}
}
}
}
Nested class can't exist inside functions. Place HCSR04 inside StartupTask instead.
See https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/nested-types
Related
Hi i've a problem getting location each 1-5 minutes with a Foreground Service, when I unplug the device and turn off the screen, the thread stops but the service notification is visible all time,
how can i prevent this?
i was reading about to use AlarmManager (is a real solution), how can i do it ? or should only foreground service do it by self
this is my code:
using Android.App;
using Android.Content;
using Android.Locations;
using Android.OS;
using Android.Text.Format;
using Invima.VehiculosApp.ViewModels;
using Java.Util;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Essentials;
using Xamarin.Forms;
namespace Invima.VehiculosApp
{
[Service(Label = "LocationUpdatesService", Enabled = true, Exported = true)]
[IntentFilter(new string[] { "com.Antss.InvimaVehiculos.Service" })]
public class LocationService : Service
{
IBinder Binder;
public override IBinder OnBind(Intent intent)
{
return Binder;
}
public const int ServiceRunningNotifID = 9000;
Ruta ruta;
Thread hiloUbicacion;
private System.Timers.Timer timer;
public override void OnCreate()
{
Notification notif = DependencyService.Get<INotification>().ReturnNotif();
StartForeground(ServiceRunningNotifID, notif);
_ = TomarUbicaciones();
base.OnCreate();
}
public override StartCommandResult OnStartCommand(Intent intent, StartCommandFlags flags, int startId)
{
string rutaStr = intent.GetStringExtra("ruta");
this.ruta = JsonConvert.DeserializeObject<Ruta>(rutaStr);
var autoEvent = new AutoResetEvent(false);
// i tried this but ... the same problem
timer = new System.Timers.Timer(30000);
timer.Elapsed += async (object sender, System.Timers.ElapsedEventArgs e) =>
{
using (HttpClient cl = new HttpClient())
{
await cl.GetAsync("https://webhook.site/a718fef4-769b-4871-87a8-ec1ccd83fc50");
}
};
timer.Start();
return StartCommandResult.Sticky;
}
public int TomarUbicaciones()
{
hiloUbicacion = new Thread(TomarUbicacionAsync);
hiloUbicacion.Start();
return 1;
}
int contador = 0;
public async void TomarUbicacionAsync()
{
while (true)
{
try
{
var request = new GeolocationRequest(GeolocationAccuracy.Medium);
var location = await Geolocation.GetLocationAsync(request);
if (location != null && ruta != null)
{
Console.WriteLine($"Latitude: {location.Latitude}, Longitude: {location.Longitude}, Altitude: {location.Altitude}");
App.BD.RutaUbicacion.Add(new RutaUbicacion
{
Fecha = DateTime.Now,
IdRuta = ruta.IdRuta,
Latitud = (decimal)location.Latitude,
Longitud = (decimal)location.Longitude,
Altitud = (decimal)location.Altitude
});
App.BD.SaveChanges();
App.Sincronizar();
}
Device.BeginInvokeOnMainThread(() =>
{
DependencyService.Get<IMessage>().ShortAlert("Done!");
});
}
catch (Exception ex)
{
}
Thread.Sleep(60000); // each minute
}
}
public override void OnDestroy()
{
try
{
hiloUbicacion.Abort();
}
catch { }
base.OnDestroy();
}
public override bool StopService(Intent name)
{
try
{
hiloUbicacion.Abort();
}
catch { }
return base.StopService(name);
}
}
}
Background
I am writing a program, which collects different events (key press, mouse position, and others) and sends a single string to a serial port.
There is a small part of the program, where a key is pressed, to control movement (forward - W key; left - A key, Forward-left - WA key).
When an event happens, a method is invoked, which grabs a numeric string and processes in the FinalStringClass Class. On the main form , there is a method, which assigns collected value to a label.
However, I am encountering a problem with code due to lack of experience in programming :(
Main Form:
Serial port;
FinalStringClass fstr;
public Form1()
{
InitializeComponent();
//... Serial port settings
timer.Start();
fstr = new FinalStringClass(UpdateLabel2);
}
public void UpdateLabel2(string x, string y, string speed, string mvm) //
{
label2.Text = "x: " + x + "y: " + y + "speed: " + speed + "mvm: " + mvm;
}
private void timer_Tick(object sender, EventArgs e)
{
var up = KeyboardInfo.GetKeyState(Keys.W);
var down = KeyboardInfo.GetKeyState(Keys.S);
var left = KeyboardInfo.GetKeyState(Keys.A);
var right = KeyboardInfo.GetKeyState(Keys.D);
if (left.IsPressed)
{
if (up.IsPressed == true) // if W and A keys are pressed, ->
{
fstr.mvmMethod("7"); // this method is triggered
return;
}
if (down.IsPressed)
{
fstr.mvmMethod("9");
return;
}
if (right.IsPressed)
{
fstr.mvmMethod("1");
return;
}
fstr.mvmMethod("4"); //if W key is pressed, then this method is triggered
}
//... (other if condition statements)
label2.Text = fstr.FinalStringBuilder();
port.Write(fstr.FinalStringBuilder());
}
External Class:
class FinalStringClass
{
private Action<string, string, string, string> updateLabel2;
Action<String> _x, _y, _speed, _mvm;
string xF, yF, speedF, mvmF;
public FinalStringClass(Action<string, string, string, string> updateLabel2)
{
this.updateLabel2 = updateLabel2;
}
public FinalStringClass(Action<String> x, Action<String> y, Action<String> speed, Action<String> mvm)
{
_x = x;
_y = y;
_speed = speed;
_mvm = mvm;
}
public void xMethod(string x)
{
_x(x);
xF = x;
}
public void yMethod(string y)
{
_y(y);
yF = y;
}
public void speedMethod(string speed)
{
_speed(speed);
speedF = speed;
}
public void mvmMethod(string mvm)
{
_mvm(mvm);
mvmF = mvm;
}
public string FinalStringBuilder()
{
return xF + yF + speedF + mvmF;
}
}
When working with a single parameter, everything works fine. But dealing with multiple parameters causes a problem :(
Example of working with a single parameter (full working code):
Main Form
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace FFApp
{
public partial class Form1 : Form
{
SerialPort port;
MyClass outside;
public Form1()
{
InitializeComponent();
timer.Start();
outside = new MyClass(UpdateLabel);
}
public void UpdateLabel(string str)
{
label1.Text = str;
}
private void init()
{
port = new SerialPort();
port.PortName = "COM1";
port.BaudRate = 115200;
try
{
port.Open();
}
catch (Exception e1)
{
MessageBox.Show(e1.Message);
}
}
public struct KeyStateInfo
{
private Keys key;
private bool isPressed;
private bool isToggled;
public KeyStateInfo(Keys key, bool ispressed, bool istoggled)
{
this.key = key;
isPressed = ispressed;
isToggled = istoggled;
}
public static KeyStateInfo Default
{
get
{
return new KeyStateInfo(Keys.None, false, false);
}
}
public Keys Key
{
get { return key; }
}
public bool IsPressed
{
get { return isPressed; }
}
public bool IsToggled
{
get { return isToggled; }
}
}
private void timer_Tick(object sender, EventArgs e)
{
var up = KeyboardInfo.GetKeyState(Keys.W);
var down = KeyboardInfo.GetKeyState(Keys.S);
var left = KeyboardInfo.GetKeyState(Keys.A);
var right = KeyboardInfo.GetKeyState(Keys.D);
Keyboard kb = new Keyboard();
if (left.IsPressed)
{
if (up.IsPressed == true)
{
outside.MyMethod("7");
return;
}
if (down.IsPressed)
{
outside.MyMethod("9");
return;
}
if (right.IsPressed)
{
outside.MyMethod("1");
return;
}
outside.MyMethod("4");
}
if (right.IsPressed)
{
if (up.IsPressed)
{
outside.MyMethod("6");
return;
}
if (down.IsPressed)
{
outside.MyMethod("8");
return;
}
if (left.IsPressed)
{
outside.MyMethod("1");
return;
}
outside.MyMethod("5");
}
if (up.IsPressed)
{
if (left.IsPressed)
{
outside.MyMethod("7");
return;
}
if (right.IsPressed)
{
outside.MyMethod("6");
return;
}
if (down.IsPressed)
{
outside.MyMethod("1");
return;
}
outside.MyMethod("2");
}
if (down.IsPressed)
{
if (left.IsPressed)
{
outside.MyMethod("9");
return;
}
if (right.IsPressed)
{
outside.MyMethod("8");
return;
}
if (up.IsPressed)
{
outside.MyMethod("9");
return;
}
outside.MyMethod("3");
}
if (!right.IsPressed && !left.IsPressed && !up.IsPressed && !down.IsPressed)
{
outside.MyMethod("1");
}
}
public class KeyboardInfo
{
[DllImport("user32")]
private static extern short GetKeyState(int vKey);
private KeyboardInfo()
{
}
public static KeyStateInfo GetKeyState(Keys key)
{
short keyState = GetKeyState((int)key);
int low = Low(keyState), high = High(keyState);
bool toggled = low == 1;
bool pressed = high == 1;
return new KeyStateInfo(key, pressed, toggled);
}
private static int High(int keyState)
{
return keyState > 0 ? keyState >> 0x10
: (keyState >> 0x10) & 0x1;
}
private static int Low(int keyState)
{
return keyState & 0xffff;
}
}
}
}
Class
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FFApp
{
class MyClass
{
Action<String> labelSetter;
public MyClass(Action<String> labelSetter)
{
this.labelSetter = labelSetter;
}
public string MyProperty { get; set; }
public void MyMethod(string text)
{
labelSetter(text);
MyProperty = text;
}
}
}
Or is it possible within this code, to get changing values (store in a variable), when pressed W/A/D/S/W+A/W+D etc keys in order to allow building final string? ex: string finalstring = x + y + speed + pressed_key;
I am struggeling with getting my SoundEngine class's function PlaySound to be played where I want it.
The function needs to be a global function but I can't make it static as the function refers to an object that the SoundEngine makes.
I'll show the snippets that are important:
In my GameWorld class:
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Input;
using System;
using SoundEngineSpace;
public GameWorld(int width, int height, ContentManager Content)
{
screenWidth = width;
screenHeight = height;
random = new Random();
gameState = GameState.Playing;
block = Content.Load<Texture2D>("block");
font = Content.Load<SpriteFont>("SpelFont");
SoundEffect blockFallSE = Content.Load<SoundEffect>("BlockFallSE");
Song BuildingWallsintheCold = Content.Load<Song>("91 Building Walls in the Cold");
soundEngine = new SoundEngine();
soundEngine.addSound(blockFallSE);
soundEngine.addSong(BuildingWallsintheCold);
soundEngine.SetSoundVolume(20);
soundEngine.SetSongVolume(5);
soundEngine.PlaySong(0);
grid = new TetrisGrid(block);
}
In my TetrisGrid class
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using SoundEngineSpace;
...
public void TetNaarBeneden()
{
soundEngine.PlaySound(0);
InPlayGrid.Velocity = new Vector2(0, gridblock.Height);
CheckValidLocation();
}//Moves tet down
And the soundEngine class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Media;
namespace SoundEngineSpace
{
public class SoundEngine
{
private void soundEngine()
{
}
BackgroundSound backgroundSound = new BackgroundSound();
SoundEffects soundEffects = new SoundEffects();
public void addSong(Song s)
{
backgroundSound.AddBackgroundSound(s);
}
public void addSound(SoundEffect s)
{
soundEffects.AddSound(s);
}
public void PlaySong(int s)
{
backgroundSound.PlayBackgroundSound(s);
}
public void PlaySound(int s)
{
soundEffects.PlaySound(s);
}
public void SetSongVolume(int v)
{
backgroundSound.SetBackGroundSoundVolume(v);
}
public void SetSoundVolume(int v)
{
soundEffects.SetSoundEffectVolume(v);
}
}
}
class BackgroundSound
{
public static void backGroundSound()
{
}
private List<Song> BackgroundSoundEffects = new List<Song>();
private bool PlayingBackGroundSound = false;
public void AddBackgroundSound(Song s)//addsongs to the list
{
BackgroundSoundEffects.Add(s);
}
public void PlayBackgroundSound(int s)//plays BackgroundSound based on location in the list
{
MediaPlayer.IsRepeating = true;//If I use this exact soundengine again, move this to it's own function instead!
if (BackgroundSoundEffects.Count() > s)
{
if (PlayingBackGroundSound)
MediaPlayer.Stop();
MediaPlayer.Play(BackgroundSoundEffects.ElementAt(s));
PlayingBackGroundSound = true;
}
else
{
Console.WriteLine("Couldent find the BackgroundSound");
}
}
public void SetBackGroundSoundVolume(int v)
{
MediaPlayer.Volume = (float)v/100;
}
}
class SoundEffects
{
public static void soundeffects()
{
}
private List<SoundEffect> soundEffects = new List<SoundEffect>();
public void AddSound(SoundEffect s)//addsongs to the list
{
soundEffects.Add(s);
}
public void PlaySound(int s)//plays sound based on location in the list
{
if (soundEffects.Count() > s)
{
SoundEffect ToPlaySound = soundEffects.ElementAt(s);
ToPlaySound.Play();
}
else
{
Console.WriteLine("Couldent find the sound");
}
}
public void SetSoundEffectVolume(int v)
{
SoundEffect.MasterVolume = (float)v/100;
}
}
I ended up making the constructor of objects that needed acces to the SounEngine pass the SoundEngine as a paramter.
Then I could create a new soundEngine within the object I needed it to exsist and call: this.soundEngine = soundEngine.
That succesfully copied the soundEngine and let me use it's fucntions.
I wanted to create a web control which has collection featured in the ASPX. I have code below which has a problem.
I seem to turn off and objects collection editor(collection stable).But I object design information Design Time at runtime what you can not get
when I turn off the project.So in a way the information will be saved during design is disappear.
When I open the project files in aspx file nor what. Designer.cs do not coincide in any record in the file.
I want to show in the picture below, this situation partially.
Based on the above, or as seen in the example in asp.net collection listing on sample collection can fix or waiting for your advice.
Here is code
//******************************************************Rol.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace SANNET.ToolBox.TemelRoller
{/*
[ControlBuilder(typeof(ListItemControlBuilder))]
[ParseChildren(true, "Text")]*/
[TypeConverter(typeof(ExpandableObjectConverter))]
public class Rol
{
private string rolAdi;
private AksiyonTuru aksiyonIcinKullan;
private EfektTuru iseYapilacak;
private string hataMesaji;
private IOzelEfekt ozelEfekt;
public String RolAdi { get { return rolAdi; } set { rolAdi = value; } }
public AksiyonTuru AksiyonIcinKullan { get { return aksiyonIcinKullan; } set { aksiyonIcinKullan = value; } }
public EfektTuru IseYapilacak { get { return iseYapilacak; } set { iseYapilacak = value; } }
public String HataMesaji { get { return hataMesaji; } set { hataMesaji = value; } }
public IOzelEfekt OzelEfekt { get { return ozelEfekt; } set { ozelEfekt = value; } }
public Rol()
{
RolAdi = "Hicbiri";
}
/*
public string GetAttribute(string key)
{
return (String)ViewState[key];
}
public void SetAttribute(string key, string value)
{
ViewState[key] = value;
}*/
}
}
//******************************************************RolListesi.cs
using SANNET.ToolBox.Yardimcilar;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Drawing.Design;
using System.Web.UI;
namespace SANNET.ToolBox.TemelRoller
{
//[TypeConverterAttribute(typeof(System.ComponentModel.ExpandableObjectConverter))]
[TypeConverterAttribute(typeof(System.ComponentModel.ExpandableObjectConverter))]
public class RolListesi : CollectionBase//ICollection<Rol>
{
private Collection<Rol> roller;
private Control parent;
public RolListesi(Control parent)
{
this.parent = parent;
parent.PreRender += parent_PreRender;
parent.Load += parent_PreRender;
roller = new Collection<Rol>();
}
void parent_PreRender(object sender, EventArgs e)
{
RolIslemleri.PreRenderIsle((Control)sender, this);
}
public Control Parent { get { return this.parent; } }
public Rol rolGetir(String rolAdi)
{
foreach (Rol r in roller) {
if (r.RolAdi.Equals(rolAdi))
return r;
}
return null;
}
public bool Contains(String rolAdi)
{
return rolGetir(rolAdi) != null;
}
public Rol this[int index]
{
get { return (Rol)roller[index]; }
}
public void Add(Rol emp)
{
roller.Add(emp);
}
public void Remove(Rol emp)
{
roller.Remove(emp);
}
}
}
//******************************************************RolCollectionEditor.cs
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SANNET.ToolBox.TemelRoller
{
public class RolCollectionEditor : CollectionEditor
{
public RolCollectionEditor(Type type)
: base(type)
{
}
protected override string GetDisplayText(object value)
{
Rol item = new Rol();
item = (Rol)value;
return base.GetDisplayText(string.Format("{0}, {1}", item.RolAdi,
item.AksiyonIcinKullan));
}
}
}
//******************************************************SANButton.cs
using DevExpress.Web.ASPxEditors;
using SANNET.ToolBox.TemelRoller;
using System.ComponentModel;
using System.Web.UI;
namespace SANNET.ToolBox.Bilesenler
{
public class SANButton : ASPxButton, IRolSahibi
{
private RolListesi roller;
/* [Editor(typeof(System.ComponentModel.Design.CollectionEditor),
typeof(System.Drawing.Design.UITypeEditor))]*/
[Editor(typeof(RolCollectionEditor),
typeof(System.Drawing.Design.UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public RolListesi Roller { get {
if (roller == null)
{
roller = new RolListesi(this);
}
return roller; } }
}
}
The answer is
[PersistenceMode(PersistenceMode.InnerProperty)]
Here is sample usage
private Roller roller;
[Editor(typeof(RolCollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerProperty)]
public Roller Roller
{
get
{
if (roller == null)
{
roller = new Roller();
} return roller;
}
}
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.