Im using System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() => ... for a wpf graphic refresh.
It works in my other function greatfully, but in my SQL delete function it wount be triggered/executed.
I tried it with System.Windows.Forms.Application.DoEvents(); but it wount do anything.
Set_Loading_Changed()
{
System.Windows.Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Input,
new Action(() =>
{
if (BLoading)
{
DataGrid_Anzeige.IsEnabled = false;
Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
}
else
{
DataGrid_Anzeige.IsEnabled = true;
Mouse.OverrideCursor = null;
}
}));
}
Btn_Remove()
{
...
Set_Loading_Changed();
using (OleDbConnection ODC = new OleDbConnection("..."))
{
foreach (var selectedRow in DataGrid_Anzeige.SelectedItems.OfType<DataRowView>())
{
sSQL_Statement = "...";
ODC.Open();
OleDbCommand ODCmd = new OleDbCommand(sSQL_Statement, ODC);
ODCmd.ExecuteNonQuery();
ODC.Close();
EDIT:
I insert the complete part of my Set_Load_Changed() function, hope you can get a clue with this informations.
Im using it primarly in my search Thread (Task.Factory.StartNew(() => { ... }));) so it must be the DispatcherPriority.Input.
You're running into a common issue with misunderstanding the WPF threading system. The way WPF is structured is with one thread for the program to run and modify the UI in, usually called the UI thread, and a second thread which you have no normal way of using, which automatically renders the UI, commonly called the rendering or compositing thread.
The key point you need to know here is that if you stall the UI thread with a large operation (like a database read or a large calculation) immediately after BeginInvoke(), then you're preventing the UI thread from running those commands until you allow it to invoke the next action. BeginInvoke() simply queues the action to be performed the next time the dispatcher is allowed - the dispatcher will not interrupt what is currently being done. Setting the priority to Input ensures that it will be handled ahead of other lower priority work, but still will not cause it to interrupt your current method.
If you instead call Invoke(), you are interrupting your work to ask the dispatcher to perform the action and then return to what you're doing when it's finished.
While this is preferable to the behavior you're currently getting, this isn't how you're intended to use the dispatcher, and will still cause your app to appear 'frozen' while it completes the long operation. To avoid this, the easiest thing to do is run the long operation in a Task, using the async/await keywords and the Task Parallel Library.
Stephen Cleary has an excellent blog where he covers a lot of topics related to this. His introductory post (dating back to the keywords' introduction) is here.
I would encourage poking around his blog if you have more issues in this area - he's one of the leading experts in explaining this area, and has covered most of the problems you run into.
Further reading:
What's the difference between Invoke() and BeginInvoke()?
WPF Threading Model
To change the cursor in WPF is unfortunately not as straightforward as in WinForms. I remember struggling with it myself until I stumbled upon the following solution. I didn't come up with this myself, I'll try and find the source to give credit where it is due.
using System;
using System.Collections.Generic;
using System.Windows.Input;
namespace MyNamespace
{
public class OverrideCursor : IDisposable
{
static Stack<Cursor> s_Stack = new Stack<Cursor>();
public OverrideCursor(Cursor changeToCursor = null)
{
if (changeToCursor == null)
changeToCursor = Cursors.Wait;
s_Stack.Push(changeToCursor);
if (Mouse.OverrideCursor != changeToCursor)
Mouse.OverrideCursor = changeToCursor;
}
public void Dispose()
{
s_Stack.Pop();
var cursor = _stack.Count > 0 ? _stack.Peek() : null;
if (Mouse.OverrideCursor != cursor)
Mouse.OverrideCursor = cursor;
}
}
}
Now this disposable class can be used anywhere in your project to change the cursor temporarily.
using (new OverrideCursor())
{
//your code
}
This will change the cursor to anything you want by passing the cursor as parameter of the constructor, or nothing to use Cursors.Wait by default.
For the time needed to execute any code placed inside the using-block the cursor will be changed turning back to normal afterwards.
You can also initiate an object of the class without the using-block to set it indefinitely but you shouldn't forget to call Dispose() when done.
Edit: source: https://stackoverflow.com/a/675686/4579864
If want to do whatever you are doing in Set_Loading_Changed() before you connect to the database, you should call Invoke instead of BeginInvoke:
Set_Loading_Changed()
{
System.Windows.Application.Current.Dispatcher.Invoke(...);
}
What's the difference between Invoke() and BeginInvoke()
Related
First of all - I'm very low skilled programmer. I am building the foundation of a simple music app for my bachelor degree project. My question is regarding a internal clock method that is meant to increase an int value by 1 BPM times a minute.
I've created an internalClock class:
public class internalClock
{
// THIS METHOD WILL BE CALLED WHEN THE THREAD IS STARTED
public static void clockMethod()
{
int BPM = 135;
int clockTick = 1;
Form1 clockForm = new Form1();
// infinite loop
while (true)
{
if (clockTick == 8)
{
clockTick = 1;
}
else
{
clockTick++;
}
clockForm.metrobox.Text = clockTick.ToString();
Thread.Sleep(60 * 1000 / BPM);
}
}
}
This is how I managed to get an access to the RichTextBox itself:
public RichTextBox metrobox
{
get { return metroBox; }
set { metroBox = value; }
}
In the main 'Program.cs' I've written what's meant to start a separate thread to run the clockMethod until the program is closed:
// THREADING
// Create a thread
internalClock oClock = new internalClock();
Thread oClockThread = new Thread(new ThreadStart(internalClock.clockMethod));
// Start the internalClock thread
oClockThread.Start();
It's not updating the text in the RichTextBox. Also, if I call the clockMethod() without creating a separate thread for it - the application freezes. Sorry for my amateur question, I'm just getting started with C# (yeah.. my uni is useless). What am I doing wrong in my code?
So the above code has several problems, however I would encourage you to check out the Timer control that you can add to the form you want to do processing at a certain interval or in certain "ticks". MSDN Form Timer
With the timer you can remove that class you have and invoking a new thread, etc etc. I would read up on the Timer class in the given link and think about how you can re-work your application structure to fit that. The concepts for why that thread isn't working, etc, is frankly not that important for where you're at. I think you just need to focus for now on a tool that already does what you want it to do, which I believe is the Timer.
As a general note, you usually don't need to create a raw thread in .NET. As of .NET 4.0 you can access types called Tasks to perform multi-threaded logic and processing. If you find the need to do that later on, check that out. Task Type MSDN
I'm using .NET 4.0 (no async).
I'm looking for a combination of Monitor.Wait and Application.Run. I've browse object explorer but I can't find one.
Does it exists ? If not, what is the best way to implement it ?
I've still tried nothing because what I have in mind is very dirty. Something like this :
while (!(timeOutHasBeenReached || aLockHasBeenAcquired))
{
Application.DoEvents() ;
}
To avoid XY problem, let me introduce the final goal (relates to unit testing) :
using (ApplicationContext applicationContext = new ApplicationContext())
{
using (Control control = new Control() { Visible = true } )
{
// control will do something across the web
// When the control has done it, it will raise an event invoking applicationContext.Exit()
// As a web connection is not always timing trustfull I'd like
// to specify a timeout (or eventually abort it with a Monitor.Pulse)
Application.Run(applicationContext);
}
}
Control is a Winform component which I can't modify and I don't want to do Thread.Abort .
Can't you abort by doing control.Invoke(() => Application.Exit());? Or just control.Close(); or Dispose.
I am building a document management system currently and I was trying to change the cursor to a "waiting" cursor while the document is loading, pretty standard.
As per the MSDN documentation, I am using the following code:
System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait;
try
{
newPage.LoadForm(data);
}
finally
{
System.Windows.Input.Mouse.OverrideCursor = null;
}
The problem is, after LoadForm is finished, the cursor doesn't return to its normal state. I have debugged the program and the "null" line is being run so I have no idea what the problem is.
Any ideas?
If this is a long-running operation, you might consider moving this whole code to a Task (though in that case you'd have to dispatch the changes to the OverrideCursor property back to the main thread).
I tested this quickly with a Sleep simulating a long-running application and it seemed to work fine (I put this code in the window's constructor in an empty WPF application for testing).
Task.Factory.StartNew(() =>
{
Application.Current.Dispatcher.Invoke(() =>
System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Wait);
try
{
Thread.Sleep(5000);
}
finally
{
Application.Current.Dispatcher.Invoke(() =>
System.Windows.Input.Mouse.OverrideCursor = null);
}
});
WORKAROUND
You must set it to the cursor type you want instead of setting it to null. So, instead of setting it to null, set it to Arrow (I assume that is what you would want in Normal state).
So in finally block replace your code with this:
System.Windows.Input.Mouse.OverrideCursor = System.Windows.Input.Cursors.Arrow;
EDIT 1:
Try setting the Cursor to null at the end of try block if in case you do not want to use the workaround.
I've just "earned" the privilege to maintain a legacy library coded in C# at my current work.
This dll:
Exposes methods for a big legacy system made with Uniface, that has no choice but calling COM objects.
Serves as a link between this legacy system, and another system's API.
Uses WinForm for its UI in some cases.
More visually, as I understand the components :
*[Big legacy system in Uniface]* ==[COM]==> [C# Library] ==[Managed API]==> *[Big EDM Management System]*
The question is: One of the methods in this C# Library takes too long to run and I "should" make it asynchronous!
I'm used to C#, but not to COM at all. I've already done concurrent programming, but COM seems to add a lot of complexity to it and all my trials so far end in either:
A crash with no error message at all
My Dll only partially working (displaying only part of its UI, and then closing), and still not giving me any error at all
I'm out of ideas and resources about how to handle threads within a COM dll, and I would appreciate any hint or help.
So far, the biggest part of the code I've changed to make my method asynchronous :
// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
errMsg = "";
try {
Action<string> asyncOp = AsyncComparedSearch;
asyncOp.BeginInvoke(application, null, null);
} catch (ex) {
// ...
}
return 0;
}
private int AsyncComparedSearch(string application) {
// my actual method doing the work, that was the called method before
}
Any hint or useful resource would be appreciated.
Thank you.
UPDATE 1:
Following answers and clues below (especially about the SynchronizationContext, and with the help of this example) I was able to refactor my code and making it to work, but only when called from another Window application in C#, and not through COM.
The legacy system encounters a quite obscure error when I call the function and doesn't give any details about the crash.
UPDATE 2:
Latest updates in my trials: I managed to make the multithreading work when the calls are made from a test project, and not from the Uniface system.
After multiple trials, we tend to think that our legacy system doesn't support well multithreading in its current config. But that's not the point of the question any more :)
Here is a exerpt of the code that seems to work:
string application;
SynchronizationContext context;
// my public method called by the external system
public int ComparedSearch(string application, out string errMsg) {
this.application = application;
context = WindowsFormsSynchronizationContext.Current;
Thread t = new Thread(new ThreadStart(AsyncComparedSearchAndShowDocs));
t.Start();
errMsg = "";
return 0;
}
private void AsyncComparedSearch() {
// ANY WORK THAT AS NOTHING TO DO WITH UI
context.Send(new SendOrPostCallback(
delegate(object state)
{
// METHODS THAT MANAGE UI SOMEHOW
}
), null);
}
We are now considering other solutions than modifying this COM assembly, like encapsulating this library in a Windows Service and creating an interface between the system and the service. It should be more sustainable..
It is hard to tell without knowing more details, but there are few issues here.
You execute the delegate on another thread via BeginInvoke but you don't wait for it. Your try\catch block won't catch anything as it has already passed while the remote call is still being executed. Instead, you should put try\catch block inside AsyncComparedSearch.
As you don't wait for the end of the execution of remote method (EndInvoke or via callback) I am not sure how do you handle the results of the COM call. I guess then that you update the GUI from within AsyncComparedSearch. If so, it is wrong, as it is running on another thread and you should never update GUI from anywhere but the GUI thread - it will most likely result with a crash or other unexpected behavior. Therefore, you need to sync the GUI update work to GUI thread. In WinForms you need to use Control.BeginInvoke (don't confuse it with Delegate.BeginInvoke) or some other way (e.g. SynchronizationContext) to sync the code to GUI thread. I use something similar to this:
private delegate void ExecuteActionHandler(Action action);
public static void ExecuteOnUiThread(this Form form, Action action)
{
if (form.InvokeRequired) { // we are not on UI thread
// Invoke or BeginInvoke, depending on what you need
form.Invoke(new ExecuteActionHandler(ExecuteOnUiThread), action);
}
else { // we are on UI thread so just execute the action
action();
}
}
then I call it like this from any thread:
theForm.ExecuteOnUiThread( () => theForm.SomeMethodWhichUpdatesControls() );
Besides, read this answer for some caveats.
In my project, whenever a long process in being executed, a small form is displayed with a small animated gif file. I used this.Show() to open the form and this.Close() to close the form.
Following is the code that I use.
public partial class PlzWaitMessage : Form
{
public PlzWaitMessage()
{
InitializeComponent();
}
public void ShowSpalshSceen()
{
this.Show();
Application.DoEvents();
}
public void CloseSpalshScreen()
{
this.Close();
}
}
When the form opens, the image file do not immediately start animating. And when it does animate, the process is usually complete or very near completion which renders the animation useless. Is there a way I can have the gif animate as soon as I load the form?
Why not using threads? It's always good idea to learn something new.
You could simply put your "long process" in background thread, and use events to report to presentation layer, for example:
// in your "long process" class
public event Action<double> ReportCompletition;
// this method will start long process in separate background thread
public void Start()
{
Thread thread = new Thread(this.LongProcess);
thread.IsBackground = true;
thread.Start();
}
private void LongProcess()
{
// do something
// report 10% completition by raising event
this.ReportCompletition(0.1);
// do something more
this.ReportCompletition(0.5);
// ... and so on
}
This way, all you have to do is implement simple method in your Form/UI, which will consume this information.
public partial class MainApplicationWindow : Form
{
private LongProcessClass _longProcess;
public MainApplicationWindow
{
this.InitializeComponent();
this._longProcess = new LongProcessClass();
// bind UI updating method to long process class event
this._longProcess.ReportCompletition += this.DisplayCompletitionInfo;
}
private void DisplayCompletitionInfo(double completition)
{
// check if control you want to display info in needs to be invoked
// - request is coming from different thread
if (control.InvokeRequired)
{
Action<double> updateMethod = this.DisplayCompletitionInfo;
control.Invoke(updateMethod, new object[] { completition });
}
// here you put code to do actual UI updating,
// eg. displaying status message
else
{
int progress = (int) completition * 10;
control.Text = "Please wait. Long process progress: "
+ progress.ToString() + "%";
}
}
Of course, you can report anything you like from within long process. Be it completition rate, ready to display string messages, anything. You can also use events to report that long process has finished, broke, or any long process data you wish.
For more detailed information on this topic you might want to check MSDN tutorials on Threading and Events.
You should do the "long process" in a separate thread. I advice using the BackgroundWorker.
This will make your code more difficult though. One of the main reasons is, that you cannot communicate with the UI from the background thread.
Also note the warning from the linked page:
Caution
When using multithreading of
any sort, you potentially expose
yourself to very serious and complex
bugs. Consult the Managed Threading
Best Practices before implementing any
solution that uses multithreading.
If this is too difficult, you could call Application.DoEvents very frequent from your "long process" code.
Whatever you choose, this will make it possible for the user to interact with your form. For instance closing it. You should be aware of this.
Use the gif in a PictureBox, and have it open using Form pWait = new Form(); pWait.Show();