how to use thread to capture screen after scrolling in UI - c#

I have a windows form which hold a web browser control, that web browser will change it's position automatically in fixed positions
So first I set the navigate to position X then I will take a capture from my form then change the position to Y and also take another capture.
My Issue is that I use the navigation to position like
webBrowser1.Navigate("javascript:window.scroll(0," + X + ");");
So I should wait tell the ui change the position then Do the capture code, after finish I should re-change the position to Y same way and wait tell the UI finish then capture.
I try to use background worker but it didn't support me as well I also try Threading but as I;m not so good dealing with Threading my ui didn't navigate before capture.
I use Threading like:
ThreadStart captureFunc = new ThreadStart(CaptureScreen);
Thread captureThread = new Thread(captureFunc);
captureThread.Start();
while (!doneVal)
{
}
captureThread.Abort();
while CaptureScreen is my capture function and doneVal is a value with default false and changed to true after capture.
any help will be appreciated.

The WebBrowser-control offers Events, such as the Navigated-Event.
You can use this to determine the end of the navigation of the WebBrowser-control:
webBrowser1.Navigated += NavigatedEventHandler; //use in constructor for example
...
private void NavigatedEventHandler(object sender, NavigatedEventArgs e){
//perform actions here
}

Related

C# Winforms Livecharts: Fire Event when rendering of CartesianChart is finished

I am using LiveCharts.WinForms.CartesianChart to render a large amount of points:
myChart.Zoom = ZoomingOptions.X;
myChart.Pan = PanningOptions.X;
myChart.Series.Add(new LineSeries
{
Values = chartValuesScores,
Fill = System.Windows.Media.Brushes.Transparent,
PointGeometrySize = 5
});
myChart.AxisX.Add(new Axis
{
Labels = labels
});
What I want to do is to display some kind of a progressbar and stop the time LiveCharts needs to render this points. But it seems that LiveCharts renders the points asynchronously. That means that after running the code above, it continues running other code lines and exits the function.
Thus, my question is: Is there a way to detect that LiveCharts.WinForms.CartesianChart is finished with rendering? I could not find an event or something else.
I found this while checking the docs: https://lvcharts.net/App/examples/v1/wpf/Events
It lists Chart.UpdaterTick as one of the events. That events seems to fire when the graph has finished loading the data and had rendered it on screen, I believe what you were looking for?
I've tested myself and appears to work as I expect.
There is an CartesianChart.Loaded event, which is fired after the chart is rendered.
myChart.Loaded += myChart_Loaded;
private void myChart_Loaded(object sender, RoutedEventArgs e)
{
// chart is rendered
}

How to correctly pause/delay Windows Forms application

I am a beginner to the OOP and the C#.
I am working on a quiz game using the Windows Forms.
My problem is related to two classes, the form and the game logic.
I have a basic UI with classic Froms controls. Take a look.
The thing I want to achieve is, when a player presses any answer button, it will higlight that pressed button by red or green color, depending on if it is right or wrong answer. After changing the color I want the program to wait for a while and then go to the next question.
Probelm is, that I don´t know how to achieve this correctly. I don´t know how to work with threads and how exactly the Form app works related to threads. Should I use a thread sleep or a timer or a async?
I will show you the method in game logic class which should handle this.
public static void Play(char answer) //Method gets a char representing a palyer answer
{
if (_rightAnswer == answer) //If the answer is true, the button should become green
{
Program.MainWindow.ChangeBtnColor(answer, System.Drawing.Color.LightGreen);
_score++;
}
else //Otherwise the button becomes Red
{
Program.MainWindow.ChangeBtnColor(answer, System.Drawing.Color.Red);
}
//SLEEP HERE
if (!(_currentIndex < _maxIndex)) //If it is the last question, show game over
{
Program.MainWindow.DisplayGameOver(_score);
}
else //If it is not the last question, load next question and dispaly it and finally change the button color to default
{
_currentIndex++;
_currentQuestion = Database.ListOfQuestions.ElementAt(_currentIndex);
_rightAnswer = _currentQuestion.RightAnswer;
Program.MainWindow.DisplayStats(_score, _currentIndex + 1, _maxIndex + 1);
Program.MainWindow.DisplayQuestion(_currentQuestion.Text);
Program.MainWindow.DisplayChoices(_currentQuestion.Choices);
}
Program.MainWindow.ChangeBtnColor(answer, System.Drawing.SystemColors.ControlLight);
}
I don´t want to completely block the UI but also I don´t want users to make other events by pressing other buttons during the pause. Because it will result in improper run of app.
If the program is really simple and you do not want to implement Threads I would suggest using Timer. Just start your Timer when clicking answer button. Your timer should contain function which would stop itself after some time and do other actions needed (e.g. pick another question).
Once the user has selected an answer you can disable all the buttons so they can't press anything else.
Then start a timer so you don't block the UI. The timer is basically a thread but handles all the threading for you so you don't have to worry about that aspect.
When the timer reaches the desired delay stop it and fire an event to select the next question.
At //SLEEP HERE add this line of code
Timer timer = new Timer(new TimerCallback(timerCb), null, 2000, 0);
The 2000 is milliseconds and is the wait time, timerCb is a call back method.
Also under that disable all your buttons so new events wont be generated.
private void timerCb(object state)
{
Dispatcher.Invoke(() =>
{
label1.Content = "Foo!";
});
}
You can do whatever you want in the callback, however if you do something that would change anything in the UI, you need to use the Dispatcher like I have changing the label content.
Suspending execution in a GUI scenario is very easy thanks to await:
await Task.Delay(2000);
This does not block the UI.
You should research what await does and how to use it. If you have never heard about it and are programming WinForms you are doing something wrong.
No timers or threads are needed. No callbacks, no Invoke.

