I cannot extend (subclass) DataReceivedEventArgs? - c#

I'm trying to extend DataReceivedEventArgs so that I can pass in additional data to a class that is extending Process. Pretty much rather than just get Data from a process when hooking up to Process.OutputDataReceived, I would like to pass in a control for it to write to.
When trying to extend DataReceivedEventArgs I get errors:
The type 'System.Diagnostics.DataReceivedEventArgs' has no constructors defined
public class DataReceivedArgsWithControl : DataReceivedEventArgs
{
public Control ControlAdded { get; set; }
}
How can I add another property to this Args? I've extended EventArgs itself because it has a constructor, but not sure how to extend this Args.

I suspect that you can't because the constructor is Internal. Perhaps a better approach would be to wrap the DataReceivedEventArgs inside your EventArgs derived class.
class MyDataReceivedEventArgs : EventArgs
{
DataReceivedEventArgs _inner;
public MyDataReceivedEventArgs(DataReceivedEventArgs inner, object extraProperty)
{
_inner = inner;
ExtraProperty = extraProperty;
}
public object ExtraProperty { get; private set;}
public DataReceivedEventArgs DataArgs
{
get
{
return _inner;
}
}
}
Of course, this might not be suitable if you need the polymorphism with DataReceivedEventArgs. If you have an event handler that is expecting a DataReceivedEventArgs then it won't work with the wrapper class. For example:
public void MyHandler(object sender, DataReceivedEventArgs e) { ... }
This could only receive a DataReceivedEventArgs instance or an instance of a derived type, which your wrapper is not. So it depends if you need to treat your custom EventArgs class is if it were a DataReceivedEventArgs anywhere.
UPDATE-
If you can't change the signature of the delegate you're using from public delegate void DataReceivedEventHandler(object sender, DataReceivedEventArgs e) then you can still subscribe using a method with the signature void MyEventHandler(object sender, EventArgs e) thanks to contravariance of delegate parameters and then check the actual type of the EventArgs parameter.
public void MyEventHandler(object sender, EventArgs e)
{
var dataEventArgs = e as MyDataReceivedEventArgs;
if(dataEventArgs != null
{
var extendedProperty = dataEventArgs.ExtraProperty;
var innerArgs = dataEventArgs.DataArgs;
}
}
The ideal option would be to redefine the delegate type to match your wrapper, but the above approach will work.

Related

C# Calling a method

I have a form with multiple instances of a user control on it.
I've assigned the following:
Switch.armySwitchCloseButton.Click += armySwitchClose;
So when one of those instances is pressed, I call the following method:
void armySwitchClose(object sender, EventArgs e)
The above method has a bunch of additional code in it which isn't required for here.
Now what I need to do is from another button, call this above function from every instance.
How can I do this?
Many Thanks
In constructor of each user control you can pass the same instance of some object who knows how to run this method
void armySwitchClose(object sender, EventArgs e)
Then, you call this method inside each event method, for ex:
Public Class UserControl(){
private MakeEvent makeEvent;
Public MyClass(MakeEvent makeEvent)
{
this.makeEvent = makeEvent;
Switch.armySwitchCloseButton.Click += armySwitchClose;
}
void armySwitchClose(object sender, EventArgs e)
{
makeEvent.armySwitchClose(sender,e);
}
}
Public Class MakeEvent() {
void armySwitchClose(object sender, EventArgs e)
{
//the real implementation
}
}
Hope this solve your problem.
Oh, I think I get your problem wrong... When you click in one button all the other events in others UC must be triggered, right? This problem can be solved with the Observer Pattern
Public Interface IObserver
{
void armySwitchClose(object sender, EventArgs e);
}
Public UserControl1: Observer
{
void armySwitchClose(object sender, EventArgs e)
{
//implementation UC1
}
}
Public UserControl2: Observer
{
void armySwitchClose(object sender, EventArgs e)
{
//implementation UC2
}
}
In button UC:
Public UserControlButton
{
private List<IObserver> observers;
public void addObserver(IObserver observer)
{
observers.Add(observer);
}
public void button_clickedEvent(object sender, EventArgs e)
{
foreach(IObserver observer in observers)
{
observer.armySwitchClose(object sender, EventArgs e);
}
}
}
In form with all buttons you call addObserver adding each user control.

Call Class Method from other Class not working

I'm trying to call methods from class "Form1" from an other class.
Here's my Code
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
MessageBox.Show("loaded");
orders.ObjectForScripting = new ScriptInterface();
}
private void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { }
private void button1_Click_1(object sender, EventArgs e) { }
}
[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class ScriptInterface
{
public void callMe(string currid)
{
MessageBox.Show(currid);
// the following throws security error
Form1.webBrowser2.Navigate("http://www.mywebpage.com/client/index.php?id="+currid);
}
}
}
INFO: I have 2 WebBorwsers. I'm catching events from webBrowser1 for updating webBrowser2.
My problem is, that i cannot call the webbrowser2 methods outside from Form1.
Any Ideas how i can solve this problem?
Your WebBrowser components are not static (this is a good thing), therefore you cannot refer to them directly off of Form1 as your code sample is attempting to do. You must obtain a reference to a Form1 instance and then you can call methods on them so long as they are marked public. Depending on your needs it is probably even better to just pass along a reference directly to your WebBrowser components
Perhaps something like this:
orders.ObjectForScripting = new ScriptInterface(this.webBrowser2);
...
public class ScriptInterface
{
private WebBrowser _browser;
public ScriptInterface(WebBrowser browser)
{
_browser = browser;
}
public void callMe(string currid)
{
_browser.Navigate("http://www.mywebpage.com/client/index.php?id="+currid);
}
}
Form1 in:
Form1.webBrowser2.Navigate(...)
Is not an object, but it is your type. You need to create an instance of your class, or if you prefer, create an object to be able to call it's method:
Form1 form = new Form1();
form.webBrowser2.Navigate(...)
On top, your method are flagged private, which mean they can only be call from inside your instanced. You should flag them public if you want other object to be able to call them.
public void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { ... }
Or if you don't want to create an instance, you can declare this method as being static
public static void webBrowser2_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { ... }
But you won't be able to access the fields that this class define unless they are static too.

