|
And now you start talking about Refresh; are you going to enumerate all the Control methods
one by one?
I have never used Refresh() and never felt the need to use it; I use Invalidate().
|
|
|
|
|
Hello Luc!
I also prefere using Invalidate(), mainly because of it's higher flexibility (additional parameters).
I think the only reason using Refresh(), which I can think of, would be if more than one GDI changing should be shown in one callstack.
Sometimes for that purpose, I see code where people use Invalidate() + DoEvents(), which I would count as bad practice. Here the usage of Refresh() would be much better.
All the best,
Martin
|
|
|
|
|
Hi Martin,
we agree on the subject of Refresh() and DoEvents().
I seldom use DoEvents, I mainly use it when a dialog gets closed before executing
a (short!) action in order to get the underlying form being redrawn as soon as possible
(so there is no risk of creating nested DoEvent calls).
PS: congrats on your diamond icon!
|
|
|
|
|
There are usually two stages to rendering controls on the form. The first is measurement and the second is rendering. When you add a control to the form it signals that the content has changed and it needs to recalculate everything. Once things have been measured the controls can be redrawn.
This has the downside that it's quite slow when adding lots of controls. What SuspendLayout and ResumeLayout offer is a way to halt re-calculating the layout of the form everytime a control is added, so if you know you're going to be adding a lot of controls you can half the recalculations and then only perform them once when you've finished adding the last one.
So:
this.SuspendLayout();
for (int i = 0; i < 1000; i++)
{
var textBox = new TextBox();
textBox.Size = new Size(120, 24);
textBox.Location = new Point(0, 24 * i);
this.Controls.Add(textBox);
}
this.ResumeLayout();
|
|
|
|
|
The following giving problems (I m using VC# express.) I get the MessageBox but after that, the application hangs up (on me). Can anyone help.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Drawing;
namespace Thread191
{
class Listing191AND192 : Form
{
Label lblInfo2 = new Label();
Button btStart = new Button();
public Listing191AND192()
{
Thread currThread = Thread.CurrentThread;
lblInfo2.Location = new Point(15, 10);
lblInfo2.Size = new Size(300, 100);
lblInfo2.Text = "Hi";
currThread.Name = "Main thread";
btStart.Location = new Point(300, 340);
btStart.Text = "Start";
btStart.Click += new EventHandler(this.StartIt);
this.Text = "Listing191";
this.Controls.Add(lblInfo2);
this.Controls.Add(btStart);
this.Size = new Size(800, 600);
}
void StartIt(object sender, EventArgs e)
{
lblInfo2.Text = "Thread 2 started from " + Thread.CurrentThread.Name + "...\n";
Thread thdTest = new Thread(new ThreadStart(DoIt));
thdTest.Name = "Thread 2";
thdTest.Start();
lblInfo2.Text += Thread.CurrentThread.Name + " sleepin....\n";
Thread.Sleep(2000);
lblInfo2.Text += Thread.CurrentThread.Name + " waking...\n";
thdTest.Join();
lblInfo2.Text += "Thread 2 ended...\n";
}
void DoIt()
{
Thread.Sleep(1000);
MessageBox.Show(Thread.CurrentThread.Name);
lblInfo2.Text += "Hello from " + Thread.CurrentThread.Name + "\n";
}
static void Main(string[] args)
{
Application.Run(new Listing191AND192());
}
}
}
|
|
|
|
|
You can't change UI controls on a thread other than the one that created it. Thus, setting the lblInfo2.Text inside DoIt() is what's causing the problem, since DoIt is being run on a thread other than the one that created the lblInfo2 control.
If you need to do background work and provide updates to the UI in response to some background work progress, have a look at the BackgroundWorker component.
|
|
|
|
|
but isn't thdTest.Join() supposed to make the currentThread wait until Thread 2 finishes with DoIt() method(including wrinting on lblInfo2).
|
|
|
|
|
Join will make the threads join in the "StartIt" method, but the "DoIt" function is running on a different thread.
|
|
|
|
|
I am sorry if I am asking too many questions.
When you say "will make the threads join in the StartIt" which threads are you referring to.
Pl correct me if I am wrong.
What I gathered is that StartIt() is being run by the Main thread and DoIt() is being run by the background thread(Thread 2) and when I use thdTest.Join() the Main Thread stops executing and waits for Thread 2 to finish its job (including writing on lblInfo2) and when Thread 2 is done, then the Main thread picks up from there again and finishes its job.
I have one more question
When I press the button the first thing I see is the MessageBox
Why isn't the label dispalaying the first line of StartIt()
lblInfo2.Text = "Thread 2 started from " + Thread.CurrentThread.Name + "...\n";
before I see the MessageBox
|
|
|
|
|
humayunlalzad wrote: When you say "will make the threads join in the StartIt" which threads are you referring to.
The main UI thread and the thdTest thread.
humayunlalzad wrote: What I gathered is that StartIt() is being run by the Main thread and DoIt() is being run by the background thread(Thread 2) and when I use thdTest.Join() the Main Thread stops executing and waits for Thread 2 to finish its job (including writing on lblInfo2) and when Thread 2 is done, then the Main thread picks up from there again and finishes its job.
That's correct. It will block the UI thread (e.g. freeze the UI) until DoIt() is done executing.
humayunlalzad wrote: Why isn't the label dispalaying the first line of StartIt()
Because the other thread may or may not have set it yet; threads don't execute in any particular order. So if the label was being set in one thread, and looked at in another thread, it's possible that by the time one thread looks at the value, it's not yet set for the other thread.
This is all complex stuff. It gets only more complex once you start having to think about locks to protect variables and data shared between threads.
Here's how you make it simple: don't share memory between threads. That means don't share variables or other data between threads. If another thread needs some data from one thread, make a copy of the data and send him the copy.
|
|
|
|
|
Judah Himango wrote: Thus, setting the lblInfo2.Text inside DoIt() is what's causing the problem
Actually, that won't necessarily cause the problem. Yes, it's a no-no, but often we won't see the actual effects that causes.
I'm more inclined to think it's the MessageBox being shown from the background thread. The MessageBox piggy-backs its message loop on the thread it is called from, and if that's a background thread I have seen all kinds of strange and upsetting behavior from the MessageBox in that situation.
So, my advice is to get rid of the message box. And fix the cross-thread issues. In C# both solutions are trivial.
It has become appallingly obvious that our technology has exceeded our humanity. - Albert Einstein
|
|
|
|
|
Either way, he needs to remove UI code from the background thread.
|
|
|
|
|
Removing the messagebox is not helping, but when I remove the lblInfo2 from the DoIt() method, the problem gets solved.
The question is how do I make DoIt() method write on lblInfo2.
|
|
|
|
|
Hi,
if you need to access a Control from a thread that did not create the Control, then
you need to use Control.InvokeRequired and Control.Invoke()
you can find many examples of this everywhere, including in CP articles; there
is an example at the end of my Sokoban article.
|
|
|
|
|
Use this instead:
lblInfo2.BeginInvoke((ThreadStart)delegate
{
lblInfo2.Text = "whatever";
});
That will invoke the text setter on the correct thread.
If you find yourself doing lots of Control.BeginInvoke or Control.Invoke calls, opt instead to use a BackgroundWorker component. Much simpler and cleaner.
|
|
|
|
|
Thanx guys, this thing is a lil bit tough for me rt now. I will get back to the prob later.
|
|
|
|
|
Ok, continuing on the context of executing reflected code...
Is there any way of adding a web reference in runtime?
Alternatively, what options do I have on invoking a web service without adding the web reference?
Thank you
Gonçalo A.
|
|
|
|
|
Well, you could always create the SOAP request yourself and send it yourself.
|
|
|
|
|
Hi
How can read the characters from Stream and write to a directory. Could any one please tell me.
I tried with this but I am getting error: UnAuthorizedException. Could anyone tell me where is wrong here?
string location = di.FullName + "/ec284451";
DirectoryInfo pub_di = new DirectoryInfo(location);
pub_di.Create();
FileStream fwrter = new FileStream(location, FileMode.Open);
// Allocate byte buffer to hold file contents
byte[] inData = new byte[4096];
// loop through reading each data block
// and writing to the request stream buffer
int bytesRead = respStream.Read(inData, 0, inData.Length);
while (bytesRead >0)
{
fwrter.Write(inData, 0, bytesRead);
bytesRead = respStream.Read(inData, 0, inData.Length);
}
Thanks
Aruna.G
|
|
|
|
|
I think you'll need to create file objects in the directory, writing the bytes to those files. Files can be created using the File.Create static method.
|
|
|
|
|
You can only write on the server, not the client, and ASP.NET is not allowed access to the file system above the root of the web app. So, you have to write to locations underneath the root of your website.
Christian Graus - Microsoft MVP - C++
"also I don't think "TranslateOneToTwoBillion OneHundredAndFortySevenMillion FourHundredAndEightyThreeThousand SixHundredAndFortySeven()" is a very good choice for a function name" - SpacixOne ( offering help to someone who really needed it ) ( spaces added for the benefit of people running at < 1280x1024 )
|
|
|
|
|
In C# how would you do this? Can you?
I am working in C++/CLI with Windows Forms. No one in the C++/CLI forum was aware of a way to tell where the mouse is pointing when the helpprovider event is called.
I want to have my compiled html help point to a topic specific to where the mouse is pointing (like as a menu item) but I can't seem to determine which control the mouse is hovering over.
My C++/CLI code is below.
private: System::Void FrmMain_HelpRequested(System::Object^ sender, System::Windows::Forms::HelpEventArgs^ hlpevent)
{
Point pt = this->PointToClient(hlpevent->MousePos);
Control^ requestingControl = dynamic_cast(sender);
Control ^ctrl = this->pt;GetChildAtPoint(pt);
Control ^ctrl2 = this->pt;ActiveControl;
Point ptMI = this->menuMainForm->PointToClient(hlpevent->MousePos);
Control ^ctrlMI = this->menuMainForm->GetChildAtPoint(ptMI);
Point ptMenuHelp = this->miHelp->DropDown->PointToClient(hlpevent->MousePos);
Control ^ctrlMenuHelp = this->miHelp->DropDown->GetChildAtPoint(ptMenuHelp);
if( File::Exists(this->pt;helpProvider->HelpNamespace ) == true)
{
Help::ShowHelp(this, this->helpProvider->HelpNamespace);
}
}
ctrl is the form itself and crtl2 is the last active mdichild in my application.
requestingControl returns the form (same as ctrl)and not the item the mouse is over.
ctrlMI and ctrlMenuHelp are undefined.
Hope someone can help
Programmer
Glenn Earl Graham
Austin, TX
modified on Monday, January 07, 2008 4:03:51 PM
|
|
|
|
|
Hi Glenn
I tried out a few things and here's what I came up with.
If you've got a MenuStrip (e.g. File, Edit, View, etc.) and you're trying to see if the mouse is over a particular menu item (e.g. the File->Exit), you can do it like this:
Point localPoint = fileMenuItem.DropDown.PointToClient(hlpevent.MousePos);
if(exitMenuItem == fileMenuItem.DropDown.GetItemAt(localPoint)) Does this help?
|
|
|
|
|
Wow. Thanks. I updated my code. I tried it but I got an undefined for the control.
Programmer
Glenn Earl Graham
Austin, TX
|
|
|
|
|
I'm not sure I understand. You got null back for the control returned?
|
|
|
|