I wants to access Form1's EventHandler In Form2
Form1 EventHandler is:-
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
How to achieve it?.
You are doing something wrong.
If you want to expose functionality, you should create a public method/function to do so. You can call this from your event handler and from your other form.
Answer updated by your question in comment, I didn't checked that it works fine may be there is a bug with it:
It's useful when you have a similar event, Also you can pass different EventArgs, easiest way is to have a different Property which determines each form and add event in their set methods but bellow is general
public abstract class FormBase : Form
{
public virtual event EventHandler MyEventHandler;
}
public class Form3 : FormBase
{
public override event EventHandler MyEventHandler;
Form2 instance;
public Form3()
{
instance = Form2.Instance;
instance[this.GetType().ToString()] = this;
// or
//instance["Form3"] = this;
}
private void dataGridView1_CellEndEdit(object sender, EventArgs e)
{
// todo
if (MyEventHandler != null)
MyEventHandler(this, e);
}
}
public class Form2
{
Dictionary<string, FormBase> dic = new Dictionary<string,FormBase>();
public FormBase this[string index]
{
get
{
FormBase retVal = null;
if (dic.TryGetValue(index, out retVal))
return retVal;
return null;
}
set
{
FormBase retVal = null;
if (value == null)
return;
if (dic.TryGetValue(index, out retVal))
{
try
{
value.MyEventHandler -= MyEventHandler1;
}
catch
{
}
retVal = value;
retVal.MyEventHandler += MyEventHandler1;
return;
}
value.MyEventHandler += MyEventHandler1;
dic.Add(index, value);
}
}
private static Form2 instance;
public static Form2 Instance
{
get
{
if (instance == null)
{
instance = new Form2();
}
return instance;
}
}
private Form2()
{
}
private void MyEventHandler1(object sender, EventArgs e)
{
}
}
Change the access modifier to public instead of private.
Another option is to parse the eventhandler on Form1 to Form2:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DataGridViewCellEventHandler dataGridViewCellEventHandler = new DataGridViewCellEventHandler(this.dataGridView1_CellEndEdit);
this.dataGridView1.CellEndEdit += dataGridViewCellEventHandler;
Form2 form2 = new Form2();
form2.CellEndEdit += dataGridViewCellEventHandler;
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
//Do something
}
}
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public event DataGridViewCellEventHandler CellEndEdit
{
add { dataGridViewOnForm2.CellEndEdit += value; }
remove { dataGridViewOnForm2.CellEndEdit -= value; }
}
}
This does however require that Form1 has access to Form2
Related
I have a problem with displaying UserControl on my Form.
The program in the nutshell:
In Form1 I have a button. After clicking this, in the Panel (container) my first UserControl (new.cs) are dynamically loaded.
On that panel I have another button that leads to another UserControl (choice.cs) and I want to display it in the same Panel (container) on my Form1.
The first point works good, but I have a problem with second one. I think I have to correct choice_button_Click function. Is there an easy way to do it?
Here is my code:
Form1.cs:
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void new_button_Click(object sender, EventArgs e)
{
if (!container.Controls.Contains(#new.Instance))
{
container.Controls.Add(#new.Instance);
#new.Instance.Dock = DockStyle.Fill;
#new.Instance.BringToFront();
}
else
{
#new.Instance.BringToFront();
}
}
public Panel getContainer()
{
return container;
}
}
}
new.cs:
namespace WindowsFormsApp1
{
public partial class #new : UserControl
{
private static #new _instance;
public static #new Instance
{
get
{
if (_instance == null)
_instance = new #new();
return _instance;
}
}
public #new()
{
InitializeComponent();
}
private void choice_button_Click(object sender, EventArgs e)
{
using (Form1 main = new Form1())
{
if (!main.getContainer().Controls.Contains(choice.Instance))
{
main.getContainer().Controls.Add(choice.Instance);
choice.Instance.Dock = DockStyle.Fill;
choice.Instance.BringToFront();
}
else
{
choice.Instance.BringToFront();
}
}
}
}
}
choice.cs:
namespace WindowsFormsApp1
{
public partial class choice : UserControl
{
private static choice _instance;
public static choice Instance
{
get
{
if (_instance == null)
_instance = new choice();
return _instance;
}
}
public choice()
{
InitializeComponent();
}
}
}
Your functional problem is that you aren't placing choice.Instance inside your instance of your Form1. You are creating a new form instead, placing it there, then discarding that form.
However, you also have an issue in your design, where you are violating the principal wherein a UserControl shouldn't be directly accessing and modifying its parent form. You would be better off adding an event to #new, raising that event from the button click, then handling that event in your form instance.
For example:
new.cs:
namespace WindowsFormsApp1
{
public partial class #new : UserControl
{
private static #new _instance;
public static #new Instance
{
get
{
if (_instance == null)
_instance = new #new();
return _instance;
}
}
public event EventHandler StepCompleted;
public #new()
{
InitializeComponent();
}
private void choice_button_Click(object sender, EventArgs e)
{
StepCompleted?.Invoke(this, EventArgs.Empty);
}
}
}
And Form1.cs:
namespace WindowsFormsApp1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void new_button_Click(object sender, EventArgs e)
{
if (!container.Controls.Contains(#new.Instance))
{
container.Controls.Add(#new.Instance);
#new.Instance.Dock = DockStyle.Fill;
#new.Instance.BringToFront();
}
else
{
#new.Instance.BringToFront();
}
}
private void new_StepCompleted(object sender, EventArgs e)
{
if (!container.Controls.Contains(choice.Instance))
{
container.Controls.Add(choice.Instance);
choice.Instance.Dock = DockStyle.Fill;
choice.Instance.BringToFront();
}
else
{
choice.Instance.BringToFront();
}
}
}
}
Now you're obviously going to be working on the same form instance, since it itself is the one handling the event. Also, #new doesn't need to do any awkward lookup to find the proper Form1 instance and modify the form.
Here is my problem : I have one delegate which I subscribe to from another class, that's alright. What I'd like is each time something subscribe to this delegate it raise an event that tells me the invocation list has changed and how +1 or -1...
I searched for an Onchange event in invocationlist but didn't find anything..
Form1:
namespace EventsOnDelegates
{
public delegate void DEL_delegate1(Double AValue);
public delegate void DEL_delegate2(Boolean AsecondValue);
public partial class Form1 : Form
{
public DEL_delegate1 SetValueCbk;
public EventHandler InvocationListChange;
private Form2 FormwithLabel;
int invoclength;
public Form1()
{
InitializeComponent();
FormwithLabel = new Form2(this);
FormwithLabel.Show();
/*the question part*/
/*I'd like to add an onchange event that tells me if the invocation list has changed and how + or -*/
InvocationListChange += new EventHandler(SetValueCbk.GetInvocationList(),InvocationListHaschanged);
}
protected virtual void InvocationListHaschanged(object sender, EventArgs e)
{
invoclength = SetValueCbk.GetInvocationList().Length;
label1.Text = Convert.ToString(invoclength);
}
private void button1_Click(object sender, EventArgs e)
{
Random newRandNum = new Random();
Double newNumber = newRandNum.NextDouble();
SetValueCbk(newNumber);
}
}
}
Form2:
public partial class Form2 : Form
{
public Form2(){}
public Form2(Form1 Form1link)
:this()
{
InitializeComponent();
Form1link.SetValueCbk += new DEL_delegate1(this.SetValueCbkFN);
}
protected void SetValueCbkFN(Double value)
{
label1.Text = Convert.ToString(value);
}
}
Thanks for help!!
You can use explicit event declaration for that event field :
private EventHandler meEvent;
public event EventHandler MeEvent
{
add { meEvent += value; MeEventInvocationListChanged(); }
remove { meEvent -= value; MeEventInvocationListChanged(); }
}
EDIT : ( Fitting this into your question )
instead of your InvocationListHasChanged method you can create :
void InvokationListChanged(int dir)
{
string msg = dir < 0 ? "Someone unsubscribed from the event" : "Someone subscribed to the event";
if(InvokeRequired)
{
Invoke( new MethodInvoker( () => { label1.Text = msg; });
}
else
{
label1.Text = msg;
}
}
And then change public DEL_delegate1 SetValueCbk; to :
private DEL_delegate1 m_SetValueCbk;
public event Del_delegate1 SetValueCbk
{
add { m_SetValueCbk+= value; InvokationListChanged(1); }
remove { m_SetValueCbk-= value; InvokationListChanged(-1); }
}
Now whenever some other object subscribe to SetValueCbk your label1.Text will change to "Someone subscribed to the event" and whenever some object unsubscribe from SetValueCbk your label1.Text will change to "Someone unsubscribed from the event"
I have Multiple class that need to subscribe to a delegate.
How is that possible? If I do declare delegate in my mainForm is that well coded?
Example code:
internal delegate void DEL_SetSingleVal(Single value);
public partial class Form1 : Form
{
Single Data;
ClasswithDel ClassDelegate;
TryToAccess AccessDelegate;
public Form1()
{
InitializeComponent();
ClassDelegate = new ClasswithDel();
AccessDelegate = new TryToAccess();
ClassDelegate.SetValCbk += new DEL_SetSingleVal(SetValCbkFn);
ClassDelegate.SetValCbk += new DEL_SetSingleVal(AccessDelegate.SetValCbkObj2Fn);
}
internal void SetValCbkFn(Single value)
{
Data = value;
}
private void SetValueLabel(String value)
{
label1.Text = value;
}
private void button1_Click(object sender, EventArgs e)
{
ClassDelegate.SetValue(Convert.ToSingle(textBox1.Text));
}
}
public class TryToAccess
{
private Single Data2;
internal void SetValCbkObj2Fn(Single value)
{
Data2 = value;//value come from From1
}
}
public class ClasswithDel
{
internal DEL_SetSingleVal SetValCbk;
public void SetValue(Single valuesent)//value to dispatch to Form1 and TryToAccess
{
SetValCbk(valuesent);
}
}
Is this looking good? Thanks for help!
I have a usercontrol which have timer
public partial class Cumle : UserControl
{
private bool cond=false;
//Some Code....
private void timer2_Tick(object sender, EventArgs e)
{
//Some Code....
if(//some condition...)
cond=true;
}
}
I am working on windows form.I want to display a message box which shows me that cond is true.I want to make this stuff without using timer on Form.
public partial class Form1 : Form
{
//What I must write here?
}
As mentioned, you should use Events. I would go like this:
public partial class Cumle : UserControl
{
public event EventHandler ConditionChangedToTrue;
protected virtual void OnConditionChangedToTrue(EventArgs e)
{
if (ConditionChangedToTrue != null)
ConditionChangedToTrue(this, e != null ? e : EventArgs.Empty);
}
private void timer2_Tick(object sender, EventArgs e)
{
//Some Code....
if (true) // add your condition
{
cond = true;
OnConditionChangedToTrue(null);
}
}
}
public partial class Form1 : Form
{
private Cumle cumle = new Cumle();
public Form1()
{
InitializeComponent();
cumle.ConditionChangedToTrue+= Cumle_ConditionChangedToTrue;
}
private void Cumle_ConditionChangedToTrue(object sender, EventArgs e)
{
// add your event handling code here
throw new NotImplementedException();
}
}
You need to add a public event to your UserControl, and subscribe to it from your main form.
Something like this should do it:
public partial class Cumle : UserControl
{
public event Action<bool> ConditionChanged = delegate {};
private bool cond=false;
//Some Code....
private void timer2_Tick(object sender, EventArgs e)
{
//Some Code....
if(//some condition...)
{
cond=true;
ConditionChanged(cond);
}
}
}
Then in your form:
public partial class Form1 : Form
{
void SubscribeToConditionChanged()
{
myUserControl.ConditionChanged += ShowDlg;
}
void ShowDlg(bool condition)
{
MessageBox.Show("....");
}
}
Would you look at my code and tell me where I went wrong? in following code I am trying to send a notification to myMethod() method when Form1 gets maximized.
Thanks!
namespace WindowsDelegate1
{
public delegate void ChangedEventHandler(object sender, EventArgs e);
class myForm : Form
{
public event ChangedEventHandler Changed;
protected virtual void OnChanged(EventArgs e)
{
if (Changed != null)
Changed(this,e);
}
public override System.Drawing.Size MaximumSize
{
//get
//{
// return base.MaximumSize;
//}
set
{
base.MaximumSize = value;
OnChanged(EventArgs.Empty);
}
}
}
}
namespace WindowsDelegate1
{
class EventListener
{
private myForm TheForm;
public EventListener(myForm theform)
{
TheForm = theform;
TheForm.Changed += new ChangedEventHandler(myMethod);
}
private void myMethod(object sender, EventArgs e)
{
MessageBox.Show("hey, window should be maximized now!");
}
public void Detach()
{
TheForm.Changed -= new ChangedEventHandler(myMethod);
TheForm = null;
}
}
}
Here is the testing unit / or main()
namespace WindowsDelegate1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
myForm f = new myForm();
EventListener listener = new EventListener(f);
f.ShowDialog();
f.WindowState = FormWindowState.Maximized;
listener.Detach();
}
}
}
What's probably happening is the event is either fired after your .Detach() call, or is never fired at all. I would start by removing the listener.Detach() call. Generally, you attach to events when the form is created or when it loads and detach when it is unloading.
Other than that, your Detach method is problematic because it tries to remove a different ChangedEventHandler instance than the one added. If you're wrapping your methods in ChangedEventHandler you need to store the instance you added.
Thank you for sharing your ideas!
I fixed it by removing the property (not idea why I used that!!) and using method instead by:
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
OnChanged(EventArgs.Empty);
}
I have updated my source code above too