Delegates and events? - c#

This question is related to c#.The scenario is that when i click the button the operations like File reading,Data manipulation ,and file dumping are going to be happened.After the completion of each operation i will update the status(i.e,File reading completed,data manipulation completed) in the label which is in UI(FORM-frmTesting)
The button click event is
namespace frmTesting
{
public partial class Form1 : Form
{
private void button1_Click_1(object sender, EventArgs e)
{
class1 l_objClass1 = new class1();
l_objClass1.DoOperation();
}
}
public class class1
{
public int DoOperation()
{
ReadTextFile();
ParsingData();
SaveTextFile();
return 0;
}
private int ReadTextFile()
{
//Read the text File
return 0;
}
private int ParsingData()
{
// Data manipulation
return 0;
}
private int SaveTextFile()
{
// save the file
return 0;
}
}
}
Is it possible by using Delegates and Events....if you have any queries plz revert back me

You'll have to modify class1 to broadcast events that other classes can listen to:
public class class1
{
// Not necessary, but will allow you to add custom EventArgs later
public delegate void StatusChangedEventHandler(object sender, EventArgs e);
public event StatusChangedEventHandler FileRead;
public event StatusChangedEventHandler FileParsed;
public event StatusChangedEventHandler FileSaved;
public int DoOperation()
{
ReadTextFile();
ParsingData();
SaveTextFile();
return 0;
}
private int ReadTextFile()
{
//Read the text File
OnFileRead(EventArgs.Empty);
return 0;
}
private int ParsingData()
{
// Data manipulation
OnFileParsed(EventArgs.Empty);
return 0;
}
private int SaveTextFile()
{
// save the file
OnFileSaved(EventArgs.Empty);
return 0;
}
protected virtual void OnFileRead(EventArgs e)
{
if(FileRead != null)
FileRead(this, e);
}
protected virtual void OnFileParsed(EventArgs e)
{
if(FileParsed != null)
FileParsed(this, e);
}
protected virtual void OnFileSaved(EventArgs e)
{
if(FileSaved != null)
FileSaved(this, e);
}
}
And then have your form listen for those events and change its label appropriately:
public partial class Form1 : Form
{
private void button1_Click_1(object sender, EventArgs e)
{
class1 l_objClass1 = new class1();
l_objClass1.FileRead +=
delegate { lblStatus.Text = "File Read..."; };
l_objClass1.FileParsed +=
delegate { lblStatus.Text = "File Parsed..."; };
l_objClass1.FileSaved +=
delegate { lblStatus.Text = "File Saved..."; };
l_objClass1.DoOperation();
}
}

The short answer is yes. You add events to class1 and add handlers to Form1 with the appropriate logic. Below is a sample of how to do this
public partial class Form1 : Form
{
private void button1_Click_1(object sender, EventArgs e)
{
class1 obj = new class1();
obj.FileReadingComplete += HandleFileReadingComplete;
obj.DataManipulationComplete += HandleDataManipulationComplete;
obj.DoOperation();
obj.FileReadingComplete -= HandleFileReadingComplete;
obj.DataManipulationComplete -= HandleDataManipulationComplete;
}
private void HandleFileReadingComplete(object sender, EventArgs args){
//code here
}
private void HandleDataManipulationComplete(object sender, EventArgs args)
{
//code here
}
}
public class class1
{
public event EventHandler FileReadingComplete;
public event EventHandler DataManipulationComplete;
public int DoOperation()
{
ReadTextFile();
OnFileReadingComplete();
ParsingData();
OnDataManipulationComplete();
SaveTextFile();
return 0;
}
private int ReadTextFile()
{
//Read the text File
return 0;
}
private int ParsingData()
{
// Data manipulation
return 0;
}
private int SaveTextFile()
{
// save the file
return 0;
}
public void OnFileReadingComplete()
{
EventHandler handler = FileReadingComplete;
if (handler != null) {
handler(this, EventArgs.Empty);
}
}
public void OnDataManipulationComplete()
{
EventHandler handler = DataManipulationComplete;
if (handler != null) {
handler(this, EventArgs.Empty);
}
}
}

