C# - Return result asynchronously - c#

I know I asked this before - but it involved threading or tasks. Now, I want to achieve the same without using threading or tasks, because I'm limited (the code is a Lua script). Now, what I want to achieve is like that:
Imagine a form with 2 buttons. The first button is called "Run", the second one is called "Set". I want Run to show a MessageBox with the text: "The result was " + result. However, I want it to show this MessageBox only once the result is set. So, you click the Run button, it halts the exceution of the method (the thread doesn't get stuck, though, so it's asychronous), and then when you click the Set button it sets the response to true and the code of the Run button continues and it shows the MessageBox.
How can I achieve this without the use of threading and tasks? Please show some examples. Moreover, if you can - show examples with threading or tasks even though my Lua code limits it. So far I've tried using a TaskCompletionSource of boolean but this involves the usage of the await operator which I can't use because it's a part of the C# sytnax (not allowed in Lua).
Best regards.

A very primitive way would be to use the Application.DoEvents() in a loop, it continues serving your form in a very delayed way, but it works to what you specified. Ofcourse if you depend on a more complex calculation inside your run loop, you would need to call application.doevents inside the complex calculation
So, like this:
using System;
using System.Windows.Forms;
namespace TestForm
{
public partial class Form1 : Form
{
FakeAsync test = new FakeAsync();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void button1_Click(object sender, EventArgs e)
{
test.Start();
}
private void button2_Click(object sender, EventArgs e)
{
test.IsSet = true;
}
}
public class FakeAsync
{
public bool Running { get; protected set; }
public bool IsSet { get; set; }
protected virtual void Loop()
{
Running = true;
while (!IsSet)
{
Application.DoEvents();
}
MessageBox.Show("Hello World!");
Running = false;
}
public void Start()
{
if (!Running)
{
Loop();
}
}
}
}

Related

EventWaitHandle blocking the entire form

I've been looking around for quite some time now, but without any solution..
What I want to achieve, is use an EventWaitHandle class in order to pause one thread.
So, I create two buttons on a form. The first one should send a message, then pause, and the second one should unpause the thread of the first button, which then sends another message. Like that:
using System;
using System.Windows.Forms;
using System.Threading;
namespace Application
{
public partial class Form1 : Form
{
EventWaitHandle wh = new AutoResetEvent(false);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MessageBox.Show("Thread blocked!");
wh.WaitOne();
MessageBox.Show("Thread unblocked!");
}
private void button2_Click(object sender, EventArgs e)
{
wh.Set();
}
}
}
But as soon as the thread gets blocked with the wh.WaitOne(), I can't do anything on the entire form, including pushing the second button or at least closing it..
What did I do wrong? Because I can't seem to find any difference between examples I could find, and my code.
You have only 1 thread. The UI thread.
When you block it, you block the entire UI.
You'll have to create a second thread.
Try this:
private void button1_Click(object sender, EventArgs e)
{
new Thread() {
void run() {
MessageBox.Show("Thread blocked!");
wh.WaitOne();
MessageBox.Show("Thread unblocked!");
}
}.start();
}

accessing progress bar via a secondary class

I have two classes, Form1.cs and secondclass.cs, I'm trying to do something on secondclass.cs and send the progress to a progress bar on Form1.cs , this is my current code:
Form1.cs
namespace DifferentClasses
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
secondclass.updateBar(20);
}
private void button2_Click(object sender, EventArgs e)
{
this.setBar(20);
}
public void setBar(int percentage)
{
this.progressBar1.Value += percentage;
Console.WriteLine(Convert.ToString(percentage));
}
}
}
secondclass.cs
namespace DifferentClasses
{
class secondclass
{
public static void updateBar(int percentage)
{
var frm = new Form1();
frm.setBar(percentage);
}
}
}
(this was a new project to test what I actually want in my main program)
as you see I have created 2 buttons, the first one runs the command via secondclass.cs
and the second one runs it directly from the same class. Funny enough both don't give errors
and both return the console line, however the first button doesn't actually change the progress bar and I can't figure out why.
The problem is in updateBar you are creating a new Form1 and setting the percentage on that.
The simplest way to solve this is to pass a reference to the current form into updateBar like this:
public static void updateBar(int percentage,Form1 f)
{
f.setBar(percentage);
}
and in the calling code do this:
secondclass.updateBar(20,this);
I'm guess the secondclass will end up running something which may take some time, so you may want to look at the async features in C#

Method Only Works Once? C#

I'm starting to think this is a stupid question, because I cannot find anything related but here goes.
So I've been learning C# and trying to figure out methods, so I created a simple method that increases a variable when used. So then I attached it to a button in Microsoft Visual Forms. However it only seems to increase the value once and then the computer stops executing the method.
Here's My Code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int number = 0;
public void button1_Click(object sender, EventArgs e)
{
NumberMethod(number);
}
public int NumberMethod(int number)
{
number++;
label1.Text = number.ToString("Number:#");
return number;
}
}
So again I want it to execute the method and increase the variable every time someone clicks the button.
Try using this keyword:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
int number = 0;
public void button1_Click(object sender, EventArgs e)
{
NumberMethod();
}
public int NumberMethod()
{
this.number++;
label1.Text = this.number.ToString("Number:#");
return this.number;
}
}
Explanation:
When you invoke NumberMethod(number) it passes only the value which is initially zero. And that is incremented by 1 from the function. The important thing is the value of the variable number is not changed yet (it remains zero). The same happens again and again.
In my solution, we are not passing the value, but changing the value of number from the method itself.

