I am creating DLL which contains loop of some data
how can i display progress bar
I tried to create new windows Form and displayed the same in for loop
but it ask me to close the form every time
People on SO are not here to write code for you - they are here to solve problems. Anyway, I am going to show you how you could do it, and then you can write your code based on what I provide.
First of all, a "DLL" is a Dynamic-link library. Therefore, you can attach it to any project you have (winform or unity 3d game and no, you will not do it but let's just say it could be used in both cases) so if you are already writing DLL's, make it usable in a lot of scenarios and provide the programmer with a lot possibilities for manipulation.
So, your task is divided in 2 parts here:
Calculate data
Inform the user of what stage of the calculation they are at now
For this task, we will use events and a simple for loop to show you how it works.
First of all, let's create an EventArgs class that will store all the data we want to pass when the programmer from the other code catches the event:
public class CustomEventArgs
{
public int OldResult { get; set; }
public int NewResult { get; set; }
}
Now, when we have an event class let's implement it in our code.
public class YourDllCalculation
{
// In the .NET Framework class library, events are based on the EventHandler delegate and the EventArgs base class.
// So we create delegate using our newly created class to represents it like EventHandler
public delegate void ResultChangeEventHandler(object sender, CustomEventArgs e);
// Now we create our event
public event IzborRobeEventHandler ResultChanged;
// Local storing variable
private int Result = 0;
// This is method from which you inform event something changed and user listening to event catch EventArgs passed (in our case our CustomEventArgs)
protected virtual void OnResultChange(CustomEventArgs e)
{
ResultChangeEventHandler h = ResultChanged;
if (h != null)
h(this, e);
}
// We will use this method from new code to start calculation;
public void StartCalculation()
{
// Calculation will be done in separate thread so your code could proceed further if needed
Thread t1 = new Thread(Calculate);
t1.Start();
}
private void Calculate()
{
for(int i = 0; i < 100; i++)
{
OnResultChange(new CustomEventArgs() { OldResult = i, NewResult = i + 1 });
Result = i;
Thread.Sleep(1000); // Pause thread from running for 1 sec
}
}
}
Now that we have our code we can use it like this in our Winform:
// Add at top
using YourDllNamespace;
public YourForm()
{
// Creating our class for calculation
YourDllCalculation calc = new YourDllCalculation();
calc += CalculationResultChanged;
calc.Calculate();
}
private void CalculationResultChanged(object sender, CustomEventArgs e)
{
// Here do whatever you want with passed values
// e.OldResult;
// e.NewResult;
// it will fire each second
}
Related
I had a winform using a method on another project thought a DLL, test, count and returns 2 values (good files and bad files) and show up on the winforms those 2 results once done.
Ive been asked to improve that winform to show up results in real time, since the work and the test can take up to 30mins, but ive been struggling since i'm beginning in async programmation.
Ive tried to call function with out or ref, without success. As far i tried, i can refresh in real time a local variable, but not one running in the method out of the winform project.
Winform :
public static int goodfiles { get; set; }
public static int badfiles { get; set; }
Task workControl;
Task refreshControl;
private async void Winform_Load(object sender, EventArgs e)
{
myprogressBar.Style = ProgressBarStyle.Marquee;
workControl = Task.Run(() => WorkMethod());
refreshControl = Task.Run(() => RefreshMethod());
await executerControl.ConfigureAwait(true);
}
private void RefreshMethod()
{
while (!workControl.IsCompleted)
{
label1.Invoke(new MethodInvoker(delegate
{
label1.Text = goodfiles.ToString();
label2.Text = badfiles.ToString();
}
}
}
private void WorkMethod()
{
goodfiles = 0;
badfiles = 0;
var Work = new WorkClass();
Work.ControlFiles(goodfiles, badfiles);
}
Class library project
public class WorkClass
{
public void ControlFiles(int goodfiles, int badfiles)
{
//Do stuff
var Test = new TestClass();
Test.TestFiles(goodfiles, badfiles);
}
}
public class TestClass
{
public void TestFiles(int goodfiles, int badfiles)
{
//Test files
if(stuff) goodfiles++;
else badfiles++;
}
}
I know it's maybe far from being the prefect architecture, but I have to deal with it.
Is it technically possible, difficult or just impossible to do? Or am I missing something obvious ?
You need to use the same fields from the worker thread and UI thread. The best way is to put them in a shared object. This might be the work-class, but you could also create a separate object that is given as a parameter to the actual work-method. I recommend against using any mutable static fields.
public class WorkClass
{
public volatile int GoodFiles;
public volatile int BadFiles;
public void ControlFiles()
{
//Test files
if (stuff) GoodFiles++;
else BadFiles++;
}
}
and call it like
WorkClass myWork;
private async void Winform_Load(object sender, EventArgs e)
{
myWork = new WorkClass();
workControl = Task.Run(() => myWork.ControlFiles());
}
To check the progress I would recommend a timer. Set it to run however often you want, and update the labels from the myWork-object when event handler for the Tick-event. You can await the workControl-task and stop the timer when the task is done.
It depends on how coupled or uncoupled you want your code to be.
In most cases, the Progress class is a good choice.
Here's an article from Stephen Cleary on the subject: Reporting Progress from Async Tasks
I have a problem: Our application has grown so far and therefore there is an object with many many EventHandlers. The point here is that removing them takes far more time, than adding them. This can be tested very fast:
Create a class with a
public event EventHandler
Make a second time and register to the event in first class like 300'000 times.
Here comes the interesting point: Registring needs like 0.1 seconds, whereas deregistring needs 5 minutes and it's growing almost exponentially.
Does anyone have a solution for that? The only one I found is to solve it over a WeakEventHandler (with it's downsides), but maybe there is another possiblity.
Example:
public class ClassWithValueChangedEvent
{
public event EventHandler ValueChanged;
public ClassWithValueChangedEvent()
{
}
}
public class MainWindowViewModel
{
public MainWindowViewModel()
{
DateTime start = DateTime.Now;
var classInstance = new ClassWithValueChangedEvent();
for (int i = 0; i < 300000; i++)
{
classInstance.ValueChanged += ClassWithValueChangedOnValueChanged;
}
Debug.WriteLine($"Elapsed Time: {(DateTime.Now - start).TotalSeconds}");
start = DateTime.Now;
for (int i = 0; i < 300000; i++)
{
classInstance.ValueChanged -= ClassWithValueChangedOnValueChanged;
}
Debug.WriteLine($"Elapsed Time: {(DateTime.Now - start).TotalSeconds}");
If we need to remove all event handlers
What I would do is that I would create an Unset method inside the class that nullifies the ValueChanged event handler like bellow:
public class ClassWithValueChangedEvent
{
public event EventHandler ValueChanged;
public void Unset()
{
ValueChanged = null;
}
}
Then, when needed I would do:
classInstance.Unset();
This is almost instantaneous.
If we need to remove individual event handlers
The process bellow is much more complicated and I don't know if I would choose it if I was in such need. The idea is that we create a custom list and we invoke the handlers manually:
public class ClassWithValueChangedEvent
{
private List<EventHandler> eventHandlers = new List<EventHandler>();
public void SetEventHandler(EventHandler evt)
{
eventHandlers.Add(evt);
}
public void UnsetEventHandler(EventHandler evt)
{
eventHandlers.Remove(evt);
}
public void UnsetAll()
{
eventHandlers.Clear();
}
public void CallEventHandlers(object? sender, EventArgs e)
{
eventHandlers.All(p => { p(sender, e); return true; });
}
}
Then, the methods of this class can be called as:
classInstance.SetEventHandler(ClassWithValueChangedOnValueChanged);
classInstance.CallEventHandlers(null, null);
classInstance.UnsetEventHandler(ClassWithValueChangedOnValueChanged);
Removing 300000 event handlers takes around 9 seconds which is much faster than minutes. I guess also that there must be a much faster way to do something like that.
I solved this question in using the WeakEventManager<>.AddHandler() from microsoft, which does not immediately remove the event handlers. It did not matter in this case.
Say I have a common class that performs some time-consuming step (eg. saving stuff to USB). I'd like to be able to call that code from multiple forms and receive feedback whenever a step is completed. How does the common class know to whom to send feedback to? The code below describes the situation:
// ### Common class frmCommon ###
// Parent form (when feedback on some slow operation is required)
private static Form m_frmParent = null;
// ...
public static void SetParentForm(Form frmParent)
{
// When some time consuming process takes place (such as saving to USB), setting the
// parent form allows feedback to be given to the user (eg. as a progress bar)
m_frmParent = frmParent;
}
public static void DoSomething()
{
for (int nStep = 0; nStep < 100; nStep++)
{
// Tell the parent form how many product sets (groups of 20) there are to read
if (m_frmParent != null)
{
// How to decide whether to call form 1 or form 2?
((frmForm1)m_frmParent).SendFeedback(nStep);
((frmForm2)m_frmParent).SendFeedback(nStep);
}
// Perform the time-consuming step...
SlowStep(nStep);
}
}
// ### FORM 1 frmForm1 ###
private void SomeEventForm1(int nStep)
{
frmCommon.SetParentForm(this);
frmCommon.DoSomething();
frmCommon.SetParentForm(null);
}
public void SendFeedback(int nStep)
{
// Do something like update a progress bar on form 1
Application.DoEvents();
}
// ### FORM 2 frmForm2 ###
private void SomeEventForm2(int nStep)
{
frmCommon.SetParentForm(this);
frmCommon.DoSomething();
frmCommon.SetParentForm(null);
}
public void SendFeedback(int nStep)
{
// Do something like update a progress bar on form 2
Application.DoEvents();
}
Aiming for .NET 2.0 if that makes a difference.
I'd rather use an event:
public class SlowProcess {
...
// Simplest, not thread safe
public static event EventHandler<int> StepChanged;
public static void DoSomething() {
for (int nStep = 0; nStep < 100; nStep++) {
if (null != StepChanged)
StepChanged(null, nStep);
SlowStep(nStep);
}
}
}
...
public partial class MyEventForm: Form {
...
private void onStepChange(Object sender, int nStep) {
//TODO: update form here after receiving a feedback
}
private void TraceSlowProcess() {
// feedback is required
SlowProcess.StepChanged += onStepChange;
try {
SlowProcess.DoSomething();
}
finally {
// No need of feedback
SlowProcess.StepChanged -= onStepChange;
}
}
}
The calling code will have to provide a delegate to that class. When the class is done with the time consuming process, it will call that delegate to inform the calling code that it finished. Look here for a good tutorial on how to do this.
1 - If SendFeedback is a function you implemented in both forms, and they do the same, consider creating a single static method in a static class to extend the Form:
public static class FormExtender
{
public static void SendFeedback(this Form frm, int nStep)
{
//do what must be done
//you can call this anyhere using, for instance: m_frmParent.SendFeedback(nStep)
//when you call it like that, m_frmParent will be given to this function as the argument frm
}
}
2 - But if the methods are different in both forms, I suggest you create an interface:
interface IFormWithFeedback
{
void SendFeedback(int nStep);
}
Then form1 and form2 should implement this (just add , IFormWithFeedBack where your forms are declared):
public class frmForm1 : Form, IFormWithFeedback
public class frmForm2 : Form, IFormWithFeedback
And your parent form inside that class should be an IFormWithFeedback instead of a form:
private static IFormWithFeedback m_frmParent = null;
Both options (extension method or interface) would allow you to call SendFeedback direclty from m_frmParent without casting it.
I am working with background workers to update a progress bar in a WPF UI I am working on. This background worker is getting its progress updates from multiple events that I am subscribed to, because the progress bar goes through several loading stages, and the percentages for those come from several places. here is some example/pseudo code explaining what I mean
The DoWork method of my background worker and the methods I am using to currently get some progress updates
// These are working fine
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
orderProcessing.OnOrderProgress += OrderStatus;
orderProcessing.OnStandardOrderProgress += StandardOrderStatus;
orderProcessing.CreateOrders(orders);
}
private void OrderStatus(int currentCount, int totalItems, string Message)
{
if (totalItems > 0)
bw.ReportProgress(Convert.ToInt32(((double)currentCount / (double)totalItems) * 100),
Message);
}
private void StandardOrderStatus(int currentCount, int totalItems, string Message)
{
if (totalItems > 0)
bw.ReportProgress(Convert.ToInt32(((double)currentCount / (double)totalItems) * 100),
Message);
}
Some code from my order processing class
public abstract class OrderProcessing
{
public delegate void OrderProgress(int CurrentItems, int TotalItems, string Message);
public event MasterSalesOrder.StandardOrderProgress OnStandardOrderProgress;
public event OrderProgress OnOrderProgress;
public abstract List<MasterSalesOrder> CreateOrders(List<Order> orders);
}
Some code from the class that holds the override method for CreateOrders()
public abstract class OrderProcessingFile : OrderProcessing
{
public event OrderProgress OnOrderProgress;
public override List<MasterSalesOrder> CreateOrders(List<Order> orders)
{
//Does Some Stuff
foreach(var stuff in stuffs)
{
OnOrderProgress(currentCount, totalCount, "Message");
}
}
}
Since I am clearly not explaining this well, I need to get info from the OrderProcessingFiles OnOrderProgress event via the OrderProcessing class that I create in the DoWork method.I am unsure on how to subscribe to an event when my code never directly instantiates an instance of the OrderProcessingFile class and it is never directly referred to.
I have tried looking for answers but as my title will show I am having a hard time even wording this in a way to get useful results, and I am genuinely stuck on this one. Let me know if more detail is needed, I tried to strip down my code to only the relevant parts but I feel like I'm explaining this strangely.
I would recommend that you create a thread safe singleton progress manager. Then have each of the background workers contact it with updates. The progress manager will use a DispatcherTimer (which runs on the GUI thread) to update the GUI appropriately.
Raw example:
public static class StatusReportManager
{
// Standard singleton code to create the manager and access it.
// Start/create the dispatch time as well.
private static DispatcherTimer Timer { get; set; }
private static object _syncObject = new object();
public static void ReportStatus(...)
{
lock (_syncObject)
{
// Process any states and set instance properties for reading
// by the timer operation.
}
}
private void ShowStatus() // Used by the dispatch timer
{
lock (_syncObject)
{
// Do any updates to the GUI in here from current state.
}
}
}
I have realized what it is I was really trying to do and have thus found an answer. Using the method found in this MSDN article I have implemented the follow code:
This is my UI
private void BwOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs)
{
orderProcessing.OnOrderProgress += OrderStatus;
orderProcessing.CreateOrders(FanGlobal.BrandItems, FanGlobal.BrandItemMasterCustomers);
}
private void OrderStatus(object obj, OrderProcessing.OrderProgressEventArgs e)
{
if (e.totalCount > 0)
bw.ReportProgress(Convert.ToInt32(((double)e.currentCount / (double)e.totalCount) * 100),e.message);
}
This in my OrderProcessing class
public event EventHandler<OrderProgressEventArgs> OnOrderProgress;
public class OrderProgressEventArgs : EventArgs
{
public int currentCount;
public int totalCount;
public string message;
public OrderProgressEventArgs(int c, int t, string m)
{
currentCount = c;
totalCount = t;
message = m;
}
}
protected virtual void OnOrderProgressChanged(OrderProgressEventArgs e)
{
EventHandler<OrderProgressEventArgs> handler = OnOrderProgress;
if (handler != null)
{
handler(this, e);
}
}
public abstract List<MasterSalesOrder> CreateOrders(List<BrandItem> BrandItems = null, List<BrandItemMasterCustomer> BrandItemMasterCustomers = null);
and then I can use it in my child class OrderProcessingFile like so
public override List<MasterSalesOrder> CreateOrders(List<BrandItem> BrandItems = null, List<BrandItemMasterCustomer> BrandItemMasterCustomers = null)
{
//Do some Stuff
OnOrderProgressChanged(new OrderProgressEventArgs(count, totalItems, "Extracting"));
}
and everything is working like a charm. Sorry for the utterly confusing question and the apparent huge gap of knowledge I have/had, but hopefully this will help someone else in the future.
I am trying to create a thread which will continuously check for changes to a value, then visually show that change in a PictureBox located in my GUI.
What I actually wrote is a bit more complicated, so I simplified it while keeping the basic idea, I would be happy to provide clarification if this isn't enough:
public class CheckPictures
{
PictureBox update;
List<String> check;
public CheckPictures(PictureBox anUpdate, List<String> aCheck)
{
update = anUpdate;
check = aCheck;
}
public void start()
{
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
}
}
static int Main(string[] args)
{
List<String> picturesList = new List<String>();
CheckPictures thread1 = new CheckPictures(PictureBox1, picturesList);
Thread oThread1 = new Thread(thread1.start));
}
What I want it to do is dynamically change the picture in PictureBox1 if I were to add the string "Me" to pictureList. The above code isn't working like I'd hoped. I had thought that by passing the actual PictureBox and List, any changes to the List elsewhere is the program would be caught by the thread. So my first question is: Is this possible? And if so, what change would I need to make to my code to achieve it?
You might want to use events. You register an eventhandler and when something changes in one thread it calls an event handler in the other to do the work. Busy waiting wastes cpu.
You definetely do not want to do an infinite loop, this will just consume cpu:
while(true)
{
if (aCheck[0] == "Me")
{
update.Image = Image.fromFile("");
}
}
I think you should look into the CountdownLatch class.
public class CountdownLatch
{
private int m_remain;
private EventWaitHandle m_event;
public CountdownLatch(int count)
{
m_remain = count;
m_event = new ManualResetEvent(false);
}
public void Signal()
{
// The last thread to signal also sets the event.
if (Interlocked.Decrement(ref m_remain) == 0)
m_event.Set();
}
public void Wait()
{
m_event.WaitOne();
}
}
The basic idea here is that you need to stop execution on your thread for some time and resume whenever a certain condition has been met (perhaps on another thread).
In other words, you will have a counter, decrement its value on certain condition and whenever it goes to zero you fire your event, execute some code and then start over (stop execution and wait for the counter to go to zero).
In your case you could set the counter to 1 and decrement its value whenever you've set aCheck[0] = "Me"; This way you don't waste CPU.
Pseudo code:
Initialize counter:
CountdownLatch latch = new CountdownLatch(1);
Make thread wait:
public void start()
{
while(true)
{
latch.Wait(); //execution stops
{
//execution resumes once the latch counter is zero.
if (aCheck[0] == "Me") //double check you have what you need
{
update.Image = Image.fromFile("");
latch = new CountdownLatch(1); //reset if you need to do it again
}
}
}
}
Whenever your condition is met (i.e. aCheck[0] = "Me";) signal your latch:
latch.Signal();
this last line will make the thread resume execution. Good stuff.
Create some object, which will raise event, when new picture was added. E.g. class representing pictures collection:
public class PicturesCollection
{
public event EventHandler<PictureAddedEventArgs> PictureAdded;
private List<string> _pictures = new List<string>();
public void Add(string name)
{
_pictures.Add(name);
if (PictureAdded != null)
PictureAdded(this, new PictureAddedEventArgs(name));
}
public IEnumerable<string> Pictures
{
get { return _pictures; }
}
}
If you want to provide some additional data to event, create custom EventArgs:
public class PictureAddedEventArgs : EventArgs
{
public PictureAddedEventArgs(string name)
{
Name = name;
}
public string Name { get; private set; }
}
All you need now - create pictures collection and subscribe to that event:
static int Main(string[] args)
{
PicturesCollection pictures = new PicturesCollection();
pictures.PictureAdded += Pictures_PictureAdded;
}
static void Pictures_PictureAdded(object sender, PictureAddedEventArgs e)
{
if (e.Name == "Me")
PictureBox1.Image = Image.fromFile("");
}
If you add somewhere in your application new picture to collection, it will raise PictureAdded event, which you can handle and update PictureBox. CPU is not wasted in this case.