EventHandler listener - c#

I'm in a position where I have two classes, one has an event handler for a button and I need to be able to listen to that event handler in the other class in order to make changes in the non-button class. I don't have much experience with this type of scenario so am not quite sure where to start.

Here is an exampple of this two classes (if I understood the question right).
class Form
{
Button _button1, _button2;
public Form()
{
_button1 = new Button("button1");
_button2 = new Button("button2");
_button1.Click += _button_Click;
_button2.Click += _button_Click;
}
void _button_Click(object sender, EventArgs e)
{
Button button = (Button)sender;
Console.WriteLine(button.Name);
}
public void Click1()
{
_button1.FireEvent();
}
public void Click2()
{
_button2.FireEvent();
}
}
class Button
{
public event EventHandler Click;
public string Name;
public Button(string name)
{
Name = name;
}
public void FireEvent()
{
Click(this, new EventArgs());
}
}
Usage:
Form f = new Form();
f.Click1();
f.Click2();

Related

C# How to have a form subscribe to an event which is within a user control within a floy layour panel?

So I have a form on a WinForms app.
On that form is a FlowLayoutPanel.
On the FlowLayout panel is a bunch of user controls each representing rows from a table from a database.
On each control is a button.
How do I have the form subscribe to a button click on one of the controls passing back that rows database info?
This is the control code:
public partial class ctrlLeague : UserControl
{
public League activeLeague = new League();
public event EventHandler<MyEventArgs> ViewLeagueClicked;
public ctrlLeague(League lg)
{
InitializeComponent();
lblLeagueName.Text = lg.leagueName;
activeLeague = lg;
}
private void btnViewLeague_Click(object sender, EventArgs e)
{
ViewLeagueClicked(this, new MyEventArgs(activeLeague));
}
public class MyEventArgs : EventArgs
{
public MyEventArgs(League activeLeague)
{
ActiveLeague = activeLeague;
}
public League ActiveLeague { get; }
}
}
if I put the following into the form constructor it tells me "
You can define your favorite event with delegate and call it wherever you want, here it is called inside btnView_Click.
This means that whenever btnView_Click called, your event is
actually called.
public partial class ctrlLeague : UserControl
{
public League activeLeague = new League();
public event EventViewLeagueClicked ViewLeagueClicked;
public delegate void EventViewLeagueClicked(object Sender);
public ctrlLeague(League lg)
{
InitializeComponent();
lblLeagueName.Text = lg.leagueName;
activeLeague = lg;
}
private void btnViewLeague_Click(object sender, EventArgs e)
{
if (ViewLeagueClicked != null)
ViewLeagueClicked(activeLeague);
}
}
now use
public Form1()
{
InitializeComponent();
League league = new League();
league.leagueName = "Seri A";
//
//These lines are best added in Form1.Designer.cs
//
ctrlLeague control = new ctrlLeague(league);
control.Location = new System.Drawing.Point(350, 50);
control.Name = "ctrlLeague";
control.Size = new System.Drawing.Size(150, 100);
control.ViewLeagueClicked += Control_ViewLeagueClicked;
this.Controls.Add(control);
}
private void Control_ViewLeagueClicked(object Sender)
{
League l = Sender as League;
MessageBox.Show(l.leagueName);
}

Prevent function from being invoked from within itself [duplicate]

