Why Won't Control Update/Refresh Mid-Process

Why won't control update/refresh mid-process

If you're doing your processing on the UI thread, it won't be able to do anything else (like redraw updated labels) while the processing is running. So for instance, if the processing is happening because the user clicked a button and is triggered by the button click handler (without explicitly placing it on another thread), it's running on the UI thread. Even though you update the label's text, it doesn't get drawn until it receives a paint message, at which point it's probably busy doing your processing.

The answer is to do long-running processing on a separate thread. The hack (IMHO) is to use Application.DoEvents to let the UI thread do some UI stuff during your processing. If you put one of those after updating the label and before you start your processing, odds are pretty high the label will get repainted. But then, during the processing, no further paint events can get processed (leading to half-drawn windows when someone moves another app window over your app and back, etc.). Hence my calling it a hack (even though, er, um, I've been known to do it :-) ).

Edit Update based on your edits:

Re

So I guess the "processing" is taking place on the UI thread but eventhandler is invoked on it's own thread...

I'm assuming DoSomeProcess is triggered from the UI thread (e.g., in direct response to a button click or similar). If so, then yes, your processing is definitely on the UI thread. Because TriggerProcessStarted triggers your callback asynchronously via BeginInvoke, you have no idea when it will run, but in any case your code then immediately launches into processing, never yielding, so no one else is going to be able to grab that thread. Since that's the UI thread, the call to the delegate will block on the Invoke call setting the label's text, whereupon it has to wait for the UI thread (which is busy processing). (And that's assuming it's scheduled on a different thread; I couldn't 100% convince myself either way, because Microsoft has two different BeginInvokes -- which IIRC one of the designers has acknowledged was a Really Dumb Idea -- and it's been a while since I fought with this stuff.)

If you make the TriggerProcessStarted calls to your callbacks synchronous, you should be okay. But ideally, schedule the processing (if it's not doing UI) on its own thread instead.

Refreshing Controls in runtime

Thats because the data is being read in the UI thread. You will have to spawn a new thread and load data in that, thus freeing the UI thread for updates.

As Alexei suggested here is the bit of explanation:

Sample Image

Note that the UI thread is blocked as long as UI update is being performed in usual process, whereas in multithreaded process, background worker does all the updation all you need to take care of is the Syncing.

Please modify the code as follows and let me know:

public void Read_in()
{
BackgroundWorker backgroundWorker1 = new BackgroundWorker();
backgroundWorker1.DoWork += new DoWorkEventHandler(backgroundWorker1_DoWork);
backgroundWorker1.RunWorkerAsync();

}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
using (StreamReader sr = new StreamReader("in.txt"))
{
while (!sr.EndOfStream)
{
Data d = new Data
{
a = sr.ReadLine()
};
if(this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate
{
_list.Add(d);
Controls.Add(d.pb);
});

}
else
{
_list.Add(d);
Controls.Add(d.pb);

}
}
}
}

Inherited control won't refresh after visual properties changed

A couple things to check here.

Are all of your MLabels referring to the same version? (probably)

How are you setting background of the MLabel control, is it a change to the default background color?

How are you changing the existing MLabels, are you setting them manually in the code, or are you relying on the default background color?

Also, check your winform code. If the designer code sets the MLabel background color explicitly, then this will override any defaults the control may have. If that is the case, then you will need to either remove the background color setting so that it uses the default, or you will have to change each one manually.

If the above all seems correct, then some code and/or a little more information would be useful here.

Updated Answer after seeing actual code:

In CustomControl1 you will want to do something like this:

 System.Drawing.Color _backColor = System.
protected override System.Drawing.Color BackColor
{
get{return _backColor;}
set{_backColor = value;}
}

In the Form1.Designer.cs remove the lines that set the BackColor. These are explicitly setting the backcolor and not allowing a default color

this.customControl11.BackColor = System.Drawing.Color.Black;

Force GUI update from UI Thread