Generate a 'Busy' or 'Working' dialogue box while a loop runs

I'm working with MSVS2010 and am having trouble creating a status bar or status strip. I have a loop that does some things and runs some functions. It's a "while" loop. All I need to do is display some sort of form that says "busy..." or "working.." while inside of this loop. Does anyone have specific step by step instructions of how to accomplish this? I have looked at tutorials and examples online but I am not getting a clear idea of how to accomplish this. Any help on this would be great. Thanks in advance.
You could use a label for it.
Just add a label and name it for example stateLabel
Then in your code just do smth like this :
stateLabel.text = "Working..."; //Change the text of the Label
while(statement = true) //Your Loop
{
//Do your work
}
stateLabel.text = "Finished work";
Something simple is to use a progress bar with the 'marquee' style property, good to make user waiting on something.
So set the' marquee' property before the loop, and then you can back to default value and/or hide this progress bar after going out through the loop.
Am I enough clear or do you want some code example?
You could do something simple like change your cursor:
//change cursor to wait cursors
this.ForceCursor = Cursors.Wait;
//do loop
while(true)
{//do work}
//change the cursor back to regular arrow when work is completed
this.ForceCursor = Cursors.Arrow;
Or, so long as you aren't doing anything with UI controls in the while loop, you could do the loop on another thread. Just put a progress bar somewhere in your window (call it myProgBar), and make it indeterminant if you do not know how long the loop will take. Here is kind of how I would do it:
//create instance of loading window
YourLoadWindow loadWin = new YourLoadWindow();
//Create a thread that will do our loop work.
Thread t = new Thread(new ThreadStart(() =>
{
//do our looping;
while (true) {//do work}
//when loop is done, we want to hide the loading window
//but we created it on a different thread, so we must use its dispatcher to do
//the work from this thread
loadWin.Dispatcher.Invoke(new Action(() => { loadWin.Close(); }));
}));
//show load window
loadWin.Show();
//start doing our work
t.Start();

Progress indicator in C# Winforms

I have created some basic applications using windows forms C#.
What I am trying to achieve is that I have some task taking place inside a function. While executing that task I need to display a message box (with no buttons) with the text "Configuring...". I also need to blink this text. How can I do that?
Do I need to have another form for this? After completing this task this form needs to be hidden or closed?
I have googled this but couldn't see an answer, may be because of my unclear question in google.
If you really need a progress indicator you have to do as toATwork said, and do a Background worker
However, it is not a really async task, so you might find it hard to make it work properly
If you finally don't care about the message, and just need to show the users that something is happening, you can always use:
// To start
Cursor cursor = Cursor.Current;
Cursor.Current = Cursors.WaitCursor;
// To finish
Cursor.Current = Cursors.Default;
This will just put the mouse cursor in "loading", but it might work for you
You can use a label on your form and change its text in function Body.
{
//your function body
label.Text="Configuring";
}

Paragraph.BringIntoView() works only when focused

I am working on a text editor that is based on RichEditBox. I have implemented functionality "Go to line" which eventually resolves to
TextPointer.Paragraph.BringIntoView();
Along with this I also set the caret position.
What I found out is that BringIntoView only works when I click on the RichEditBox first (focus it). Otherwise it seems to get ignored. I can see that the caret position has been adjusted by the code around BringIntoView though.
Does anybody know what is the reason/nature of that problem? How can I overcome it?
Found a workaround for this, not sure if it will work in a pure WPF environment, in my case I'm running WPF inside a mainly Windows Forms solution using WPF UserControls where needed.
Instead of invoking BringIntoFocus() immediately, defer it to a later moment by adding it to a queue that gets handled by a timer. For example:
System.Windows.Forms.Timer DeferredActionTimer = new System.Windows.Forms.Timer() { Interval = 200 };
Queue<Action> DeferredActions = new Queue<Action>();
void DeferredActionTimer_Tick(object sender, EventArgs e) {
while(DeferredActions.Count > 0) {
Action act = DeferredActions.Dequeue();
act();
}
}
In your forms constructor, or in the OnLoad event add:
DeferredActionTimer.Tick += new EventHandler(DeferredActionTimer_Tick);
DeferredActionTimer.Enabled = true;
Finally, instead of calling TextPointer.Paragraph.BringIntoView(); directly, call it like this:
DeferredActions.Enqueue(() => TextPointer.Paragraph.BringIntoView());
Note that the Windows Forms timer kicks events off in the main thread (via the message pump loop). If you have to use another timer you need a bit of extra code. I'd recommend you to use System.Timers.Timer rather than the System.Threading.Timer (it's a little more thread-safe). You would also have to wrap the action in a Dispatcher.Invoke structure. In my case, the WinForms timer works like a charm.
Can't you just give the RichTextBox(?) focus first then, using Keyboard.Focus(richTextBox) or richTextBox.Focus()?

Categories