My application in C# has a Textbox with a txt_TextChanged event.
private void txt_TextChanged(object sender, EventArgs e)
{
//Do somthin
}
But there's one specific part that I want to change txt.Text without firing the txt_TextChanged event.
txt.Text ="somthing" //Don't fire txt_TextChanged
How can I do that?
There is no direct way to prevent the raising of events for the text property, however your event handler can use a flag to determine weather or not to perform a task. This i likely to be more efficient than attaching and detaching the event handler. This can be done by a variable within the page or even a specialized class wrapper
With a variable:
skipTextChange = true;
txt.Text = "Something";
protected void TextChangedHandler(object sender, EventArgs e) {
if(skipTextChange){ return; }
/// do some stuffl
}
With specialized event handler wrapper
var eventProxy = new ConditionalEventHandler<EventArgs>(TextBox1_TextChanged);
TextBox1.TextChanged = eventProxy.EventAction;
eventProxy.RaiseEvents = false;
TextBox1.Text = "test";
public void TextBox1_TextChanged(object sender, EventArgs e) {
// some cool stuff;
}
internal class ConditionalEventHadler<TEventArgs> where TEventArgs : EventArgs
{
private Action<object,TEventArgs> handler;
public bool RaiseEvents {get; set;}
public ConditionalEventHadler(Action<object, TEventArgs> handler)
{
this.handler = handler;
}
public void EventHanlder(object sender, TEventArgs e) {
if(!RaiseEvents) { return;}
this.handler(sender, e);
}
}
txt.TextChanged -= textBox1_TextChanged; // dettach the event handler
txt.Text = "something"; // update value
txt.TextChanged += textBox1_TextChanged; // reattach the event handler
You can extend text box and introduce there a new property that will not trigger the TextChanged event.
class SilentTextBox : TextBox
{
// if true, than the TextChanged event should not be thrown
private bool Silent { get; set; }
public string SilentText
{
set
{
try
{
Silent = true;
Text = value;
}
finally
{
Silent = false;
}
}
}
protected override void OnTextChanged(EventArgs e)
{
// raise event only if the control is in non-silent state
if (!Silent)
{
base.OnTextChanged(e);
}
}
}
try this extension method
public static class TextBoxExt
{
private static readonly FieldInfo _field;
private static readonly PropertyInfo _prop;
static TextBoxExt()
{
Type type = typeof(Control);
_field = type.GetField("text", BindingFlags.Instance | BindingFlags.NonPublic);
_prop = type.GetProperty("WindowText", BindingFlags.Instance | BindingFlags.NonPublic);
}
public static void SetText(this TextBox box, string text)
{
_field.SetValue(box, text);
_prop.SetValue(box, text, null);
}
}
you can use textbox.SetText("...") to change text and the TextChanged event will not be fired.
A quick and dirty way is to do an
ctrl.Enable = false;
ctrl.Text = "Something";
ctrl.Enable = true;
and then in the OnChange event, encapsulate the offending code with a
if (ctrl.Enabled) {
// offending code here.
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
EventHandler TextChanged_EventHandler = new EventHandler(textBox1_TextChanged);
textBox1.TextChanged -= TextChanged_EventHandler;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("BUG");
}
}
I found a simple method, suitable for event handlers and controls that are not in the same .cs file
public static void SetTextWithoutRaiseEvent(this TextBox textBox, string content)
{
var scroll = textBox.Template.FindName("PART_ContentHost", textBox);
(scroll as ScrollViewer).Content = content;
}

assigning delegate subscribe event to a List

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"

Delegate with generic list signature for passing data to another form