Related

Updating a pictureBox.Image from another class

Update: I am pretty sure i found out the reason why, i will update this question with my findings as soon as i got it for sure. It is related to having 2 usercontrol's placed above each other and i draw on the one behind thats why i don't see the changes! I had to check the hashcode of the timer to figure out that 2 timers are involved.
I am developing a winforms application and i have applied the MVP-pattern to separate the responsibilities and stuff... (applied the passive-view approach, and also fire events to require the corresponding presenter to perform an action).
I have also checked other questions here and many other relevant topics, but nothing helped...
Problem description: I added a UserControl (SubView) into a SplitContainer's panel which is placed inside a Form (MainView). This SubView has its own presenter (SubPresenter) that requires it to switch its background (SwitchBackground(), picturebox) whenever that is triggered by the user from the MainView.
Problem: The SwitchBackground() method gets executed (i debugged that) when that is triggered from the MainView (actually from the MainPresenter), but the changes are not displayed on the SubView. I have also examined (or at least tried to do that correctly :) ) if the method requires switching the context into the GUI thread or something by checking the InvokeRequired.
I would be glad to have any recommendations regarding this issue, because i am stuck there and can't go further with programming...
Here is an example application i wrote to illustrate the problem (for the complete example project, i uploaded it on github: link):
SubView:
public interface ISubView
{
void StartSwitchingBackground();
void StopSwitchingBackground();
}
public partial class SubView : UserControl, ISubView
{
private Bitmap plot;
private Brush brush1;
private Brush brush2;
private int drawCount;
private Timer timer;
public SubView()
{
InitializeComponent();
brush1 = new SolidBrush(Color.Yellow);
brush2 = new SolidBrush(Color.Blue);
timer = new Timer();
timer.Tick += OnTick;
}
private void OnTick(object sender, EventArgs e)
{
SwitchBackground();
}
private void SwitchBackground()
{
if (InvokeRequired)
Console.WriteLine("InvokeRequired"); // never happens, so i assume it is not considered a call from another thread...
if (plot == null || plot.Size != pictureBox.Size)
plot = new Bitmap((int)(pictureBox.Width*0.8), (int)(pictureBox.Height*0.8));
using (Graphics g = Graphics.FromImage(plot))
{
int x = plot.Width / 2;
int y = plot.Height / 2;
int w = plot.Width / 4;
int h = plot.Height / 4;
if (drawCount % 2 == 0)
{
g.Clear(Color.White);
g.FillRectangle(brush1, (x - w) / 2, (y - h) / 2, w, h);
}
else
{
g.Clear(Color.Black);
g.FillRectangle(brush2, (x - w) / 2, (y - h) / 2, w, h);
}
drawCount++;
}
pictureBox.Image = plot;
}
public void StartSwitchingBackground()
{
if (!timer.Enabled)
timer.Start();
Console.WriteLine("started");
}
public void StopSwitchingBackground()
{
if (timer.Enabled) timer.Stop();
Console.WriteLine("stopped");
}
private void btnStartSwitching_Click(object sender, EventArgs e)
{
StartSwitchingBackground();
}
private void btnStopSwitching_Click(object sender, EventArgs e)
{
StopSwitchingBackground();
}
}
SubPresenter:
public class SubPresenter
{
private ISubView view;
public SubPresenter(ISubView view)
{
this.view = view;
}
public void SwitchBackground()
{
view.StartSwitchingBackground();
}
public void StopSwitching()
{
view.StopSwitchingBackground();
}
}
MainView:
public interface IMainView
{
ISubView SubView { get; }
event EventHandler SwitchEventTriggered;
event EventHandler StopSwitchEventTriggered;
}
public partial class MainView : Form, IMainView
{
private SubView subView;
public MainView()
{
InitializeComponent();
subView = new SubView();
splitContainer1.Panel2.Controls.Add(subView);
subView.Dock = DockStyle.Fill;
subView.Anchor = AnchorStyles.Top & AnchorStyles.Left;
splitContainer1.Resize += splitContainer1_Resize;
}
void splitContainer1_Resize(object sender, EventArgs e)
{
subView.Size = splitContainer1.Panel2.Size;
}
private void btnStart_Click(object sender, EventArgs e)
{
StartSwitching();
}
private void StartSwitching()
{
OnStartSwitchingTriggered();
}
private void OnStartSwitchingTriggered()
{
var handler = SwitchEventTriggered;
if (handler == null) return;
handler(this, EventArgs.Empty);
}
private void btnStop_Click(object sender, EventArgs e)
{
StopSwitching();
}
private void StopSwitching()
{
OnStopSwitching();
}
private void OnStopSwitching()
{
var handler = StopSwitchEventTriggered;
if (handler == null) return;
handler(this, EventArgs.Empty);
}
public ISubView SubView { get { return this.subView; } }
public event EventHandler SwitchEventTriggered;
public event EventHandler StopSwitchEventTriggered;
}
MainPresenter:
public class MainPresenter
{
private readonly IMainView mainView;
private readonly SubPresenter subPresenter;
public MainPresenter(IMainView view)
{
this.mainView = view;
this.subPresenter = new SubPresenter(mainView.SubView);
mainView.SwitchEventTriggered += OnSwitchEventTriggerd;
mainView.StopSwitchEventTriggered += OnStopSwitchEventTriggered;
}
private void OnStopSwitchEventTriggered(object sender, EventArgs e)
{
subPresenter.StopSwitching();
}
private void OnSwitchEventTriggerd(object sender, EventArgs e)
{
subPresenter.SwitchBackground();
}
}
Entry Point:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
MainView mainView = new MainView();
MainPresenter mainPresenter = new MainPresenter(mainView);
Application.Run(mainView);
}
}
You have two instances of SubView in MainView.
Use only subView1, you can delete all occurrences of subView;
The minimum fix is to replace:
public ISubView SubView { get { return this.subView; } }
with:
public ISubView SubView { get { return this.subView1; } }

