I have mad a custom control. and i need to redirect the Event handler. i have cut the code down dramatically to try and articulate what im trying to do.
public class RemoteDesktop : WindowsFormsHost
{
public event OnConnectingEventHandler OnConnecting;
public delegate void OnConnectingEventHandler(object sender, EventArgs Arguments);
public event OnDisconnectingEventHandler OnDisconnecting;
public delegate void OnDisconnectingEventHandler(Object sender, IMsTscAxEvents_OnDisconnectedEvent Arguments);
private AxMsRdpClient7NotSafeForScripting RDPUserControl = new AxMsRdpClient7NotSafeForScripting();
public RemoteDesktop()
{
this.RDPUserControl.BeginInit();
this.RDPUserControl.SuspendLayout();
base.Child = RDPUserControl;
this.RDPUserControl.ResumeLayout();
this.RDPUserControl.EndInit();
}
}
public class RemoteDesktopViewModel
{
public RemoteDesktopViewModel()
{
RemoteDesktop newRDC = new RemoteDesktop();
newRDC.OnConnecting += new RemoteDesktop.OnConnectingEventHandler(newRDC_OnConnecting);
}
void newRDC_OnConnecting(object sender, EventArgs Arguments)
{
//DoStuff
}
}
basically it all works, i can connect and disconnect to the remote computer however i cannot get the fired events to occur in my view model.
Can anyone help me figure out how i can point my events correctly.
Thank you.
Thanks to some help i have the resolution
Step 1:
Declare delegates outside the class (within the namespace)
Step 2:
Declare the events to be called for the control.
Step 3: use the event handlers of the controls to reise the delegates you created
Completed Code
public delegate void OnConnectingEventHandler(object sender, EventArgs Arguments);
public delegate void OnDisconnectingEventHandler(Object sender,IMsTscAxEvents_OnDisconnectedEvent Arguments);
public class RemoteDesktop : WindowsFormsHost
{
public event OnConnectingEventHandler IsConnecting;
public event OnDisconnectingEventHandler IsDisconnecting;
private AxMsRdpClient7NotSafeForScripting RDPUserControl = new AxMsRdpClient7NotSafeForScripting();
public RemoteDesktop()
{
this.RDPUserControl.BeginInit();
this.RDPUserControl.SuspendLayout();
base.Child = RDPUserControl;
this.RDPUserControl.ResumeLayout();
this.RDPUserControl.EndInit();
RDPUserControl.OnConnecting += RemoteDesktop_OnConnecting;
RDPUserControl.OnDisconnected += RDPUserControl_OnDisconnected;
}
void RDPUserControl_OnDisconnected(object sender, IMsTscAxEvents_OnDisconnectedEvent e)
{
IsDisconnecting(sender, e);
}
void RemoteDesktop_OnConnecting(object sender, EventArgs Arguments)
{
IsConnecting(sender, Arguments);
}
}
public class RemoteDesktopViewModel
{
public RemoteDesktopViewModel()
{
RemoteDesktop newRDC = new RemoteDesktop();
newRDC.IsConnecting += new RemoteDesktop.OnConnectingEventHandler(newRDC_OnConnecting);
}
void newRDC_OnConnecting(object sender, EventArgs Arguments)
{
//DoStuff
}
}
//at the constractor of the class
OnConnecting+=RDC_OnConnecting;
then you can write your logic in method:newRDC_OnConnecting. make sure OnConnectingEventHandler have same method signatures with newRDC_OnConnecting.
Related
I have a class that calls another class - the new class has events that I have defined for it. I am subscribed to the events in my calling class but my calling class does not seem to be able to get the EventArgs. I know I must be doing something ignorant here but I don't know what.
My code abbreviated below. WorkControl is the main process and calls MyProcess which executes some code and fires off the event.
public class WorkControl
{
public MyProcess myp;
public WorkControl()
{
myp.InBoxShareDisconnected += OnShareFolderDisconnected();
}
private EventHandler OnShareFolderDisconnected<NetworkShareDisconnectedEventArgs>()
{
// How do I get my EventArgs from the event?
throw new NotImplementedException();
}
}
public class MyProcess
{
public void MyDisconnectTrigger
{
NetworkShareDisconnectedEventArgs e =
new NetworkShareDisconnectedEventArgs(path, timestamp, connected);
OnInBoxShareDisconnected(e);
}
public event EventHandler<NetworkShareDisconnectedEventArgs> InBoxShareDisconnected;
protected void OnInBoxShareDisconnected(NetworkShareDisconnectedEventArgs e)
{
// InBoxShareDisconnected(this, e);
InBoxShareDisconnected.SafeInvoke(this, e);
}
}
You have a couple problems. Your MyProcess class shouldn't raise events in the constructor and the MyWorker class needs to have an instance of MyProcess to attach the event to. The other problem is that you need to declare the event handler correctly.
Lets look at the proper event pattern for your producer MyProcess class:
public class MyProcess
{
public event EventHandler<NetworkShareDisconnectedEventArgs> InBoxShareDisconnected;
public MyProcess()
{
//This doesn't really do anything, don't raise events here, nothing will be
//subscribed yet, so nothing will get it.
}
//Guessing at the argument types here
public void Disconnect(object path, DateTime timestamp, bool connected)
{
RaiseEvent(new NetworkShareDisconnectedEventArgs(path, timestamp, connected));
}
protected void RaiseEvent(NetworkShareDisconnectedEventArgs e)
{
InBoxShareDisconnected?.Invoke(this, e);
}
}
And now we can look at your consumer class:
public class WorkControl
{
private MyProcess _myProcess;
public WorkControl(MyProcess myProcess)
{
_myProcess = myProcess; //Need to actually set it to an object
_myProcess.InBoxShareDisconnected += HandleDisconnected;
}
private void HandleDisconnected(object sender, NetworkShareDisconnectedEventArgs e)
{
//Here you can access all the properties of "e"
}
}
So now you can consume the events in the consumer class and have access to all the properties of the NetworkShareDisconnectedEventArgs arguments. This is a pretty standard event producer/consumer model.
I have this code below:
using System;
using System.Windows.Forms;
namespace MyCode
{
public partial class Main_GUI : Form
{
//Attributes
private Processes process;
//Constructor
public Main_GUI()
{
InitializeComponent(); //a form with a button named BUTTON_Start, and a label named LABEL_log
p = new Processes();
}
//OnClickStart
private void BUTTON_Start_Click(object sender, EventArgs e)
{
try
{
LABEL_log.Text = "Started...";
p.start();
}
catch (Exception ex)
{
//do something with the exception
}
}
}//End of Class
public class Processes
{
//Constructor
public Processes() { }
//Methods
public void start()
{
try
{
//Do something
//...
//when finished send an event the Main_GUI Class (Form) in order to change the LABEL_log.Text value to "finished !"
}
catch (Exception e)
{
//do something with the exception
}
}
}
}
I ve tried a lot to create some events, I even use this example :
http://www.codeproject.com/Articles/11541/The-Simplest-C-Events-Example-Imaginable
but I cant understant how to create an event with my classes...
I such a fool I know but I really need your help !
Thanks the team !!
Regards.
FB
Define the event in the Process class:
public event EventHandler Finished;
Then in the same class define a method that raises the event "safely":
protected void RaiseFinished()
{
// Make sure the event has at least one subscriber.
if(Finished != null)
{
Finished(this, EventArgs.Empty);
}
}
You call the method where you want your event to be raised, in your case the start method:
public void Start()
{
try
{
//Do something
//...
RaiseFinished();
}
catch (Exception e)
{
//do something with the exception
}
}
Then in your Main_GUI class constructor subscribe to the event defining an handler:
//Constructor
public Main_GUI()
{
InitializeComponent(); //a form with a button named BUTTON_Start, and a label named LABEL_log
p = new Processes();
// Subscribe to the event.
p.Finished += p_Finished;
}
// This will get called when the Finished event is raised.
private void p_Finished(object sender, EventArgs e)
{
LABEL_log.Text = "Finished!";
}
Is it possible to send reference of 'sender' without specifying it explicitly as a parameter in delegate-based event handling?
I have a internal class which raises some events and I want to call the events explicitly for test purposes.
public class Manager {
public class DataStruct {
public int Id { get; private set; }
public event EventHandler Event1; // Can't be called by other classes
public void fireEvent1(Event1();} // So another caller...
// Delegates *can* be called by other classes
public delegate void DelegateHandler(DataStruct sender);
public DelegateHandler NewEvent;
public void DelegateHandler(DataStruct sender) {
MessageBox.Show(string.Format(
"{0} raises event", sender.Id));
}
}
}
// Form1 ///////////////////////////////////////////////////////////////////
partial class Form1 {
Manager.DataStruct dsRaiser, dsListener;
private void Form1_Load(object sender, EventArgs e) {
dsRaiser.Event1 += dsListener.SOME_HANDLER;
dsRaiser.NewEvent += dsListener.DelegateHandler;
}
private void button1_Click(object sender, ...) {
dsRaiser.fireEvent1(); // No argument needed but fireEvent1, not Event1().
}
private void button2_Click(object sender, ...) {
dsRaiser.NewEvent(dsRaiser); // Way to omit parameter dsRaiser?
}
//////////////////////////////////////////////////////////////////////////
If your handler method needs to use the sender's reference, then you HAVE to pass that reference.
If not, just declare a void parameterless delegate, like Action.
But when thinking of events, that parameter should be passed by the class that raises the event itself. (Remember events are not meant to be called from outside).
So, if you really want to use a simple delegate instead of an event, you will have to pass the parameters.
If you need the sender, you will need to do exactly what you did with the event: create a method to "raise" the delegate, and in that method you pass this as the sender.
But considering you have to do exactly the same thing in both cases, I'd surely use the event.
public class DataStruct {
public int Id { get; private set; }
public event EventHandler Event1; // Can't be called by other classes
// you need to pass those parameters to the event when called.
public void fireEvent1{Event1(this, new EventArgs());}
// Delegates *can* be called by other classes, but only with all parameters passed.
public delegate void DelegateHandler(DataStruct sender);
public DelegateHandler NewEvent;
// To avoid passing parameters, you need to do exactly what you did with the event
public void RaiseDelegate() { NewEvent(this); }
public void DelegateHandler(DataStruct sender) {
MessageBox.Show(string.Format(
"{0} raises event", sender.Id));
}
}
Yes, it is possible.
Just store the sender inside the subscription when subscribing to an event.
If we had a delegate declared like this:
public Action NewEvent; // No need to be DelegateHandler
Then we can use c# compiler to generate such a subscription for us using anonymous delegates:
dsRaiser.NewEvent += () =>
{
dsListener.DelegateHandler(dsRaiser);
};
Anything, which we reference inside our anonymous handler is automatically captured for us (both dbListener and dsRaiser in this case).
Or, if we want explicit declaration of the subscription:
class MySubscription
{
private readonly DataStruct _raiser;
private readonly DataStruct _listener;
public MySubscription(DataStruct raiser, DataStruct listener)
{
_raiser = raiser;
_listener = listener;
}
public void HandleTheSubscription()
{
_listener.DelegateHandler(_raiser);
}
}
And this is how we subscribe:
private void Form1_Load(object sender, EventArgs e) {
var mySubscription = new MySubscription(dsRaiser,dsListener);
dsRaiser.NewEvent += mySubscription.HandleTheSubscription;
}
As you can see MySubscription is defined by us and we can store any objects there.
Goal: To change a image on a form when either udp or tcp uses its send method
Problem: I have no idea how to get the event, eventhandler and delegates set up correctly
Send Interface
interface ISendData
{
void Send();
}
Tcp Connection class
//Need some type of delegate??
public class TCPconnection : ISendData
{
void Send()
{
//how invoke/fire a send Event?
}
}
UDP Connection class
//Need some type of delegate??
public class UDPConnection : ISendData
{
void Send()
{
//how invoke/fire a send event?
}
}
the winform which 'should' subscribe to seeing the fired events
public class myForm
{
private DataWatcher datawatcher = new DataWatcher();
private Image statusIndicator = null;
public myform()
{
initComponents();
datawatcher.DataSendActive += new DataWatcherSendHandler(DataSending);
datawatcher.DataSendInactive += new DataWatcherSendHandler(NoDataSending);
}
public void DataSending(object sender, DataWatcherArgs e)
{
statusIndicator = Properties.resources.greenLight;
}
public void NoDataSending(object sender, DataWatcherArgs e)
{
statusIndicator = Properties.resources.redLight;
}
}
The Event/Event handler?? But I really have no Idea what I'm doing here to make this work
public delegate void EventHandler(object sender, EventArgs e);
class DataWatcher
{
public event EventHandler DataSendActive;
public event EventHandler DataSendInactive;
protected virtual void onDataSendActive(System.EventArgs e)
{
if (DataSendActive != null)
{
DataSendActive(this, e);
}
}
protected virtual void onDataSendInactive(System.EventArgs e)
{
if (DataSendInactive != null)
{
DataSendInactive(this, e);
}
}
}
There are many conventions used to do this. Here's my little implementation.
public enum ActivityState
{
Sending,
Receiving,
Idle
}
public interface IDataTransferManager
{
// This event will fire when the activity state changes.
// note that Action<T> is introduced in .NET 3.5
// if you're using .NET 2.0, you can use a delegate.
event Action<ActivityState> DataActivityStateChange;
void Send(byte[] data);
//byte[] Receive();
// ... more methods ... //
}
Now the TcpConnection class will implement this.
public class TcpConnection : IDataTransferManager
{
public event Action<ActivityState> DataActivityStateChange;
public void Send(byte[] data)
{
// we're sending data. fire the change event
FireDataActivityStateChange(ActivityState.Sending);
//TODO: send the data
// we're done sending. Fire the change event
FireDataActivityStateChange(ActivityState.Idle);
}
private void FireDataActivityStateChange(ActivityState state)
{
// helper method, so I don't have to check the event
// to avoid null reference exceptions.
if (DataActivityStateChange != null)
DataActivityStateChange(state);
}
}
Here's the setup for your Form.
class MyForm // :Form
{
IDataTransferManager dataManager;
public MyForm()
{ // here, usually an instance will be passed in,
// so there's only one instance throughout the application.
// let's new up an instance for explanation purposes.
dataManager = new TcpConnection();
dataManager.DataActivityStateChange += (state) =>
{
// NOTE: if you don't like inline,
// you can point this labda to a method.
switch (state)
{
case ActivityState.Sending:
// change the image to the spinning toilet ball
break;
case ActivityState.Receiving:
// change the image to the spinning toilet ball, but reverse :P
break;
case ActivityState.Idle:
// hide it ?
break;
}
};
}
}
Here is a simple example of how you could implement an event for sending and not sending and subscribe to it
public class Connection
{
//Set up an event
public event EventHandler DataSending;
public event EventHandler DataNotSending
//This method will trigger the event for sending
private void OnDataSending()
{
if (DataSending!= null) { DataSending(this, EventArgs.Empty); }
}
//this method will trigger the event for finished sending
private void OnDataNotSending()
{
if (DataNotSending!= null) { DataNotSending(this, EventArgs.Empty); }
}
//This method performs your send logic
public void Send()
{
//Call your method that tells the event to be raised
OnDataSending();
//Then put your send code
OnDataNotSending(); //we're done!
}
}
This is how you use it in a consuming program
public class myForm
{
//This method is the one that sets up the
//instance and subscribes to the event
public myForm()
{
Connection con = new Connection();
con.DataSending += new EventHandler(con_DataSending);
con.DataNotSending += new EventHander(con_DataNotSending);
}
void con_DataSending(object sender, EventArgs e)
{
//Put your subscription logic here.
//Whatever you want to do in response to a send
}
void con_DataNotSending(object sender, EventArgs e)
{
//Put your subscription logic here.
//Respond to it not sending
}
}
Is it possible to create a weak event listener on a static event using WeakEventManager?
I would like to create a weak event listener on the static CompositionTarget.Rendering event to avoid memory leaks when I don't know the lifetime of the WPF/Silverlight source element.
I implemented the rendering event manager by the weak event pattern:
public class RenderingEventManager : WeakEventManager
{
public static void AddListener(IWeakEventListener listener)
{
CurrentManager.ProtectedAddListener(null, listener);
}
public static void RemoveListener(IWeakEventListener listener)
{
CurrentManager.ProtectedRemoveListener(null, listener);
}
private static RenderingEventManager CurrentManager
{
get
{
var managerType = typeof(RenderingEventManager);
var manager = (RenderingEventManager)GetCurrentManager(managerType);
if (manager == null)
{
manager = new RenderingEventManager();
SetCurrentManager(managerType, manager);
}
return manager;
}
}
protected sealed override void StartListening(object source)
{
CompositionTarget.Rendering += this.OnCompositionTargetRendering;
}
protected sealed override void StopListening(object source)
{
CompositionTarget.Rendering -= this.OnCompositionTargetRendering;
}
void OnCompositionTargetRendering(object sender, EventArgs e)
{
this.DeliverEvent(sender, e);
}
}
and tested the manager in a simple window:
public partial class Window1 : Window, IWeakEventListener
{
public Window1()
{
InitializeComponent();
RenderingEventManager.AddListener(this);
}
bool IWeakEventListener.ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
{
return true;
}
}
The ReceiveWeakEvent method is not being called. OnCompositionTargetRendering is called, but it seems like DeliverEvent does not work as I expected.
Adding listeners to instance events like Button.Click works fine...
The test project is on .NET 4.0 Client Profile.
A post on Microsoft Connect from 2009 states that static events are not supported,
but I checked the WeakEventManager source code, and it looks ok:
protected void ProtectedAddListener(object source, IWeakEventListener listener)
{
Debug.Assert(listener != null, "Listener cannot be null");
object sourceKey = (source != null) ? source : StaticSource;
...
}
Figured it out myself: change the sender argument of the DeliverEvent method to null:
void OnCompositionTargetRendering(object sender, EventArgs e)
{
this.DeliverEvent(null, e);
}