I'm quite new in C#, so I'm struggling with this more than two days. I hope that some one can help me out with this one.
Below some simplified code from my application.
I want to pass a List from Form1 to Form2 using delegate and event.
How can I do this? I read tons of explanations about events and delegates, but I still can't figure it out, how this really works.
Form1:
public delegate List<string> ProfileImportEventHandler();
public event ProfileImportEventHandler ProfileImported;
private void btnImport_Click(object sender, EventArgs e)
{
// raise an event
OnProfileImported();
}
protected virtual void OnProfileImported()
{
if (ProfileImported != null) // check if there are subscribers
{
ProfileImported();
}
}
Form2:
public partial class Form2 : Form
{
Form1 frm1;
public Form1()
{
// Constructor logic
frm1.ProfileChanged += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
}
}
List<string> Form1_OnProfileImported()
{
// TO DO
}
UPDATE
None of the solutions worked so far. Here is what I have already tried:
Form 2
// use generic list for profiles that will be imported from USB-Stick
private List<string> profilePaths = new List<string>();
public delegate void ProfileImportEventHandler(object sender, ProfileImportEventArgs e);
public event ProfileImportEventHandler ProfileImported;
public delegate void ImportButtonClickedEventHandler();
public event ImportButtonClickedEventHandler ButtonImportClicked;
public delegate void HaveDataDelegate(IList<string> data);
public event HaveDataDelegate HaveData;
//....
private void btnImport_Click(object sender, EventArgs e)
{
// do something...
// raise an event
var ea = new ProfileImportEventArgs(profilePaths);
OnProfileImported(ea);
OnButtonImportClicked();
// When there is data:
var copy = HaveData; // Use copy to avoid race conditions
if (copy != null)
{
copy(profilePaths);
}
// close form
this.Dispose();
}
protected virtual void OnProfileImported(ProfileImportEventArgs ea)
{
if (ProfileImported != null) // check if there are any subscribers
{
ProfileImported(this, ea);
}
}
protected virtual void OnButtonImportClicked()
{
if (ButtonImportClicked != null)
{
// fire event
ButtonImportClicked();
}
}
Form 1
public partial class frm_1 : Form
{
// child form
frm_2 frm2;
public frm_1()
{
InitializeComponent();
// do something...
// not sure if this is correct code and the correct place for it
frm2 = new frm_2();
frm2.ProfileImported += new frm_2.ProfileImportEventHandler(frm2_OnProfileImported);
//frm2.ProfileImported += frm2_OnProfileImported;
frm2.ButtonImportClicked += new frm_2.ImportButtonClickedEventHandler(frm2_ButtonImportClicked);
// In creation/init:
frm2.HaveData += DataFromForm2;
}
void frm2_OnProfileImported(object sender, ProfileImportEventArgs e)
{
// do something
}
void frm2_ButtonImportClicked()
{
// do something
}
private void DataFromForm2(IList<string> data)
{
// Process the data from Form2.
}
}
What am I still missing? Thank you for your help.
frm1.ProfileChanged += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
[…]
List<string> frmLoadProfileUSB_OnProfileImported()
First those names do not match. Second, with matching signatures you do not need (since C#2 if I recall correctly) to explicitly create the delegate. Thus:
frm1.ProfileChanged += frmLoadProfileUSB_OnProfileImported;
However, I think you have the event in the wrong place. It appears it is Form2 trying to pass data to Form1. Thus the event needs to be on Form2, with a delegate that is passed the data. Thus:
In Form2
public delegate void HaveDataDelegate(IList<string> data);
public event HaveDataDelegate HaveData;
// When there is data:
var copy = HaveData; // Use copy to avoid race conditions
if (copy != null) {
copy(data);
}
In Form1
// In creation/init:
Form2Instance.HaveData += DataFromForm2;
private void DataFromForm2(IList<string> data) {
// Process the data from Form2.
}
It's better not to use strong coupling.
So best solution here would be to store data in database or create proxy-object (class/struct).
like:
public (static) class ProfileChangesMonitor
{
...your logic here
}
If you want to use event handlers, you should follow the general pattern, defining a class that inherits EventArgs (supposing you want to involve a list in the event) in this way:
// Event Args
public class ProfileImportEventArgs : EventArgs {
private IList<string> list;
public ProfileImportEventArgs(IList<string> list) {
this.list = list;
}
public IList<string> List {
get {
return this.list;
}
}
}
// Event Handler Delegate
public delegate void ProfileImportEventHandler(object sender, ProfileImportEventArgs e);
// Form1:
public event ProfileImportEventHandler ProfileImported;
// ...
private void btnImport_Click(object sender, EventArgs e)
{
// raise an event
List<string> list = new List();
// Add something to list if needed
var ea = new ProfileImportEventArgs(list);
OnProfileImported(ea);
// Use ea.list here if necessary
}
protected virtual void OnProfileImported(ProfileImportEventArgs ea)
{
if (ProfileImported != null) { // check if there are subscribers
ProfileImported(this, ea);
}
}
// Form2:
public partial class Form2 : Form
{
Form1 frm1;
public Form1()
{
// Constructor logic
// TODO: Instantiate frm1 first.
frm1.ProfileImported += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
}
}
private void frmLoadProfileUSB_OnProfileImported(object sender, ProfileImportEventArgs e)
{
// Use and/or modify e.List if needed
}

C# - How to Transfer Information Between User Control

im doing an application where user enter a value inside the text box then he press a button, both in the same user control. Then the result from the text box will show at the label of other user control. Both of the user control is in the same windows form.
Thanks!
Image of user interface
The most common way to do this is use an event. This is how I would do it:
First define an EventArgs:
public class MyEventArgs : EventArgs
{
public string Text { get; private set; }
public MyEventArgs(string Text)
{
this.Text = Text;
}
}
Then in your UserControl (the one with the button):
public partial class MyUserControl
{
public event EventHandler<MyEventArgs> ButtonClicked;
public MyUserControl()
{
//...
button1.Click += (o, e) => OnButtonClicked(new MyEventArgs(textBox1.Text));
}
protected virtual void OnButtonClicked(MyEventArgs args)
{
var hand = ButtonClicked;
if(hand != null) ButtonClicked(this, args);
}
}
Then subscribe to your MyUserControl.ButtonClicked event in the form and call a method in the second control.
Note if the behavior of the button and the text in the textbox are actually not related, you can use a property to get the text entered and an empty EventArgs for your event instead.
P.S. The names MyEventArgs, MyUserControl, and ButtonClicked are just for demonstration purposes. I encourage you to use more descriptive/relevant naming in your code.
try this:
public class FirstUserControl:UserControl
{
Public event EventHandler MyEvent;
//Public property in your first usercontrol
public string MyText
{
get{return this.textbox1.Text;} //textbox1 is the name of your textbox
}
private void MyButton_Clicked(/* args */)
{
if (MyEvent!=null)
{
MyEvent(null, null);
}
}
//other codes
}
public class SecondUserControl:UserControl
{
//Public property in your first usercontrol
public string MyText
{
set{this.label1.Text = value;} //label1 is the name of your label
}
//other codes
}
then in your MainForm:
public class MainForm:Forms
{
//Add two instance of the UserControls
public MainForm()
{
this.firstUserControl.MyEvent += MainWindow_myevent;
}
void MainWindow_myevent(object sender, EventArgs e)
{
this.secondUserControl.MyText = this.firstUserControl.MyText;
}
//other codes
}

Categories

Resources