Creating a base Windows Forms form

I have done a base form for my window app but not sure is this correct or is there a better way to improve it.
My purpose:
Simplify my code at UI form
Create CRUD button to be inherited.
Question:
How do I implement interface with the 4 button events at the UserForm.cs by right clicking the UserForm:BaseForm. Currently I have to manually write all 4 button event to override.
My BaseForm seem to be empty. Can I put the messageBox.show("succcess") at my baseForm? Meaning to say that after run the UserForm.cs, it will run back to BaseForm. This can save up a few lines of code at userform.
Should I put my logger at the baseForm too?
My baseForm.cs
public BaseForm()
{
InitializeComponent();
}
public virtual void btnSave_Click(object sender, EventArgs e)
{
}
public virtual void btnDelete_Click(object sender, EventArgs e)
{
}
public virtual void btnNew_Click(object sender, EventArgs e)
{
}
public virtual void btnReset_Click(object sender, EventArgs e)
{
}
My UserForm.cs inherit baseForm
public override void btnSave_Click(object sender, EventArgs e)
{
if (!IsValidated()) return;
BindValueToObject();
try
{
user.Add();
bindingSource.Add(user);
MessageBox.Show("Success");
}
catch(Exception ex)
{
MessageBox.Show("failed");
Logger.Error(typeof(UserForm), ex.ToString());
return;
}
}
public override void btnDelete_Click(object sender, EventArgs e)
{
base.btnDelete_Click(sender, e);
}
public override void btnNew_Click(object sender, EventArgs e)
{
base.btnNew_Click(sender, e);
}
public override void btnReset_Click(object sender, EventArgs e)
{
base.btnReset_Click(sender, e);
}
1 - At the moment the methods in your base form is declared as virtual. This means that it is optional for any derived classes to override the methods. Therefore you won't be notified asking to override them. If this is your desired behavior then you will have to manually override the methods by either writing the code yourself or getting your IDE to generate the methods for you. However, if this is not the desired behavior and you would in fact like to force all derived classes to implement these methods, then you should declare them as abstract.
2 - Any calls to those methods will trigger the overridden methods in the derived class (if it exists) and thus the code in your base class will never get executed. If you're interested in both executing the code in the derived- and the base class then you should issue a call to the base method like this
public override void btnReset_Click(object sender, EventArgs e)
{
// do form specific stuff here
someButton.Text = String.Empty;
// then invoke base method
base.btnReset_Click(sender, e);
}
3 - If you're going to do general logging for the form, then putting it in the base class would be a good idea. However, remember always to invoke the base method call in any overridden method.