Can I prevent ListBox.RefreshItem(object item) from removing and re-adding the object?

The issue I am having is that when I update my object, the ListBox automatically removes and then re-adds the object to the list, thus calling the index and value changed events. I was able to prevent this by creating a custom ListBox control and when the PropertyChangedEvent was called, I would raise a flag that would prevent those events in the base class from being called. What is happening now is that my entire reference is being replace by a new reference and unless I re-select the item in the ListBox, I have the wrong reference.
What I basically want to do, is to change the Display Value in my object and then have it update only the text in the list box. I do not want it to remove and to re-add the object/reference/whatever it does. It's quite annoying.
Here is the example code I am working with...
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.myListBox1.SelectedValueChanged += this.onchange;
}
private void Form1_Load(object sender, EventArgs e)
{
this.myListBox1.Add(new strobj("z"));
this.myListBox1.Add(new strobj("a"));
this.myListBox1.Add(new strobj("b"));
this.myListBox1.Add(new strobj("f"));
this.myListBox1.Add(new strobj("n"));
this.myListBox1.Add(new strobj("h"));
this.myListBox1.Add(new strobj("p"));
this.myListBox1.Add(new strobj("t"));
this.myListBox1.Add(new strobj("c"));
this.myListBox1.Add(new strobj("q"));
}
private void onchange(object sender, EventArgs e)
{
MessageBox.Show("Hello World");
}
int i = 0;
private void button1_Click(object sender, EventArgs e)
{
if (this.myListBox1.SelectedItem != null)
{
strobj item = (strobj)this.myListBox1.SelectedItem;
item.Name1 = i++.ToString();
}
}
}
public partial class MyListBox
{
public MyListBox()
{
InitializeComponent();
}
public void Add(strobj item)
{
item.OnNameChanged += this.MyDispalyMemberChanged;
this.Items.Add(item);
}
bool refreshing = false;
public void MyDispalyMemberChanged(strobj itemChanged)
{
this.refreshing = true;
this.RefreshItem(this.Items.IndexOf(itemChanged));
this.refreshing = false;
}
protected override void OnSelectedValueChanged(EventArgs e)
{
if (!this.refreshing)
{
base.OnSelectedValueChanged(e);
}
}
}
class strobjCollection : List<strobj>
{
NameChangeEventHandler NameChangedEvent;
}
delegate void NameChangeEventHandler(strobj sender);
public class strobj
{
internal NameChangeEventHandler OnNameChanged;
private string _Name1;
public string Name1
{
get { return this._Name1; }
set
{
this._Name1 = value;
if (this.OnNameChanged != null)
{
this.OnNameChanged(this);
}
}
}
public int i = 0;
public string str = "p";
public strobj(string name)
{
this._Name1 = name;
}
public strobj()
{
this._Name1 = "You did not create this object";
}
public override string ToString()
{
return this._Name1;
}
}
This is what the INotifyPropertyChanged interface was made for.
Instead of raising your custom event, you'd raise the PropertyChanged event with the name of the property you changed set in the event args and the listbox would update.
See MSDN.

