Gtk.Application.Invoke not working - c#

Application.Invoke occurs inside of a foreach loop, which I removed to save space. When bwSearchEngines completes THEN the ui updates with the code inside of the Invoke. How can this be corrected? it needs to update everytime the invoke is called, which is called inside of a foreach loop that I removed.
When the button is pressed the button click event occurs, which starts the task.
lblStatus is a label on a statusbar, tvResults is a TreeView, and OnBtnSearchClicked is a button click event
To be clear, I am running Gnome 3.4.2 on Debian wheezy, NOT Windows. This is not a Windows app. I am using MonoDevelop 3.0.3.2 and Gtk# 2.12
public void bwSearchEngines()
{
//a couple foreach loops removed to save space
Application.Invoke(delegate {
lblStatus.Text = (engines.listSearchSesults.Count+1).ToString();
tvResults.Model = lsTorrents;
});
}
protected void OnBtnSearchClicked (object sender, EventArgs e)
{
lsTorrents.Clear(); //first remove data from TreeView before populating it
btnSearch.Visible = false; //when a search is started disable search button
Task.Factory.StartNew( () => {
bwSearchEngines();
}).ContinueWith(_ => btnSearch.Visible = true);
}

since no one wants to help I had to figure this out for myself. My solution is not what I wanted because it locks the ui! bwSearchEngines is called in the button click event and not in the started thread. so bwSearchEngines is called directly in the button event, which locks the ui until the function returns (function completes). this function is long running and shouldn't lock the ui BUT it does update like i wanted. Oh right after the Application.Invoke i had to add while(Application.EventsPending()) Application.RunIteration();
unfortunately this cannot work this way because bwSearchEngines will run really long, so blocking the ui is not an option but i must update the ui. what i have presented so far need to work together

Related

c# webBrowser.ReadyState will not achieve Complete state inside DocumentCompleted event?

I have a problem with my little c# project.
I need to somehow navigate through a site, performing a few simple actions on each page. My solution to it was along the lines of this:
private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
var button = webBrowser1.Document.GetItemById("next_page_button");
button.InvokeMember("click");
webBrowser1.Refresh();
//here's my ugly solution which works
do {} while (webBrowser1.ReadyState!=WebBrowserReadyState.Complete);
webBrowser1.Navigate("http://www.webtest.com/page3");
webBrowser1.Refresh();
//same method of waiting for loading, causes endless loop this time
do {} while (webBrowser1.ReadyState!=WebBrowserReadyState.Complete);
var images = webBrowser1.Document.GetElementsByTagName("img");
//and then I do stuff with all them images..
So basically my program detects that the webBrowser loaded a page just fine the first time with that ugly while loop, but then, after the navigate() command it enters the second loop and never comes out of it. How come?
I've checked and double checked everything in debug mode, going through every step.
I could use your advice on organizing this program better for sure. xD
After two years i don't know it would help!!
but for others, the main thread is getting busy with your while loop so webbrowser object can not do anything, you need to implement this
webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler((object sender, WebBrowserDocumentCompletedEventArgs arg) =>
{
/// do anything you want with webbrowser document.
})
or using Application.DoEvents(), this will make your main thread loop once and the webbrowser object load it's resources like javascripts files.

Button Click Event not updating textbox until Finished

Here's a C# code, What happens is when qsubmit button is clicked, program straight away displays "wait..!".
When I debug the program it is found that when I click and function executes textbox1.text = "Hello"; but doesn't updates textbox, it updates only when the control goes off the event function, when that happens value of textbox has already been changed to "wait..!". I want to know why it doesn't updates textbox instantly(If that would have done, I would have seen the text during Thread.Sleep())
private void Button_QSubmit_Click(object sender, EventArgs e)
{
textBox1.Text = "Hello";
Thread.Sleep(1000);
textBox1.Text = "Wait..!";
}
The UI thread is responsible to redraw the windows. So as long as you are doing this inside the UI Thread (e.g. a Button click event), the process is busy with your code and the window is not drawn.
A easy solution could be the use of an Timer. Just add an timer and in the button click you start it (e.g. you set itup to fire in 1 second).
The Timer Event then will simply set the Text.
https://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx shows details about the Timer class.
You are hanging the UI Thread by calling Thread.Sleep from the Main Thread (UI), to update the text box you have to let the UI thread do its job outside your function to update the UI..anyway call Application.DoEvents() before the sleep. But calling Application.DoEvents() is a bad design

Code in button click c# happens after the function finishes