At first I wondered why the OP hadn't already marked one of the responses as the answer, but after trying it myself and still have it not work, I dug a little deeper and found there's much more to this issue then I'd first supposed.

A better understanding can be gained by reading from a similar question: Why won't control update/refresh mid-process

Lastly, for the record, I was able to get my label to update by doing the following:

private void SetStatus(string status) 
{
lblStatus.Text = status;
lblStatus.Invalidate();
lblStatus.Update();
lblStatus.Refresh();
Application.DoEvents();
}

Though from what I understand this is far from an elegant and correct approach to doing it. It's a hack that may or may not work depending upon how busy the thread is.

Why does a function not run procedurally

It does indeed run synchronously on the same thread but the UI thread cannot both sleep and hide/show the TextBox simultaneously.

A single thread cannot do two things simultaneously.

Button.Text is changing after Form is visible

Added

  btnItemConfigForm.Update();

under

var itemConfigBtnText = btnItemConfigForm.Text;
btnItemConfigForm.Text = "Waiting...";

This updates the button Control before moving on to initialising and showing the form.

Activate updated service worker on refresh

I wrote a blog post explaining how to handle this. https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68

I also have a working sample on github. https://github.com/dfabulich/service-worker-refresh-sample

There are four approaches:

  1. skipWaiting() on installation. This is dangerous, because your tab can get a mix of old and new content.
  2. skipWaiting() on installation, and refresh all open tabs on controllerchange Better, but your users may be surprised when the tab randomly refreshes.
  3. Refresh all open tabs on controllerchange; on installation, prompt the user to skipWaiting() with an in-app "refresh" button. Even better, but the user has to use the in-app "refresh" button; the browser's refresh button still won't work. This is documented in detail in Google's Udacity course on Service Workers and the Workbox Advanced Guide, as well as the master branch of my sample on Github.
  4. Refresh the last tab if possible. During fetches in navigate mode, count open tabs ("clients"). If there's just one open tab, then skipWaiting() immediately and refresh the only tab by returning a blank response with a Refresh: 0 header. You can see a working example of this in the refresh-last-tab branch of my sample on Github.

Putting it all together...

In the Service Worker:

addEventListener('message', messageEvent => {
if (messageEvent.data === 'skipWaiting') return skipWaiting();
});

addEventListener('fetch', event => {
event.respondWith((async () => {
if (event.request.mode === "navigate" &&
event.request.method === "GET" &&
registration.waiting &&
(await clients.matchAll()).length < 2
) {
registration.waiting.postMessage('skipWaiting');
return new Response("", {headers: {"Refresh": "0"}});
}
return await caches.match(event.request) ||
fetch(event.request);
})());
});

In the page:

function listenForWaitingServiceWorker(reg, callback) {
function awaitStateChange() {
reg.installing.addEventListener('statechange', function () {
if (this.state === 'installed') callback(reg);
});
}
if (!reg) return;
if (reg.waiting) return callback(reg);
if (reg.installing) awaitStateChange();
reg.addEventListener('updatefound', awaitStateChange);
}

// reload once when the new Service Worker starts activating
var refreshing;
navigator.serviceWorker.addEventListener('controllerchange',
function () {
if (refreshing) return;
refreshing = true;
window.location.reload();
}
);
function promptUserToRefresh(reg) {
// this is just an example
// don't use window.confirm in real life; it's terrible
if (window.confirm("New version available! OK to refresh?")) {
reg.waiting.postMessage('skipWaiting');
}
}
listenForWaitingServiceWorker(reg, promptUserToRefresh);

Page still refreshes after wrapping the repeater in an update panel

Pretty sure an <asp:HyperLink> isn't going to get you a partial update, it renders to HTML as an <a href=".."> tag. You'll need a control that actually causes a postback, an <asp:Button> or <asp:LinkButton>.

RichOutputText won't update programmatically

You have to trigger partial page update, so UI can catch up with the state.

AdfFacesContext.getCurrentInstance().addPartialTarget(inputText);

Btw, you better switch to actionListener instead of action.



Related Topics



Leave a reply



Submit