C#: String as parameter to event?

I have a GUI-thread for my form and another thread that computes things.
The form has a richtTextBox. I want the worker-thread to pass strings to the form, so that every string is displayed in the textbox.
Everytime a new string is generated in the worker thread I call an event, and this should now display the string.
But I don't know how to pass the string! This is what I tried so far:
///// Form1
private void btn_myClass_Click(object sender, EventArgs e)
{
myClass myObj = new myClass();
myObj.NewListEntry += myObj_NewListEntry;
Thread thrmyClass = new Thread(new ThreadStart(myObj.ThreadMethod));
thrmyClass.Start();
}
private void myObj_NewListEntry(Object objSender, EventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
// Here I want to add my string from the worker-thread to the textbox!
richTextBox1.Text += "TEXT"; // I want: richTextBox1.Text += myStringFromWorkerThread;
});
}
///// myClass (working thread...)
class myClass
{
public event EventHandler NewListEntry;
public void ThreadMethod()
{
DoSomething();
}
protected virtual void OnNewListEntry(EventArgs e)
{
EventHandler newListEntry = NewListEntry;
if (newListEntry != null)
{
newListEntry(this, e);
}
}
private void DoSomething()
{
///// Do some things and generate strings, such as "test"...
string test = "test";
// Here I want to pass the "test"-string! But how to do that??
OnNewListEntry(EventArgs.Empty); // I want: OnNewListEntry(test);
}
}
Like this
public class NewListEntryEventArgs : EventArgs
{
private readonly string test;
public NewListEntryEventArgs(string test)
{
this.test = test;
}
public string Test
{
get { return this.test; }
}
}
then you declare your class like this
class MyClass
{
public delegate void NewListEntryEventHandler(
object sender,
NewListEntryEventArgs args);
public event NewListEntryEventHandler NewListEntry;
protected virtual void OnNewListEntry(string test)
{
if (NewListEntry != null)
{
NewListEntry(this, new NewListEntryEventArgs(test));
}
}
}
and in the subscribing Form
private void btn_myClass_Click(object sender, EventArgs e)
{
MyClass myClass = new MyClass();
myClass.NewListEntry += NewListEntryEventHandler;
...
}
private void NewListEntryEventHandler(
object sender,
NewListEntryEventArgs e)
{
if (richTextBox1.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
this.NewListEntryEventHandler(sender, e);
});
return;
}
richTextBox1.Text += e.Test;
}
I've taken the liberty of making the NewListEntryEventArgs class immutable, since that makes sense. I've also partially corrected your naming conventions, simplified and corrected where expedient.
You need to create a new class by inheriting off EventArgs.
Create your own version of the EventArgs.
Do it like this:
public class MyEventArgs : EventArgs
{
public string MyEventString {get; set; }
public MyEventArgs(string myString)
{
this.MyEventString = myString;
}
}
Then in your code replace the EventArgs with MyEventArgs and create an MyEventArgs object with your string in it.
Then you can access it by using the MyEventArgs instance .MyEventString.
So you would do something like this:
///// myClass (working thread...)
class myClass
{
public event EventHandler NewListEntry;
public void ThreadMethod()
{
DoSomething();
}
protected virtual void OnNewListEntry(MyEventArgs e)
{
EventHandler newListEntry = NewListEntry;
if (newListEntry != null)
{
newListEntry(this, e);
}
}
private void DoSomething()
{
///// Do some things and generate strings, such as "test"...
string test = "test";
OnNewListEntry(new MyEventArgs(test));
}
}
And in your form:
private void myObj_NewListEntry(Object objSender, MyEventArgs e)
{
this.BeginInvoke((MethodInvoker)delegate
{
// Here I want to add my string from the worker-thread to the textbox!
richTextBox1.Text += e.MyEventString;
});
}
In general you need to inherit EventArgs and add a string property, and then make your event of type EventHandler<YourEventArgs>, but that is a classic case for the BackgroundWorker.
Sample here:
http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx
and here:
C# backgroundWorker reports string?