Add item to listview from another form

I've stomped with a problem I've spent some hours trying to solve, with my very limited knowledge.
I have a listview in my form1 called listMachine
And I have a method in form1.cs such as
private void máquinaToolStripMenuItem_Click(object sender, EventArgs e)
{
machinename open = new machinename();
open.Show();
}
machinename.cs is another form, and I use that method to open my other form, with an object called open.
the machinename button is a simple form which just serves as an input receiver, it asks a name, we have to type it into the textbox, press a button and it receives the input.
This is the code that runs when you press the button
public void buttonAceitarnome_Click(object sender, EventArgs e)
{
if (textBoxnomenova.TextLength == 0)
{
toolTipEmptyname.Show("O nome da máquina não pode estar vazio", textBoxnomenova);
}
else
{
Variables.var = textBoxnomenova.Text;
//MessageBox.Show(Variables.var); debug purpose, the messagebox does carry variables.var text
obj.listMachine.Items.Add(Variables.var); //If I change the variables.var to "test" it will NOT add the item.
this.Close();
}
}
Also, I forgot to mention my Variables.cs class, I created it because it was the only way I found to pass variables from a class to another (machinename.cs to form1.cs), but still, the items are not added into the listview.
This is my variables.cs code
public static class Variables
{
public static string var;
}
The comments I added to the code also give you some extra debug info..
I didn't want to ask for online help, but couldn't solve this on my own :(
If I were you, I would first remove the Variables class.
Then, you'r first form/class is called obj.cs, am I right? Or is it form1.cs?
I made it look like this:
public partial class obj : Form
{
public static string text; //This is a variable that can be reached from
public obj()
{
InitializeComponent();
}
private void máquinaToolStripMenuItem_Click(object sender, EventArgs e)
{
machinename open = new machinename();
open.ShowDialog(); //I put ShowDialog instead of Show
addItem(); //This method is called when the showed dialog is closed (machinename.cs)
}
private void addItem()
{
listMachine.Items.Add(text);
}
}
and the machinename.cs class like this:
public partial class machinename : Form
{
public machinename()
{
InitializeComponent();
}
private void buttonAceitarnome_Click(object sender, EventArgs e) //This one can be private
{
if (textBoxnomenova.TextLength == 0)
{
//Something here
}
else
{
obj.text = textBoxnomenova.Text; //Initializing the public static variable
this.Close(); //Closes the form, next step will be to run the method in obj.cs
}
}
}
If I understood your question correctly, you wanted to add an item to the ListView called "listMachine" via a button in the form "machinename.cs". This code will do that. I hope it helps you.
Change the click event from private to protected.
protected void máquinaToolStripMenuItem_Click(object sender, EventArgs e)

How to detect that a Window has used up its "ShowDialog" call

In WPF you get to call ShowDialog on a window exactly once. After that it is done for.
Seems kind of lame to me, but those are the rules. If you call ShowDialog again you get this exception:
Cannot set Visibility or call Show, ShowDialog, or WindowInteropHelper.EnsureHandle after a Window has closed
What I want to know is: How can I take a Window (or UserControl really) and check to see if it has had ShowDialog called (so I know to new up a different one before calling ShowDialog again).
Something like this:
public void ShowListOfClients()
{
// | This is the method I want to write
// V
RefreshViewIfNeeded(_myWindowOrUserControlThatShowsAList);
FillWindowWithBusinessData(_myWindowOrUserControlThatShowsAList);
_myWindowOrUserControlThatShowsAList.ShowDialog();
}
NOTE: Clearly in the above example it would be easier to just create a new WindowOrUserControlThatShowsAList every time I enter the method. But please consider the question more that the dumbed down example.
This isn't exclusive to ShowDialog(), Show() does it too. And no, there is no IsDisposed property to check. IsLoaded is only half a solution, it will be false for the 1st invocation as well.
First approach is to just make a dialog that can be re-shown:
public bool CloseAllowed { get; set; }
private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
if (!CloseAllowed) {
this.Visibility = System.Windows.Visibility.Hidden;
e.Cancel = true;
}
}
The next one is to explicitly keep track of the health of the object reference:
private Window1 win = new Window1(); // say
private void button1_Click(object sender, RoutedEventArgs e) {
if (win == null) {
win = new Window1();
win.Closing += delegate { win = null; };
}
win.ShowDialog();
}
Well the dirty way to do it would be to catch the exception.
The clean way to do it would be to show a window with ShowDialog, and destroy (lose reference to, etc) the window when the function returns. The view should not be tightly coupled with the models (you are using MVVM right?) so creating new visual objects for each client view should not be an issue.
Easy way to deal with this problem without messing up with the Closing event :
public partial class MainWindow
{
private SomeCustomWindow _someCustomWindow;
public MainWindow()
{
InitializeComponent();
}
private void OnOpenCustomWindowButtonClick(object sender, RoutedEventArgs e)
{
if (_someCustomWindow != null)
_someCustomWindow.Close();
_someCustomWindow = new SomeCustomWindow();
_someCustomWindow.ShowDialog();
}
private void OnWindowClosing(object sender, CancelEventArgs e)
{
if (_someCustomWindow!= null)
_someCustomWindow.Close();
}
}

Categories

Resources