I have class (ConsoleApplication) names ClassA with a field:
public class ClassA
{
List<Task> Tasks;
(...)
public void PlotGrid()
{
Action<object> action = new Action<object>(ShowChart);
Task task = new Task(action, intervalX);
task.Start();
Tasks.Add(task);
}
(...)
private void ShowChart(object intervalX)
{
int interval = Convert.ToInt32(intervalX);
ChartForm chart = new ChartForm(GetValuesForPlotting(), interval);
chart.ShowDialog();
}
}
(Description about ChartForm's at the end of post)
Ok. When I have created the ClassA in Program.cs:
class Program
{
static void Main(string[] args)
{
ClassA class = new ClassA();
class.PlotGrid();
Console.WriteLine("it was shown as parallel with windowsform(the ChartForm)");
}
}
In terminal had shown:
it was shown as parallel with windowsform(the ChartForm) but a ChartForm not shown. I want to create a descructor or other way for ClassA. How i can do it if a parent (ClassA) has children (ChartForm) and until it has a children whom are running - don't close app.
I tried to add in destructor ClassA:
~ClassA()
{
Task.WaitAll(Tasks.ToArray());
}
but it didn't help.
Class ChartForm is from other project, which inherit WindowsForms (Form) and has only one object: Chart.
Please look below:
public partial class ChartForm : Form
{
private List<Complex> valuesForPlotting;
int intervalX;
public ChartForm(List<Complex> valuesForPlotting, int intervalX)
{
InitializeComponent();
this.valuesForPlotting = valuesForPlotting;
this.intervalX = intervalX;
}
private void Form1_Load(object sender, EventArgs e)
{
chart1.ChartAreas[0].AxisX.Interval = intervalX;
chart1.ChartAreas[0].AxisX.Minimum = 0;
chart1.ChartAreas[0].AxisX.Maximum = valuesForPlotting.Max(p=> p.Real)+intervalX;
for (int i = 0; i < valuesForPlotting.Count; i++)
{
chart1.Series["ser1"].Points.AddXY
(valuesForPlotting[i].Real, valuesForPlotting[i].Imaginary);
}
chart1.Series["ser1"].ChartType = SeriesChartType.FastLine;
chart1.Series["ser1"].Color = Color.Red;
}
}
Related
Look at my code pls. I have ThirdClass to triger an event. In Second Class I Handle that event. But how to handle that event in my Program Class. In this class I have no ThirdClass object to subscribe an event. Do I have to declerate another event in Second class In order to triger MyPurpose() method?
public class Program
{
static void Main(string[] ars)
{
Program myProgram = new Program();
SecondClass second = new SecondClass();
second.LaunchSecondClass();
//A want to run this method when OnCounted event fired
//...
//myProgram.MyPurpose();
//...
}
public void MyPurpose()
{
Console.WriteLine("Program Class here!");
Console.ReadLine();
}
}
public class SecondClass
{
public void LaunchSecondClass()
{
ThirdClass third = new ThirdClass();
third.myEvent += this.OnCounted;
third.count();
}
private void OnCounted(object sender, EventArgs e)
{
Console.WriteLine("Second Class Here.");
//Console.ReadLine();
}
}
public class ThirdClass
{
public event EventHandler myEvent;
public void count()
{
for (int i = 0; i < 3; i++)
{
//Only for testing
Thread.Sleep(1000);
}
OnCounted();
}
protected virtual void OnCounted()
{
if (myEvent != null)
myEvent(this, EventArgs.Empty);
}
}
There are a lot of way to do what you want, as I said. The goal can be achieved, despite this, I highly recommend you to pay attention to #Glubus 's comment, .
Here's three of this ways:
Option 1 - Expose a new Event on SecondClass
public class SecondClass
{
public event EventHandler SecondEvent;
public void LaunchSecondClass()
{
ThirdClass third = new ThirdClass();
third.myEvent += this.OnCounted;
third.count();
}
private void OnCounted(object sender, EventArgs e)
{
Console.WriteLine("Second Class Here.");
//Console.ReadLine();
SecondEvent?.Invoke(); // Based on C# 6
}
}
And in your main program:
static void Main(string[] ars)
{
Program myProgram = new Program();
SecondClass second = new SecondClass();
second.SecondEvent += MyPurpose;
second.LaunchSecondClass();
}
Option 2 - Expose the ThirdClass on SecondClass as a property
public class SecondClass
{
public ThirdClass ThirdClass { get; }
public SecondClass()
{
ThirdClass = new ThirdClass();
ThirdClass.myEvent += this.OnCounted;
}
public void LaunchSecondClass()
{
if(ThirdClass == null)
ThirdClass = new ThirdClass();
ThirdClass.count();
}
private void OnCounted(object sender, EventArgs e)
{
Console.WriteLine("Second Class Here.");
//Console.ReadLine();
}
}
And in your main program:
static void Main(string[] ars)
{
Program myProgram = new Program();
SecondClass second = new SecondClass();
second.ThirdClass.myEvent += MyPurpose;
second.LaunchSecondClass();
}
Option 3 - Pass and Action (Delegate) to be executed by the SecondClass's method
public class SecondClass
{
public void LaunchSecondClass(Action action)
{
ThirdClass third = new ThirdClass();
third.myEvent += this.OnCounted;
if(action != null)
third.myEvent += (o, a) => action.Invoke();
third.count();
}
private void OnCounted(object sender, EventArgs e)
{
Console.WriteLine("Second Class Here.");
//Console.ReadLine();
}
}
And in your main program:
static void Main(string[] ars)
{
Program myProgram = new Program();
SecondClass second = new SecondClass();
second.LaunchSecondClass(MyPurpose);
}
Remember that there are no guarantees of a best practicle choice without know the real scenario where you're intent to apply it. So, maybe you must search up a design pattern to your problem and follow up the SOLID principles when planning your solutions
This is the best way to get a clean and efficient code .
Here's a good read about this topics:
Design Patterns
SOLID Principles
I Hope it help you, and sorry for my bad english
I'm searching for this for several hours now and was not able to find proper solution. I'm c# beginner.
I have a winforms app with a ListBox and a class that does some work and should run forever on separate thread. I want to push MyDataStruct to ListBox each time its created in WorkerClass.Work.
Later on, several WorkerClass instances should run simultaneously and I will have combobox to pick which instance data to feed to ListBox . Is it better to have WorkerClas return only single MyDataStruct and keep their queue in Form1 class or have a queue in each WorkerClass and exchange the entire queue with Form1 every time it changes?
is my void QueueToLb good way to add queue data to ListBox ?
thank you for your support.
public partial class Form1 : Form
{
Queue<MyDataStruct> qList;
MyDataStruct myDataStruct;
private void RunTask()
{
//how do I make MyLongTask to update either qList or myDataStuct
Task.Run(() =>
{
MyLongTask(0, 1000);
});
}
private void MyLongTask(int low, int high)
{
WorkerClass wc = new WorkerClass();
wc.Work(low,high);
}
private void QueueToLb()
{
//is this good way to update listbox from queue?
List<MyDataStruct> lstMds = qList.Reverse<MyDataStruct>().ToList<MyDataStruct>();
List<string> lstStr = new List<string>();
foreach (MyDataStruct m in lstMds)
{
lstStr.Add(m.ToString());
}
listBox1.DataSource = lstStr;
}
}
public class WorkerClass
{
Queue<MyDataStruct> qList; //not sure if its better to keep the queue here or in Form1
public WorkerClass()
{
qList = new Queue<MyDataStruct>();
}
public void Work(int low, int high) //does some work forever
{
while (true)
{
if (qList.Count > 11) qList.Dequeue();
MyDataStruct mds = new MyDataStruct();
Random random = new Random();
mds.dt = DateTime.Now;
mds.num = random.Next(low, high);
qList.Enqueue(mds);
Thread.Sleep(1000);
}
}
}
public class MyDataStruct
{
public DateTime dt;
public int num;
public override string ToString()
{
StringBuilder s = new StringBuilder();
s.Append(num.ToString());
s.Append(" - ");
s.Append(dt.ToShortDateString());
return s.ToString();
}
}
OK I think I figured how to use BackgroundWorker on this, I'll be happy if someone could verify it is correct
public partial class Form1 : Form
{
Queue<MyDataStruct> qList;
BackgroundWorker bw = new BackgroundWorker();
public Form1()
{
InitializeComponent();
bw.WorkerReportsProgress = true;
bw.DoWork += new DoWorkEventHandler(Bw_DoWork);
bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
}
private void Form1_Load(object sender, EventArgs e)
{
qList = new Queue<MyDataStruct>(12);
}
private void button1_Click(object sender, EventArgs e)
{
bw.RunWorkerAsync();
}
private void MyLongTask(int low = 0, int high = 1000)
{
WorkerClass wc = new WorkerClass(bw);
wc.Work(low,high);
}
private void BindToLbWithQueue()
{
MyDataStruct mds = new MyDataStruct();
Random random = new Random();
mds.dt = DateTime.Now;
mds.num = random.Next(0, 1000);
qList.Enqueue(mds);
QueueToLb();
}
private void QueueToLb()
{
//is this good way to update listbox from queue?
List<MyDataStruct> lstMds = qList.Reverse<MyDataStruct>().ToList<MyDataStruct>();
List<string> lstStr = new List<string>();
foreach (MyDataStruct m in lstMds)
{
lstStr.Add(m.ToString());
}
listBox1.DataSource = lstStr;
}
#region worker
private void Bw_DoWork(object sender, DoWorkEventArgs e)
{
MyLongTask();
}
private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
qList = (Queue<MyDataStruct>)e.UserState;
QueueToLb();
}
#endregion
}
public class WorkerClass
{
Queue<MyDataStruct> qList; //not sure if its better to keep the queue here or in Form1
BackgroundWorker bw = null;
public WorkerClass(BackgroundWorker bw)
{
this.bw = bw;
qList = new Queue<MyDataStruct>();
}
public void Work(int low, int high) //does some work forever
{
while (true)
{
if (qList.Count > 11) qList.Dequeue();
MyDataStruct mds = new MyDataStruct();
Random random = new Random();
mds.dt = DateTime.Now;
mds.num = random.Next(low, high);
qList.Enqueue(mds);
bw.ReportProgress(0, qList);
Thread.Sleep(1000);
}
}
}
public class MyDataStruct
{
public DateTime dt;
public int num;
public override string ToString()
{
StringBuilder s = new StringBuilder();
s.Append(num.ToString());
s.Append(" - ");
s.Append(dt.ToShortDateString());
return s.ToString();
}
}
I have a problem which i don't know how to solve.
I have some classes (Processors) that fires an event with progress information ( Percentage of how far it is). There are multiple processors that do this and the top Processor (Engine) which calls them all needs to send information to the end user on its progress.
If i don't know beforehand how many items will be processed by each processor how can i give the user some good feedback on how far the process is?
Take a look at the following simplified example
NetFiddle
class Program {
static void Main(string[] args) {
var p = new Program();
p.Run();
}
private void Run() {
var engine = new Engine();
engine.UpdateProgress += Engine_UpdateProgress;
engine.Process();
Console.ReadLine();
}
private void Engine_UpdateProgress(object sender, UpdateProgressEventArgs e) {
Console.WriteLine($"{e.UpdateDateTime} - Caller: {e.Caller}, Percentage: {e.Percentage}");
}
}
public class Engine {
private readonly ProcessorA _processorA;
private readonly ProcessorB _processorB;
private readonly ProcessorC _processorC;
private readonly ProcessorD _processorD;
public event EventHandler<UpdateProgressEventArgs> UpdateProgress;
public Engine() {
_processorA = new ProcessorA();
_processorB = new ProcessorB();
_processorC = new ProcessorC();
_processorD = new ProcessorD();
//Handle events
_processorA.UpdateProgress += ProcessorA_UpdateProgress;
_processorB.UpdateProgress += ProcessorA_UpdateProgress;
_processorC.UpdateProgress += ProcessorA_UpdateProgress;
_processorD.UpdateProgress += ProcessorA_UpdateProgress;
}
private void ProcessorA_UpdateProgress(object sender, UpdateProgressEventArgs e) {
OnUpdateProgress(e);
}
public void Process() {
_processorA.Process();
_processorB.Process();
_processorC.Process();
_processorD.Process();
}
protected virtual void OnUpdateProgress(UpdateProgressEventArgs e) {
UpdateProgress?.Invoke(this, e);
}
}
public class ProcessorA : Processor {
private readonly ProcessorA_A _processorA_A;
public ProcessorA() {
_processorA_A = new ProcessorA_A();
//Handle events
_processorA_A.UpdateProgress += ProcessorA_A_UpdateProgress;
}
public void Process() {
_processorA_A.Process();
}
private void ProcessorA_A_UpdateProgress(object sender, UpdateProgressEventArgs e) {
OnUpdateProgress(e);
}
}
public class ProcessorB : Processor {
public void Process() {
for (int i = 0; i <= 100; i++) {
var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorB), Percentage = i, UpdateDateTime = DateTime.Now};
//Do some work
Thread.Sleep(r.Next(50,250));
OnUpdateProgress(args);
}
}
}
public class ProcessorC : Processor {
public void Process() {
for (int i = 0; i <= 100; i++) {
var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorC), Percentage = i, UpdateDateTime = DateTime.Now };
//Do some work
Thread.Sleep(r.Next(50, 250));
OnUpdateProgress(args);
}
}
}
public class ProcessorD : Processor {
public void Process() {
for (int i = 0; i <= 100; i++) {
var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorD), Percentage = i, UpdateDateTime = DateTime.Now };
//Do some work
Thread.Sleep(r.Next(50, 250));
OnUpdateProgress(args);
}
}
}
public class ProcessorA_A : Processor {
public void Process() {
for (int i = 0; i <= 100; i++) {
var args = new UpdateProgressEventArgs() { Caller = nameof(ProcessorA_A), Percentage = i, UpdateDateTime = DateTime.Now };
//Do some work
Thread.Sleep(r.Next(50, 250));
OnUpdateProgress(args);
}
}
}
public class Processor : IProcessor {
protected Random r = new Random();
public event EventHandler<UpdateProgressEventArgs> UpdateProgress;
protected virtual void OnUpdateProgress(UpdateProgressEventArgs e) {
UpdateProgress?.Invoke(this, e);
}
}
public interface IProcessor {
event EventHandler<UpdateProgressEventArgs> UpdateProgress;
}
public class UpdateProgressEventArgs {
public int Percentage { get; set; }
public string Caller { get; set; }
public DateTime UpdateDateTime { get; set; }
}
Just sending the progress from child to parent won't do the trick obviously. I hope someone can help me find a solution for this. Or if someone has another brilliant solution :)
Thanks in advance
Engine could maintain a private list of "the last completeness" of each process. In a Dictionary more than likely.
if we extend your Engine class to have this.
private Dictionary<IProcessor, int> _lastReportedPercentage = new Dictionary<IProcessor, int>();
and in the constructor where all your child processors are defined, set them all to 0.
public Engine()
{
//your other stuff
_lastReportedPercentage[_processorA] = 0;
_lastReportedPercentage[_processorB] = 0;
_lastReportedPercentage[_processorC] = 0;
_lastReportedPercentage[_processorD] = 0;
}
in your Event handler for the child processes do something like this:
private void ProcessorA_UpdateProgress(object sender, UpdateProgressEventArgs e)
{
_lastReportedPercentage[(IProcessor)sender] = e.Percentage;
var totalCompleteness = (int)Math.Floor(_lastReportedPercentage.Values.Sum() / _lastReportedPercentages.Values.Count);
OnUpdateProgress(new UpdateProgressEventArgs() { Caller = nameof(Engine), Percentage = totalCompleteness, UpdateDateTime = DateTime.Now });
}
You will then be reporting, from your Engine, the total completeness of all tasks.
There are some obvious design flaws to this, but you get the idea. It can be extended for a variable number of Processors if they're loaded from not-the-constructor, etc. but this should give you the desired output you'd want.
I would suggest having each processor keep a count of how many items it has completed, and how many items it has remaining.
This way the engine receives updates whenever an item is completed, as well as when an item is added to the processor.
As in Skintkingle's answer, you would then store the last received update from each processor within the engine.
You can then let the engine decide on the best way to put this information across. Something as simple as total completed / total remaining would work well.
I have my progressbar in form1. and i have another class called process.cs
In the main form I have these two functions...
public void SetProgressMax(int max)
{
uiProgressBar.Value = 0;
uiProgressBar.Minimum = 0;
uiProgressBar.Maximum = max;
}
public void IncrementProgress()
{
uiProgressBar.Increment(1);
}
How can I call these functions from my process.cs class?
You're creating a "tightly coupled" solution which requires the process class to have a reference to the Form (I'll use Form1 in this example).
So in your process class, you need to create a variable to store the reference to the form, and allow a way to pass that reference in. One way is to use the constructor of the class:
public class process
{
private Form1 f1 = null;
public process(Form1 f1)
{
this.f1 = f1;
}
public void Foo()
{
if (f1 != null && !f1.IsDisposed)
{
f1.SetProgressMax(10);
f1.IncrementProgress();
f1.IncrementProgress();
f1.IncrementProgress();
}
}
}
Here's an example of creating the process class from within Form1 and passing the reference in:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process p = new process(this);
p.Foo();
}
public void SetProgressMax(int max)
{
uiProgressBar.Value = 0;
uiProgressBar.Minimum = 0;
uiProgressBar.Maximum = max;
}
public void IncrementProgress()
{
uiProgressBar.Increment(1);
}
}
--- EDIT ---
Here's a boiled down version of the "loosely coupled" events approach (ignoring multi-threading issues for simplicity):
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
process p = new process();
p.Progress += p_Progress;
p.Foo();
}
void p_Progress(int value)
{
uiProgressBar.Value = value;
}
}
public class process
{
public delegate void dlgProgress(int value);
public event dlgProgress Progress;
public void Foo()
{
// ... some code ...
// calcuate the current progress position somehow:
int i = (int)((double)3 / (double)10 * (double)100); // 30% complete
// raise the event if there are subscribers:
if (Progress != null)
{
Progress(i);
}
}
}
Note that in this approach the process class has no reference to the form and has no idea what is being done with the progress value. It simply reports the progress and the subscriber (the form in this case) decides what to do with that information.
I have this sample code for async operations (copied from the interwebs)
public class LongRunningTask
{
public LongRunningTask()
{
//do nowt
}
public int FetchInt()
{
Thread.Sleep(2000);
return 5;
}
}
public delegate TOutput SomeMethod<TOutput>();
public class GoodPerformance
{
public void BeginFetchInt()
{
LongRunningTask lr = new LongRunningTask();
SomeMethod<int> method = new SomeMethod<int>(lr.FetchInt);
// method is state object used to transfer result
//of long running operation
method.BeginInvoke(EndFetchInt, method);
}
public void EndFetchInt(IAsyncResult result)
{
SomeMethod<int> method = result.AsyncState as SomeMethod<int>;
Value = method.EndInvoke(result);
}
public int Value { get; set; }
}
Other async approaches I tried required the aysnc page attribute, they also seemed to cancel if other page elements where actioned on (a button clicked), this approach just seemed to work.
I’d like to add a cancel ability and exception handling for the longRunningTask class, but don’t erm, really know how.
In example:
public class ValueEventArgs : EventArgs
{
public int Value { get;set;}
}
public class ExceptionEventArgs : EventArgs
{
public Exception Exception { get;set;}
}
public class LongRunningTask
{
private bool canceled = false;
public event EventHandler<ValueEventArgs> Completed = delegate {}
public event EventHandler<ExceptionEventArgs> GotError = delegate {}
public void Cancel()
{
canceled = true;
}
public void FetchInt()
{
try
{
int result = 0;
for (int i = 0; i < 1000; i++)
{
if (canceled)
return;
result++;
}
Completed(this, new ValueEventArgs {Value = result});
}
catch(Exception exc)
{
GotError(this, new ExceptionEventArgs { Exception = exc });
}
}
public void BeginFetchInt()
{
ThreadPool.QueueUserWorkItem(i => FetchInt());
}
}
And somewhere:
LongRunningTask task = new LongRunningTask();
task.Completed +=new EventHandler<ValueEventArgs>(task_Completed);
task.GotError +=new EventHandler<ExceptionEventArgs>(task_GorError);
task.BeginFetchInt();
//in any moment until it calculates you may call:
task.Cancel();