Invoking EventHandler generic, TargetParameterCountException

I have a DirectoryMonitor class which works on another thread.
It has the following events declared:
public class DirectoryMonitor
{
public event EventHandler<MonitorEventArgs> CreatedNewBook;
public event EventHandler ScanStarted;
....
}
public class MonitorEventArgs : EventArgs
{
public Book Book { get; set; }
}
There is a form using that monitor, and upon receiving the events, it should update the display.
Now, this works:
void DirectoryMonitor_ScanStarted(object sender, EventArgs e)
{
if (InvokeRequired)
{
Invoke(new EventHandler(this.DirectoryMonitor_ScanStarted));
}
else {...}
}
But this throws TargetParameterCountException:
void DirectoryMonitor_CreatedNewBook(object sender, MonitorEventArgs e)
{
if (InvokeRequired)
{
Invoke(new EventHandler<MonitorEventArgs>(this.DirectoryMonitor_CreatedNewBook));
}
else {...}
}
What am I missing?
The Invoke method excepts to receive a System.Delegate instance which can be invoked without passing any additional parameters. The delegate created by using DirectoryMonitor_ScanStarted requires 2 parameters and hence you get the exception when it's used.
You need to create a new delegate which wraps the call and arguments together.
MethodInvoker del = () => this.DirectoryMonitor_ScanStarted(sender,e);
Invoke(del);
You're missing the parameters:-
void DirectoryMonitor_ScanStarted(object sender, MonitorEventArgs e)
{
if (InvokeRequired)
{
Invoke(new EventHandler<MonitorEventArgs>(DirectoryMonitor_ScanStarted), sender, e);
}
else {...}
}
For reasons not clear to me (probably due to COM legacy) it's permissible to omit parameters when using a generic event, but not when using a user defined EventArg type.

How to subscribe to other class' events in C#?

A simple scenario: a custom class that raises an event. I wish to consume this event inside a form and react to it.
How do I do that?
Note that the form and custom class are separate classes.
public class EventThrower
{
public delegate void EventHandler(object sender, EventArgs args) ;
public event EventHandler ThrowEvent = delegate{};
public void SomethingHappened() => ThrowEvent(this, new EventArgs());
}
public class EventSubscriber
{
private EventThrower _Thrower;
public EventSubscriber()
{
_Thrower = new EventThrower();
// using lambda expression..could use method like other answers on here
_Thrower.ThrowEvent += (sender, args) => { DoSomething(); };
}
private void DoSomething()
{
// Handle event.....
}
}
Inside your form:
private void SubscribeToEvent(OtherClass theInstance) => theInstance.SomeEvent += this.MyEventHandler;
private void MyEventHandler(object sender, EventArgs args)
{
// Do something on the event
}
You just subscribe to the event on the other class the same way you would to an event in your form. The three important things to remember:
You need to make sure your method (event handler) has the appropriate declaration to match up with the delegate type of the event on the other class.
The event on the other class needs to be visible to you (ie: public or internal).
Subscribe on a valid instance of the class, not the class itself.
Assuming your event is handled by EventHandler, this code works:
protected void Page_Load(object sender, EventArgs e)
{
var myObj = new MyClass();
myObj.MyEvent += new EventHandler(this.HandleCustomEvent);
}
private void HandleCustomEvent(object sender, EventArgs e)
{
// handle the event
}
If your "custom event" requires some other signature to handle, you'll need to use that one instead.

Categories

Resources