I have some simple C# code that is triggered on a Button Press. The button press first clears some ListBoxes, then changes the text of a label, and then calls a function.
private void button1_Click(object sender, EventArgs e)
{
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox3.Items.Clear();
listBox4.Items.Clear();
label5.Text = "Getting links...";
process(url);
label5.Text = "Finished";
}
But the Lists are cleared and the label is changed after process() is finished executing. This ruins the purpose as I'm changing the label so that the user is aware that some action is taking place. How can I make the initial label change before the function process() finishes?
If your process method is long-running, it can cause UI freezing and prevent UI from redrawing - that's why you don't see your label text immediate update.
Simpliest way to achieve your goal - is call label5.Refresh() right after label5.Text = "Getting links...";, this will immediately cause invalidation and redrawing of label.
Or even you can call this.Refresh() if more than one control should be updated - this will update whole usercontrol or form owns your controls.
But note - if your process method runs a very long time (more than a 2-3 seconds for example) - you should consider doing it asyncroniously in thread separate from UI. It is considered as "good style" because it will not cause UI freezing.
You can use async keyword. Only when accessing the UI from different thread you have to use the Invoke
private async void button1_Click(object sender, EventArgs e)
{
await Task.Run(
() =>
{
this.Invoke((MethodInvoker)delegate
{
listBox1.Items.Clear();
listBox2.Items.Clear();
listBox3.Items.Clear();
listBox4.Items.Clear();
myLabel.Text = "Getting links...";
});
});
this.process(url);
await Task.Run(
() =>
{
this.Invoke((MethodInvoker)delegate { myLabel.Text = "Finished"; });
});
}
What about using a Task to run process(url) in a "thread" separated from GUI?
In this way GUI will stay responsive to the user ang got "refreshed", then, when your task ends, you just have to update GUI label.
When you have ops that must take a bit of time, you should always separate them from GUI. My two cents.
You have 2 options. either use a different thread to run process(url), or add before it Application.DoEvents().

C# Winforms: selective disabling of UI whilst a thread runs

I have a quite complex form that presents an option to run a script (our own type). Whilst it runs, I don't want to lock the UI completely, so I would like to start it in a thread. So far so good, but to prevent the user messing with things I need to selectively disable parts of the UI. I could recursively set Enabled = false and then Enabled = true when the thread ends. But this ignores the state of the control at the time of running (ie controls which were disabled for various reasons would be incorrectly re-enabled). Short of building a tree of booleans, is there some other way to block input (such as the GlassPane type in Java)?
Don't use DoEvents, it's evil.
Use a panel and add all the controls you want to disable in it. When the panel will be disabled, all inner controls will appear to be disabled but the value of their Enabled property won't be actually modified.
Here's a working example:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
// Disables UI elements using the panel
this.SetPanelEnabledProperty(false);
// Starts the background work
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(this.Worker));
}
private void Worker(object state)
{
// Simulates some work
System.Threading.Thread.Sleep(2000);
// Now the work is done, enable the panel
this.SetPanelEnabledProperty(true);
}
private void SetPanelEnabledProperty(bool isEnabled)
{
// InvokeRequired is used to manage the case the UI is modified
// from another thread that the UI thread
if (this.panel1.InvokeRequired)
{
this.panel1.Invoke(new MethodInvoker(() => this.SetPanelEnabledProperty(isEnabled)));
}
else
{
this.panel1.Enabled = isEnabled;
}
}
}
Could you use a panel populated with the controls you want disabling while the script runs, then re-enable the panel when the script has ended.
Alternatively you could start a Process for the script.
You can solve this either using the Application.DoEvents() method, or you have to write a delegate which invokes the corosponding control.
I think the Application.DoEvents() would be the simplest way.
You should call Application.DoEvents() in the loop on your thread.
For the delegate version, you find here some information: http://msdn.microsoft.com/de-de/library/zyzhdc6b.aspx

How would I stop a thread, allow a UI event to be handled, and then "restart" the thread?

I have a form that appears as shown in the attached image. I have two parts of the form that concern this question: the TabControl, and the Panel, as shown in the image. It should be noted that the panel is NOT within the TabControl.
My situation is that I have a thread that executes continuously when the button, displayed in melt-your-eyes green in the Panel, is clicked. The thread polls the device which I'm interfacing with and updates the controls in the "Status" GroupBox at the bottom of the TabControl. When the user clicks on a control in the TabControl (tabControl_Enter event), I trigger a ManualResetEvent which lets the thread finish its iteration so that I can perform the IO required by the clicked control. The code to to suspend the thread is as follows:
private void StopSynchThread()
{
synchWaitHandle.Reset();
//various UI changes
}
private void updateSynchStat()
{
while (true)
{
synchWaitHandle.WaitOne();
try
{
updateSynch();
}
}
What I would like to do is then restart the thread automatically, instead of by button press, as is currently done. What I'm trying to do is avoid having to restart the thread by conditionally calling StartSynchThread() within each of the "bazillion" UI event handlers. StartSynchThread() is defined as:
private void StartSynchThread()
{
synchWaitHandle.Set();
}
Is there a precedent or decent paradigm for handling this? Without any concept of how to do so, I was thinking that I could alter my function that performs the IO with the device to generate an event after it gets a response from the device, but that seems inelegant.
Any ideas? I appreciate your insights. Thanks.
If you really can fire it off with a simple button click, you ought to be able to just put a timer on the form that will periodically check for the right conditions and then "push" the button (call synchWaitHandle.Set();) automatically.

Categories