I have a simple task I was trying to get to repeat using FluentScheduler, but I can't seem to get it to run properly. I am entirely new to "Jobs" and "Actions", so I am sure it is something stupid I am not accounting for.
I am modifying my original question as the supplied solutions were working for a console app, but not a Windows Forms app. I have tried moving the line Application.Run(ThisForm); to be before and after the JobManager and the Task, but it never updates the TextBox with the string.
public class Program
{
public class MyRegistry : Registry
{
public MyRegistry()
{
Action someMethod = new Action(() =>
{
Form1 ThisForm = new Form1();
ThisForm.Text ="HELLO";
});
this.Schedule(someMethod).ToRunNow().AndEvery(2).Seconds();
}
}
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(ThisForm);
JobManager.Initialize(new MyRegistry());
var t = Task.Run(async delegate
{
await Task.Delay(-1);
});
t.Wait();
}
}
Related
I'm trying to use a WPF window as a message popup that will close once a task has been performed. All the documentation I've seen says that this can't be done with a messageBox, that's why I'm going with the WPF. I found one code snip that allowed me to open the WPF window but it wouldn't progress the application to the next process. Below is the last code example I found that I thought showed promise but the window isn't opening -
[STAThread]
static void Main(string[] args)
{
try
{
string filePath = "my new directory";
var popup = new PopupTest();
popup.Dispatcher.BeginInvoke
(System.Windows.Threading.DispatcherPriority.Normal,
(Action)(() =>
{
popup.Show();
}));
// Do some console application stuff
do
{
Directory.CreateDirectory(filePath);
} while (!Directory.Exists(filePath));
popup.Close();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
}
}
The cs.xaml file is just the default
/// Interaction logic for PopupTest.xaml
/// </summary>
public partial class PopupTest : Window
{
public PopupTest()
{
InitializeComponent();
}
}
I feel like this should be simpler than I'm making it. Anything that can point me in the right direction is appreciated.
You need to reference the WPF assemblies and create and run a System.Windows.Application on the STA thread:
[STAThread]
static void Main(string[] args)
{
var app = new System.Windows.Application();
app.Run(new PopupTest());
}
The Run method blocks and doesn't return until the app is shut down.
If you want to do some stuff while the app is running, you need to do this on another thread:
[STAThread]
static async Task Main(string[] args)
{
Task t = Task.Run(() =>
{
string filePath = "my new directory";
do
{
Directory.CreateDirectory(filePath);
} while (!Directory.Exists(filePath));
});
var app = new System.Windows.Application();
app.Run(new MainWindow());
await t;
}
I've been working on porting an application to Android from .NET WinForms for a client, and I have run into a snag with a requirement for Dialogs that wait for user interaction before continuing.
I'll say this now, up front. While I'm relatively new to Android, I am aware that this is frowned upon in Android because of impacts on the UI thread. I understand this, however, I've been told in no uncertain terms they want it the same way it works on .NET and I fail to see how async methods and callbacks will allow me to do that without massively re-organizing their routines (against, their wishes). So, for the purpose of this question, doing it the generally ideal way is not an option for me.
I have tried some different options to achieve the result I want, nothing has been 100%. I am close though with this:
public class MessageBox
{
public class mHandler : Handler
{
public override void HandleMessage(Message mesg)
{
throw new MessageBoxException();
}
}
public class MessageBoxException : Exception
{
public MessageBoxException()
{
}
public MessageBoxException(string message)
: base(message)
{
}
public MessageBoxException(string message, Exception inner)
: base(message, inner)
{
}
}
public enum MessageBoxResult
{
Positive, Negative, Ignore, Cancel, Closed
};
private static Handler handler;
private static MessageBoxResult yesNoDialogResult;
public static MessageBoxResult Show(Context context, String title, String message, String positiveMessage, String negativeMessage)
{
yesNoDialogResult = MessageBoxResult.Closed;
AlertDialog.Builder alert = new AlertDialog.Builder(context);
alert.SetTitle(title);
alert.SetMessage(message);
alert.SetCancelable(false);
alert.SetIcon(Android.Resource.Drawable.IcDialogAlert);
handler = new mHandler();
alert.SetPositiveButton("OK", (senderAlert, args) =>
{
yesNoDialogResult = MessageBoxResult.Positive;
handler.SendMessage(handler.ObtainMessage());
});
alert.SetNegativeButton("Cancel", (senderAlert, args) =>
{
yesNoDialogResult = MessageBoxResult.Negative;
handler.SendMessage(handler.ObtainMessage());
});
alert.Show();
try { Looper.Loop(); }
catch (MessageBoxException exc) { }
return yesNoDialogResult;
}
}
I have created a MessageBox class with a Show(). To make it wait, I am using a custom Handler and the main Looper to trigger a custom Exception, which I am then handling.
At runtime, this all works, quite well actually. The problem I'm having however is that when I debug my application using Visual Studio 2013, it always breaks when I throw my exception.
To combat this, I've tried changing my Exception settings to never break on my custom exception, to no avail. I've also tried the use of [System.Diagnostics.DebuggerHidden] to bypass debugging the error, but all that accomplished was moving the point where it fails from inside the Show or Handler to instead the .Show() method call when I tried to use it.
If anyone can point me in the right direction here for either a fix to this, or another workable solution, I would be extremely grateful.
Using EventWaitHandle to make a AlertDialog "modal":
public class MessageBox
{
public enum MessageBoxResult
{
Positive, Negative, Ignore, Cancel, Closed
};
private static MessageBoxResult yesNoDialogResult;
public static async Task<MessageBoxResult> Show(Context context, String title, String message, String positiveMessage, String negativeMessage)
{
yesNoDialogResult = MessageBoxResult.Closed;
var alert = new AlertDialog.Builder(context)
.SetTitle(title).SetMessage(message)
.SetCancelable(false)
.SetIcon(Android.Resource.Drawable.IcDialogAlert);
var waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
alert.SetPositiveButton("OK", (senderAlert, args) =>
{
yesNoDialogResult = MessageBoxResult.Positive;
waitHandle.Set();
});
alert.SetNegativeButton("Cancel", (senderAlert, args) =>
{
yesNoDialogResult = MessageBoxResult.Negative;
waitHandle.Set();
});
alert.Show();
await Task.Run(() => waitHandle.WaitOne());
return yesNoDialogResult;
}
}
Usage:
button.Click += async delegate {
Console.WriteLine("MessageBox.Show");
var answer = await MessageBox.Show(this, "Stack", "Overflow", "", "");
Console.WriteLine(answer);
};
I have a C# application that acts as a web server to the local machine only.
I have used the example from this site as the base for my web server.
So, here is my problem, the main application spawns a listener thread to listen for and handle the response.
In Program.cs
static class Program
{
[STAThread]
static void Main()
{
Application.Run(new SysTrayApp());
}
}
In SysTrayApp.cs:
public partial class SysTrayApp : Form
{
...
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
WebServer myWebServer = new WebServer(WebServer.Response, "http://localhost:8080/");
myWebServer.Run();
}
}
In WebServer.cs
...
public void Run()
{
ThreadPool.QueueUserWorkItem((o) =>
{
Console.WriteLine("Webserver running...");
try
{
while (_listener.IsListening)
{
var ctx = _listener.GetContext();
try
{
string rstr = _responderMethod(ctx.Request);
byte[] buf = Encoding.UTF8.GetBytes(rstr);
ctx.Response.ContentLength64 = buf.Length;
ctx.Response.OutputStream.Write(buf, 0, buf.Length);
}
catch { } // suppress any exceptions
finally
{
// always close the stream
ctx.Response.OutputStream.Close();
}
}
}
catch { } // suppress any exceptions
});
}
When a request is received, I want to display a Windows Form to the local environment (not the HTTP response). The problem is that I am no longer in the main STAThread when I receive the request, so I can't open a form properly.
If I try open it in the listener thread, the form just freezes because the listener starts listening and blocks the thread. A similar thing happens if I open a threadpool thread.
public static string Response(HttpListenerRequest request)
{
Form form = new Form();
form.Show();
return "TEST!";
}
If I open it in a new normal Thread, the form pops up and then the thread closes and then the form closes again.
public static string Response(HttpListenerRequest request)
{
Thread thread = new Thread(startForm);
thread.Start();
return "TEST!";
}
public static void startForm()
{
Form form = new Form();
form.Show();
}
So, from what I can figure out, only forms in the main application/UI thread seem to work properly and also, you can't block the main thread, or else the forms freeze. So, from within the WebServer listener, how do I trigger the opening of a form on the main thread?
Should I create an event on the main form that launches the second form and try to trigger it from the listener thread?
Or is there a better way to do it?
P.S. I am a PHP/Python programmer that has had to venture into C# just for a single project, so I am not really sure what I am doing.
You can invoke a method of SysTrayApp in the worker thread as below
public class SysTrayApp : Form
{
public SysTrayApp()
{
Task.Factory.StartNew(Process, TaskCreationOptions.LongRunning);
}
void ActualWork(DateTime dt)
{
this.Text = dt.ToString();
}
void Process()
{
while(true)
{
this.Invoke((Action)(() => ActualWork(DateTime.Now)));
Thread.Sleep(1000);
}
}
}
BTW: Don't use threads from threadpool for long running tasks. Why .net Threadpool is used only for short time span tasks?
I have a method that creates a bound with a windows form and also sents to that window form a parameter. I would like to create a thread to that window form. How can I do it?
public Send_to_windowForm(string name_form, string value_for_labellBox)
{
thread t = new thread(new threadStart (form(value_for_labelBox)).Start();
Application.Run(new form(value_for_labelBox));
form.text=name_form;
}
it's not working. I don't think it's correct. How can I do it? And one more question: how can i handleall the form application that the thread opens? I would like to handle all the forms because in a specific moment i want to add a new value to one of the forms opened on the desktop.
THX
You need to do something like this:
namespace UIThreadMarshalling {
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var tt = new ThreadTest();
ThreadStart ts = new ThreadStart(tt.StartUiThread);
Thread t = new Thread(ts);
t.Name = "UI Thread";
t.Start();
Thread.Sleep(new TimeSpan(0, 0, 10));
}
}
public class ThreadTest {
Form _form;
public ThreadTest() {
}
public void StartUiThread()
{
using (Form1 _form = new Form1())
{
Application.Run(_form);
}
}
}
}
How you update textboxes and labels in the main thread from a new thread running a different class.
MainForm.cs (Main thread)
public partial class MainForm : Form
{
public MainForm()
{
Test t = new Test();
Thread testThread = new Thread(new ThreadStart(t.HelloWorld));
testThread.IsBackground = true;
testThread.Start();
}
private void UpdateTextBox(string text)
{
textBox1.AppendText(text + "\r\n");
}
}
public class Test
{
public void HelloWorld()
{
MainForm.UpdateTextBox("Hello World");
// How do I execute this on the main thread ???
}
}
I have looked at the examples on here but cant seem to get it right. Please could someone give some good links.
I have started again fresh so I don't mess up my code. If anyone would like to put up a working example with my example that would be great.
Also if I had to update multiple objects like textboxes and labels etc (not all at the same time) what would be the best way to go about it, having a method for each textbox or is there a way to do this with one method?
Invoke or BeginInvoke, e.g.
Invoke((MethodInvoker)delegate {
MainForm.UpdateTextBox("Hello World");
});
#tiptopjones I guess you're asking also how to get a reference to the form. You could make your HelloWorld method take an object parameter, use the ParameterizedThreadStart delegate, and then pass a reference to the form as a parameter to the Thread.Start method. But I would suggest reading about anonymous methods which makes it a lot easier and keeps everything strongly typed.
public class MainForm : Form {
public MainForm() {
Test t = new Test();
Thread testThread = new Thread((ThreadStart)delegate { t.HelloWorld(this); });
testThread.IsBackground = true;
testThread.Start();
}
public void UpdateTextBox(string text) {
Invoke((MethodInvoker)delegate {
textBox1.AppendText(text + "\r\n");
});
}
}
public class Test {
public void HelloWorld(MainForm form) {
form.UpdateTextBox("Hello World");
}
}
When you get comfortable with that you could read up on lambda expressions and do it like:
Thread testThread = new Thread(() => t.HelloWorld(this));
You can call the BeginInvoke method, which will queue a delegate to be executed asynchronously on the UI thread.
If you need the background thread to wait until the function finishes on the UI thread, you can call Invoke instead.
Note that you will need a reference to the instance of your form; you should probably pass that to the Test constructor and store it in a private field.
The BackgroundWorker component will do all of this automatically using the ReportProgress method; you should consider using it.
The prefered way in WinForms is to use the SynchronizationContext
public partial class MainForm : Form
{
SynchronizationContext ctx;
public MainForm()
{
ctx = SynchronizationContext.Current;
Test t = new Test();
Thread testThread = new Thread(new ThreadStart(t.HelloWorld));
testThread.IsBackground = true;
testThread.Start();
}
private void UpdateTextBox(string text)
{
ctx.Send(delegate(object state)
{
textBox1.AppendText(text + "\r\n");
},null);
}
}
public class Test
{
public void HelloWorld()
{
MainForm.UpdateTextBox("Hello World");
// How do I excute this on the main thread ???
}
}