Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I have a Flight class and a Form class, I want to send Log messages to a textfield from the Flight class to the Form.
I have an already working one for another class called Airport, but this one is practically identical, yet the event LogMessage is always null, even after subscribing.
-- MainForm --
namespace FlightSim
{
public partial class MainForm : Form
{
Airport airport = new Airport();
Luggage luggage = new Luggage();
Flight flight = new Flight();
DAO db = new DAO();
public MainForm()
{
InitializeComponent();
InitializeEvents();
}
private void InitializeEvents()
{
this.airport.ErrorMessage += new System.EventHandler(OnErrorReceived);
this.flight.LogMessage += new System.EventHandler(OnLogReceived);
}
public void OnErrorReceived(object sender, System.EventArgs e)
{
string msgContent = ((Airport.MessageEventArgs)e).msgContent;
this.mainLog.AppendText(msgContent);
}
public void OnLogReceived(object sender, System.EventArgs e)
{
string msgcontent = ((Flight.MessageEventArgs)e).msgContent;
this.mainLog.AppendText(msgcontent);
}
}
}
-- Flight --
namespace FlightSim
{
public class Flight
{
public class MessageEventArgs : System.EventArgs
{
public string msgContent;
}
public event System.EventHandler LogMessage;
DAO db = new DAO();
public Flight(string flightNumber, string departure, string destination, int totalLoadCapacity)
{
this.FlightNumber = flightNumber;
this.Departure = departure;
this.Destination = destination;
this.TotalLoadCapacity = totalLoadCapacity;
//LogMessage += (s, o) => { };
}
public void StartFlight()
{
string tmpDeparture = this.Departure;
string tmpDestination = this.Destination;
this.OnLogUpdate("Taking off from " + tmpDeparture + " now.");
this.Destination = tmpDeparture;
Thread.Sleep(1000);
this.OnLogUpdate("Arriving in " + tmpDestination + " now.");
this.Departure = tmpDestination;
}
protected void OnLogUpdate(string logMessage)
{
if (logMessage == "")
return;
MessageEventArgs e = new MessageEventArgs();
var handler = LogMessage;
if (handler != null)
{
e.msgContent = logMessage;
handler(this, e);
}
}
}
}
So, what can be the cause for an event being null even though it is subscribed?
Given the constructor with arguments and the initialization without arguments, you probably are creating another Flight class somewhere else. All you have to do is make sure that you subscribe the same event upon creation. Do something like this;
Flight someOtherFlight = new Flight("1", "Amsterdam", "Hong Kong", 500);
someOtherFlight.LogMessage += new System.EventHandler(OnLogReceived);
And you should be fine.
Edit: This MCVE works fine
Program.cs
namespace StackOverflowPlayground
{
class Program
{
static void Main(string[] args)
{
var sim = new AirportSim();
sim.flight.StartFlight();
}
}
}
FlightSim.cs
using System;
using System.Threading;
namespace StackOverflowPlayground
{
public class AirportSim
{
public Flight flight = new Flight("1","","",1);
public AirportSim()
{
InitializeEvents();
}
private void InitializeEvents()
{
flight.LogMessage += OnLogReceived;
}
public void OnLogReceived(object sender, System.EventArgs e)
{
string msgcontent = ((Flight.MessageEventArgs)e).msgContent;
Console.WriteLine(msgcontent);
}
}
public class Flight
{
public class MessageEventArgs : EventArgs
{
public string msgContent;
}
public event EventHandler LogMessage;
public Flight(string flightNumber, string departure, string destination, int totalLoadCapacity)
{
FlightNumber = flightNumber;
Departure = departure;
Destination = destination;
TotalLoadCapacity = totalLoadCapacity;
//LogMessage += (s, o) => { };
}
public string Destination { get; set; }
public int TotalLoadCapacity { get; set; }
public string Departure { get; set; }
public string FlightNumber { get; set; }
public void StartFlight()
{
string tmpDeparture = this.Departure;
string tmpDestination = this.Destination;
OnLogUpdate("Taking off from " + tmpDeparture + " now.");
Destination = tmpDeparture;
Thread.Sleep(1000);
OnLogUpdate("Arriving in " + tmpDestination + " now.");
Departure = tmpDestination;
}
protected void OnLogUpdate(string logMessage)
{
if (logMessage == "")
return;
var e = new MessageEventArgs();
var handler = LogMessage;
if (handler != null)
{
e.msgContent = logMessage;
handler(this, e);
}
}
}
}
Related
I have a websocket connection and I want to make get methods for it. I used this example.
This is a part of the data model:
public class Message
{
public string MessageType { get; set; }
}
public class SensorData : Message
{
public float Temperature { get; set; }
public float Humidity { get; set; }
public float Pressure { get; set; }
}
This is the websocket class:
public WebSocketConnection(string url)
{
socket = new WebSocket(url);
}
private WebSocket socket;
public int Timeout = 10000;
public void Connect()
{
socket.Connect();
socket.OnMessage += Socket_OnMessage;
}
public void Disconnect()
{
socket.Close();
socket.OnMessage -= Socket_OnMessage;
}
public event EventHandler<OnSensorDataEventArgs> SensorDataReveived;
private void Socket_OnMessage(object sender, MessageEventArgs e)
{
var msg = JsonConvert.DeserializeObject<Message>(e.Data);
switch (msg.MessageType)
{
case "other message types":
{
...
}
case "SensorData":
{
SensorDataReveived?.Invoke(this, new OnSensorDataEventArgs(JsonConvert.DeserializeObject<SensorData>(e.Data)));
break;
}
}
}
public Task<SensorData> GetSensorData()
{
var msg = JsonConvert.SerializeObject(new Message() { MessageType = "RequestSensorData" });
var tcs = new TaskCompletionSource<SensorData>();
SensorDataReveived += (sender, e) => {
tcs.SetResult(e.SensorData);
};
socket.Send(msg);
return tcs.Task;
}
The problem is the GetSensorData method. When socket.Send(msg) is called, the websocket server answers and the event is triggered, but after the SetResult call there happens nothing. I already tried TaskCreationOptions.RunContinuationsAsynchronously and wrapping SetResult in a Task.Run but that didn't help.
private async void BtnShowSensorData_Clicked(object sender, EventArgs e)
{
var sensorData = await connection.GetSensorData(); //Connection is an instance of WebSocketConnection
labelTemperature.Text = " Temperature: " + sensorData.Temperature.ToString();
labelHumidity.Text = " Humidity: " + sensorData.Humidity.ToString();
labelPressure.Text = " Pressure: " + sensorData.Pressure.ToString();
}
/* class library /
/ calcEventArgs.cs */
namespace calc1
{
public class calcEventArgs
{
}
public class CalculationCompletedEventArgs : System.EventArgs
{
public string StringValue { get; set; }
public int IntegerValue { get; set; }
}
}
/* CalcMain.xaml.cs */
namespace calc1
{
public partial class CalcMain : Page
{
public delegate void CalcEventHandler(object sender, CalculationCompletedEventArgs e);
public event CalcEventHandler CalculateCompletedEvent;
public CalcMain()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
CalculationCompletedEventArgs pArgs = new CalculationCompletedEventArgs();
pArgs.StringValue = "1 + 1";
pArgs.IntegerValue = 2;
CalcEventHandler eh = CalculateCompletedEvent;
if (eh != null) eh(this, pArgs);
}
}
}
/* EventTest application program */
namespace EventTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
calc1.CalcMain c = new calc1.CalcMain();
c.CalculateCompletedEvent += new calc1.CalcMain.CalcEventHandler(CalcfromPage);
}
private void CalcfromPage(object sender, calc1.CalculationCompletedEventArgs e)
{
MessageBox.Show(e.StringValue + " = " + e.IntegerValue.ToString());
}
private void Button_Click(object sender, RoutedEventArgs e)
{
fraMainScreen.Navigate(new Uri("pack://application:,,,/calc1;component/CalcMain.xaml", UriKind.Absolute));
}
}
}
this is my code
i have problem ...
CalcEventHandler eh = CalculateCompletedEvent
CalculateCompletedEvent is always null..
help..
thanks. ^^
This is my class, I always get a null insted of my panel...
Can someone give me a hint on how to do this?
[Serializable]
public class DragDropBlock : Panel
{
public DragDropBlock()
{
this.MouseDown += new MouseEventHandler(Mouse_Down);
this.MouseUp += new MouseEventHandler(Mouse_Up);
}
void Mouse_Down(object sender, System.Windows.Forms.MouseEventArgs e)
{
Clipboard.SetData("DragDropBlock", this);
}
void Mouse_Up(object sender, System.Windows.Forms.MouseEventArgs e)
{
IDataObject IBlock = Clipboard.GetDataObject();
DragDropBlock Block = (DragDropBlock)IBlock.GetData(typeof(DragDropBlock));
}
}
Given a class:
[Serializable]
class Test
{
public string Data
{
get;
set;
}
}
This works:
Test t = new Test()
{
Data = "DERP!"
};
Clipboard.SetData("Test", t);
Test newT = (Test)Clipboard.GetData("Test");
Console.WriteLine(newT.Data);
And if you want to use data objects:
Test t = new Test()
{
Data = "DERP!"
};
Clipboard.SetDataObject(new DataObject("Test", t));
Test newT = (Test)Clipboard.GetDataObject().GetData("Test");
Console.WriteLine(newT.Data);
The output to both of those is:
DERP!
This is the correction of my class: Working!!!
[Serializable]
class DragBlock
{
public string Data
{
get;
set;
}
}
public class DragDropBlock : Panel
{
DragBlock Block;
public DragDropBlock()
{
this.MouseDown += new MouseEventHandler(Mouse_Down);
this.MouseUp += new MouseEventHandler(Mouse_Up);
Block = new DragBlock()
{
Data = "TEST!"
};
}
void Mouse_Down(object sender, System.Windows.Forms.MouseEventArgs e)
{
Clipboard.SetDataObject(new DataObject("DragBlock", Block));
}
void Mouse_Up(object sender, System.Windows.Forms.MouseEventArgs e)
{
DragBlock newBlock = (DragBlock)Clipboard.GetDataObject().GetData("DragBlock");
Console.WriteLine(newBlock.Data);
}
}
I have this simple project to grab HTML element inner data. This is a DLL Project.
public class WebGrabber
{
public string URL { set; get; }
public string Element { set; get; }
public bool FindByID { set; get; }
private WebBrowser b { set; get; }
private mshtml.IHTMLDocument2 doc { set; get; }
public void GetPageElementInnerHTML(string url, string element, bool findById)
{
URL = url;
Element = element;
FindByID = findById;
b = new WebBrowser();
b.Navigate(url);
b.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(b_DocumentCompleted);
}
void b_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
doc = (IHTMLDocument2)b.Document.DomDocument;
string result = "<html>";
IHTMLElement head = (IHTMLElement)((IHTMLElementCollection)doc.all.tags("head")).item(null, 0);
result += "<head>" + head.innerHTML + "</head>";
if (null != doc)
{
foreach (IHTMLElement element in doc.all)
{
if (element is mshtml.IHTMLDivElement)
{
dynamic div = element as HTMLDivElement;
if (FindByID)
{
string id = div.id;
if (id == Element)
{
result += "<body>" + div.IHTMLElement_innerHTML + "</body></html>";
break;
}
}
else
{
string className = div.className;
if (className == Element)
{
result += "<body>" + div.IHTMLElement_innerHTML + "</body></html>";
break;
}
}
}
}
}
doc.close();
}
}
What I need is to implement access to string result variable.
So it could be possible to get asynchronously this variable from other project.
Perhaps I need some GetResult(); method?....
How I can do it?
Thank you!
You can pass the eventhandler as an argument then work with the result in the app no in the class library o just pass a callback and invoke after download is complete.
I'm new here so i hope i did understand what you wanted.
Passing the evnthandler
public void GetPageElementInnerHTML(string url, string element, bool findById, WebBrowserDocumentCompletedEventHandler downloadComplete)
Using a delegate:
public class WebGrabber
{
public string URL { set; get; }
public string Element { set; get; }
public bool FindByID { set; get; }
private WebBrowser b { set; get; }
private mshtml.IHTMLDocument2 doc { set; get; }
public delegate void DownloadCompletedDelegate(string result);
private DownloadCompletedDelegate _downloadedComplete;
public void GetPageElementInnerHTML(string url, string element, bool findById, DownloadCompletedDelegate downloadComplete)
{
_downloadedComplete = downloadComplete;
URL = url;
Element = element;
FindByID = findById;
b = new WebBrowser();
b.Navigate(url);
b.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(b_DocumentCompleted);
}
void b_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
doc = (IHTMLDocument2)b.Document.DomDocument;
string result = "<html>";
IHTMLElement head = (IHTMLElement)((IHTMLElementCollection)doc.all.tags("head")).item(null, 0);
result += "<head>" + head.innerHTML + "</head>";
if (null != doc)
{
foreach (IHTMLElement element in doc.all)
{
if (element is mshtml.IHTMLDivElement)
{
dynamic div = element as HTMLDivElement;
if (FindByID)
{
string id = div.id;
if (id == Element)
{
result += "<body>" + div.IHTMLElement_innerHTML + "</body></html>";
break;
}
}
else
{
string className = div.className;
if (className == Element)
{
result += "<body>" + div.IHTMLElement_innerHTML + "</body></html>";
break;
}
}
}
}
}
doc.close();
_downloadedComplete.Invoke(result);
}
}
In the APP
GetPageElementInnerHTML(URL, element, true/false, CompletedCallback);
private void CompletedCallback(string result)
{
//your code
}
Here is working code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using mshtml;
using System.Collections;
namespace MyCompany.WebpageGrabber
{
// A delegate type for hooking up change notifications.
public delegate void ChangedEventHandler(object sender, EventArgs e);
public class WebGrabber : ArrayList
{
// An event that clients can use to be notified whenever the
// elements of the list change.
public event ChangedEventHandler Changed;
// Invoke the Changed event; called whenever list changes
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this, e);
}
// Override some of the methods that can change the list;
// invoke event after each
public override int Add(object value)
{
int i = base.Add(value);
OnChanged(EventArgs.Empty);
return i;
}
public override void Clear()
{
base.Clear();
OnChanged(EventArgs.Empty);
}
public override object this[int index]
{
set
{
base[index] = value;
OnChanged(EventArgs.Empty);
}
}
public string URL { set; get; }
public string Element { set; get; }
public bool FindByID { set; get; }
private WebBrowser b { set; get; }
private mshtml.IHTMLDocument2 doc { set; get; }
public void GetPageElementInnerHTML(string url, string element, bool findById)
{
URL = url;
Element = element;
FindByID = findById;
b = new WebBrowser();
b.Navigate(url);
b.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(b_DocumentCompleted);
}
void b_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
doc = (IHTMLDocument2)b.Document.DomDocument;
string result = "<html>";
IHTMLElement head = (IHTMLElement)((IHTMLElementCollection)doc.all.tags("head")).item(null, 0);
result += "<head>" + head.innerHTML + "</head>";
if (null != doc)
{
foreach (IHTMLElement element in doc.all)
{
if (element is mshtml.IHTMLDivElement)
{
dynamic div = element as HTMLDivElement;
if (FindByID)
{
string id = div.id;
if (id == Element)
{
result += "<body>" + div.IHTMLElement_innerHTML + "</body></html>";
break;
}
}
else
{
string className = div.className;
if (className == Element)
{
result += "<body>" + div.IHTMLElement_innerHTML + "</body></html>";
break;
}
}
}
}
}
doc.close();
this.Add(result);
}
}
}
and here is code how we call it:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
WebGrabber g = new WebGrabber();
g.GetPageElementInnerHTML("http://www.google.com/web/guest/home", "portlet-borderless-container", false);
g.Changed += new ChangedEventHandler(g_Changed);
}
void g_Changed(object sender, EventArgs e)
{
var html = ((WebGrabber)sender)[0];
}
I have a background process that i want to regularly maintain the state of gps location. I am not clear on how to invoke a delegate on the main thread in the ui layer when the threaded method is in another class. Here is sample code. My form launches the thread on load:
public partial class MainScreen : Form
{
.
. // form stuff
.
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
Thread t = new Thread(gpsStatusManager.UpdateLocation);
t.IsBackground = true;
t.Start();
}
delegate void GpsDataParameterDelegate(GpsStatus value);
public void UpdateGpsStatus(GpsStatus value)
{
if (InvokeRequired)
{
// We're not in the UI thread, so we need to call BeginInvoke
BeginInvoke(new GpsDataParameterDelegate(UpdateGpsStatus), new object[] { value });
return;
}
// Must be on the UI thread if we've got this far
gpsStatus.SetGpsStatus(value);
}
}
I have a domain object class for the gps information:
public class GpsStatus
{
public void SetGpsStatus(GpsStatus gpsStatus)
{
Latitude = gpsStatus.Latitude;
Longitude = gpsStatus.Longitude;
CurrentDateTime = gpsStatus.CurrentDateTime;
NumberOfSatellites = gpsStatus.NumberOfSatellites;
TotalNumberSatellites = gpsStatus.TotalNumberSatellites;
}
public float Latitude { get; private set; }
public float Longitude { get; private set; }
public DateTime CurrentDateTime { get; private set; }
public int NumberOfSatellites { get; private set; }
public int TotalNumberSatellites { get; private set; }
}
Then, my manager class where i update status in the secondary thread:
public class GpsStatusManager
{
private GpsStatus _gpsStatus;
public void UpdateLocationx()
{
while (UpdateGpsData())
{
Thread.Sleep(2000);
}
}
private bool UpdateGpsData()
{
SError error;
SGpsPosition gpsPosition;
try
{
if (CApplicationAPI.GetActualGpsPosition(out error, out gpsPosition, true, 0) != 1)
return false;
}
catch (Exception)
{
return false;
}
var numberOfSatellites = gpsPosition.Satellites;
var totalSatellites = gpsPosition.satellitesInfo;
var datetime = gpsPosition.Time;
var lat = gpsPosition.Latitude;
var lon = gpsPosition.Longitude;
_gpsStatus.SetGpsStatus(lat, lon, datetime, numberOfSatellites, totalSatellites);
//How do I invoke the delegate to send the _gpsStatus data to my main thread?
return true;
}
}
Thanks for any assistance.
Here's one way to do it, just off the top of my head:
public class GpsStatusEventArgs : EventArgs
{
public GpsStatus Status { get; private set; }
public GpsStatusEventArgs(GpsStatus status)
{
Status = status;
}
}
public class GpsStatusManager
{
...
public event EventHandler<GpsStatusEventArgs> GpsStatusUpdated;
private void OnGpsStatusUpdated(GpsStatus gpsStatus)
{
EventHandler<GpsStatusEventArgs> temp = GpsStatusUpdated;
if (temp != null)
temp.Invoke(this, new GpsStatusEventArgs(gpsStatus));
}
}
public partial class MainScreen : Form
{
...
private void MainScreen_Load(object sender, EventArgs e)
{
var gpsStatusManager = new GpsStatusManager();
gpsStatusManager.GpsStatusUpdated += new EventHandler<GpsStatusEventArgs>(GpsStatusManager_GpsStatusUpdated);
...
}
private void GpsStatusManager_GpsStatusUpdated(object sender, GpsStatusEventArgs e)
{
UpdateGpsStatus(e.Status);
}
...
}
Then add this to the bottom of UpdateGpsData:
OnGpsStatusUpdated(_gpsStatus);
You should use the SynchronizationContext class.
In the UI thread (in any class), set a field (perhaps static) to SynchronizationContext.Current.
You can then call Send or Post on the saved instance to execute code on the UI thread.
Here is another approach using the ISynchronizeInvoke interface. This is the same pattern the System.Timers.Timer class uses to raise the Elapsed event.
public class GpsStatusManager
{
public ISynchronizeInvoke SynchronizingObject { get; set; }
public event EventHandler Update;
public void UpdateGpsData()
{
// Code omitted for brevity.
OnUpdate(_gpsStatus);
return true;
}
private OnUpdate(GpsStatus status)
{
if (SynchronizingObject != null && SynchronizingObject.IsInvokeRequired)
{
ThreadStart ts = () => { OnUpdate(status); };
SynchronizingObject.Invoke(ts, null);
}
else
{
if (Update != null)
{
Update(this, status);
}
}
}
public class UpdateEventArgs : EventArgs
{
public GpsStatus Status { get; set; }
}
}