How to send custom event message just after control instantiation?

I have null exception error on sending ValueChanged() event when creating this custom control and testing it in a client:
Source of custom control:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
namespace customevent
{
[DefaultEvent("ValueChanged")]
public partial class UserControl1 : UserControl
{
private int m_value;
public delegate void ValueChangedHandler();
[Category("Action")]
[Description("Value changed.")]
public event ValueChangedHandler ValueChanged;
public int Value
{
get { return m_value; }
set {
m_value = value;
ValueChanged();
}
}
public UserControl1()
{
InitializeComponent();
}
public UserControl1(int iValue)
{
this.Value = iValue;
InitializeComponent();
}
}
}
Then in test form:
private void Form1_Load(object sender, EventArgs e)
{
userControl11.Value = 100;
}
private void userControl11_ValueChanged()
{
MessageBox.Show(userControl11.Value.ToString());
}
Or instead of form_load, do this in constructor:
private void InitializeComponent()
{
this.userControl11 = new customevent.UserControl1(100);
You should declare the event handling as this:
public event EventHandler ValueChanged;
protected virtual void OnValueChanged(object sender, EventArgs e)
{
if (ValueChanged != null)
{
ValueChanged(sender, e);
}
}
public int Value
{
get { return m_value; }
set {
if (m_value == value) return;
m_value = value;
OnValueChanged(this, EventArgs.Empty);
}
}
PS: there is an interface INotifyPropertyChanged, you should use this instead to comply with standard .NET databinding rules.
You're not checking for nulls:
public int Value
{
get { return m_value; }
set {
m_value = value;
if(ValueChanged != null)
{
ValueChanged();
}
}
}
Furthermore, you're also not hooking into this event in your Form:
private void Form1_Load(object sender, EventArgs e)
{
userControl1.ValueChanged += userControl11_ValueChanged;
userControl11.Value = 100;
}
private void userControl11_ValueChanged()
{
MessageBox.Show(userControl11.Value.ToString());
}
Simon got you almost there:
protected virtual void OnValueChanged(object sender, EventArgs e)
{
var tmp = ValueChanged;
if (tmp != null)
{
tmp(sender, e); // With the tmp, we won't explode if a subscriber changes the collection of delegates underneath us.
}
}

Nested Generic Events

I want to have a generic event that I can fire that will take a custom eventArgs> e
Here is my code so far
public event resultsEventHandler<T> returnResults;
public delegate void resultsEventHandler<T>(object sender, resultEventArgs<ObservableEntityCollection<T>> e);
protected virtual void OnreturnResults(resultEventArgs<ObservableEntityCollection<T>> > e)
{
if (returnResults != null)
{
returnResults<T>(this, e);
}
}
public class resultEventArgs<ObservableEntityCollection<T>> : EventArgs
{
private readonly ObservableEntityCollection<T> _results;
public resultEventArgs(ObservableEntityCollection<T> results)
{
this._results = results;
}
public ObservableEntityCollection<T>> queryResult
{
get { return _results; }
}
}
Not sure of the question but
public class resultEventArgs<ObservableEntityCollection<T>> : EventArgs
should be
public class resultEventArgs<T> : EventArgs

Categories

Resources