|
OK thank you. I have to do it for work
|
|
|
|
|
I'm creating a WinForms application.
For a log running action I want to create some form in screen and write text to it from different methods allowing user to see the progress.
Any idea how to implement this ?
Where to find sample code which implements this ?
Andrus
|
|
|
|
|
You could use an event to trigger an update on a control (label, textbox, progressbar, etc). Then give the event argument some type of identifier so you know where you are in the process.
|
|
|
|
|
Thank you.
I create the following login class. However, login form does not show messages.
What i'm doing wrong ?
How to force login form to scroll when all lines are filled in form ?
using System;<br />
using System.Windows.Forms;<br />
using System.IO;<br />
<br />
class main {<br />
[STAThreadAttribute()]<br />
public static void Main() {<br />
<br />
LoginForm f = new LoginForm();<br />
f.Show();<br />
<br />
f.Writeln("Login message 1");<br />
f.Writeln("Login message 2");<br />
MessageBox.Show("");<br />
<br />
}<br />
<br />
class LoginForm : Form {<br />
<br />
int vpos = 0;<br />
<br />
public void Writeln(string s) {<br />
<br />
Label l = new Label();<br />
l.Visible = true;<br />
l.Text = s;<br />
vpos += 20;<br />
}<br />
}<br />
}
Andrus
|
|
|
|
|
In this example, you need to add the label to the controls collection of the form. But I would use a listbox so you can scroll through each. Using just the label, you'll never see "Login messge 1", for instance.
Take a look at events and delegates. It's what you really want to use.
|
|
|
|
|
Yep, and in my opinion ListBox is the right control for collecting log strings.
My standard log method looks somewhat like this:
public void log(string s) {
if (s.Length!=0) s=DateTime.Now.ToString("hh:mm:ss.fff ")+s;
lb.Items.Add(s);
if (Control.ModifierKeys!=Keys.Control) lb.TopIndex=lb.Items.Count-1;
}
|
|
|
|
|
Thank you.
I created the following code.
Is this best way ?
using System;<br />
using System.Windows.Forms;<br />
using System.IO;<br />
<br />
class main {<br />
[STAThreadAttribute()]<br />
public static void Main() {<br />
<br />
LoginForm f = new LoginForm("Performing task x");<br />
<br />
for (int i = 0; i <= 100; i++) {<br />
f.Writeln("Login message " + i.ToString());<br />
}<br />
MessageBox.Show("");<br />
<br />
}<br />
<br />
class LoginForm : Form {<br />
<br />
ListBox lb;<br />
<br />
public LoginForm(string s) {<br />
Text = s;<br />
Left = 0;<br />
Top = 1000;<br />
Height = 500;<br />
Width = 2000;<br />
lb = new ListBox();<br />
lb.Dock = DockStyle.Fill;<br />
this.Controls.Add(lb);<br />
Show();<br />
}<br />
<br />
public void Writeln(string s) {<br />
<br />
lb.Items.Add(s);<br />
if (Control.ModifierKeys != Keys.Control) lb.TopIndex = lb.Items.Count - 1;<br />
}<br />
}<br />
}
Andrus
|
|
|
|
|
Does this work at all ?
Normally:
1. you create an instance of your main form inside the static Main method
2. you dont have Show() in a form's constructor
3. you pass the formk to Application.Run() which brings life to it (and does not return)
4. your main form organizes the remainder of the job; a good place to put some stuff is
in the Load event handler. Everything else typically is in handlers that react to
some event such as a button click, a timer tick, ...
That would also be what you get when you ask Visual Studio to create a new Windows
application. Yours looks like a Console application with a dead? form added to it.
|
|
|
|
|
> Does this work at all ?
I tried and it works OK.
> 1. you create an instance of your main form inside the static Main method
Yes, I create MDI parent form in my application.
Main() is for testing loginform() class only.
> 2. you dont have Show() in a form's constructor
Why not ?
I need to create and show login form using single command.
This works OK.
> dead? form added to it.
This form is not dead.
It shows login messages.
I it OK to use this Loginform call in MDI application ?
Andrus
|
|
|
|
|
AndrusM wrote: I it OK to use this Loginform call in MDI application ?
I dont know; I dont use MDI/SDI models. Sorry.
|
|
|
|
|
ListBox is only for WinForms application.
Every Winform application I have seen used SDI or MDI windows.
How can you create WinForm application without using SDI or MDI ?
Andrus
|
|
|
|
|
If SDI means you can see, read, operate on only one document or window, then I dont (unless
it happens to be a Console app).
If MDI is just the concept of working on more than one document at a time, then I am "using" MDI. If it involves special classes that support this, then I dont.
|
|
|
|
|
MDI means that there are parent window containing all other windows, having MDIPArent property set to true. Those other windows cannot moved outside of parent window.
Andrus
|
|
|
|
|
What type of application is your long running application service? Console App?
If it is a Console application then you can use the delegate event method mentioned, which when called posted the text passed as a param (keeping it simple)
If it is a service, is a windows form really the correct way to do it? manybe the Windiws Eventlog would be more appropriate.
If it is a windows application, look at Trace and Trace Listener (if I am thinking of the right things), the trace listener could access a windowow with a ListBox
Just ideas
|
|
|
|
|
I'm creating MDI Winforms application.
There is no trace listener which outputs text to winforms window visible for end user.
Also trace listeners work only when debugging application.
For this reason I need to create separate logging class.
Andrus
|
|
|
|
|
I understand that you are working in MDI, but what is your long running application? Is this the MDI app??
I assumed that the MDI app was a reporting tool
If it is long running are you sure this is appropriate as it screams service to me!
|
|
|
|
|
Luc,
thank you. Using your hint I created login form class below.
However I have the following issues with it:
1. Log message is shown only after messagebox is displayed.
How to force text to be displayed in login form immediately after calling Log method ?
2. Log window is displayed in top of screen.
Top = (int)(0.6 * (double)screen.WorkingArea.Height);
seems not working. How to show login form in lower part of screen ?
3. If there are more items than login area height, a scroll bar appears.
How to remove the scroll bar.
4. How to remove icon and all buttons from login form title bar ?
Andus.
using System;<br />
using System.Windows.Forms;<br />
using System.IO;<br />
<br />
class main {<br />
[STAThreadAttribute()]<br />
public static void Main() {<br />
<br />
Status s = new Status("Performing task x");<br />
s.Log("This text is not shown immediately");<br />
<br />
System.Threading.Thread.Sleep(8000);<br />
MessageBox.Show ("now it is shown");<br />
}<br />
<br />
public class Status : Form {<br />
<br />
ListBox lb;<br />
<br />
public Status(string title) {<br />
<br />
lb = new ListBox();<br />
lb.Dock = DockStyle.Fill;<br />
Controls.Add(lb);<br />
<br />
Screen screen = Screen.AllScreens[0];<br />
AutoScroll = false;<br />
FormBorderStyle = FormBorderStyle.FixedSingle;<br />
Text = title;<br />
Left = 0;<br />
Top = (int)(0.6 * (double)screen.WorkingArea.Height);<br />
Height = screen.WorkingArea.Height / 3;<br />
Width = screen.WorkingArea.Width;<br />
Show();<br />
}<br />
<br />
public void Log(string s) {<br />
lb.Items.Add(s);<br />
lb.TopIndex = lb.Items.Count - 1;<br />
}<br />
}<br />
}
Andrus
|
|
|
|
|
Hi,
1.
I am not surprised; you are doing it in a strange (probably wrong) way as I told you before.And it is only getting worse. You should not have the Sleep, dont do MessageBox if there is
something better (your form), dont include Show() in a form's constructor,
use Application.Run so you have a message pump, etc.
2.
A form's location is either automatic or user defined, depending on Form.StartPosition
3.
Normally the idea of logging is to have a record of the entire history.
If you dont like it, you could make the listbox taller, remove the oldest logs,
not use a listbox at all, etc
4.
read up on Form properties. If you set a sufficient number of them to false or "" you
can get rid of anything you dont want.
I must insist you study some more, and start doing things in a more conventional way;
otherwise you will have problems all over the place.
|
|
|
|
|
Luc,
1. This issue reproduction performs some task and exists.
It uses form only to show progress messages.
Since it does not need to enter to message bump it does not call Application.Run() method.
My actual MDI application calles Run() method for MDI parent form.
However, it encounters exactly the same issue.
So my questions were:
A. How to force listbox to show new item immediately, without entering wait state ?
B. How to force status window to continue display messages when I switch to other application and then back to my application ?
Current not responding appears and window stops updating.
2. StartPosition = FormStartPosition.Manual; fixes the issue. Thank you.
3. I close login window immediately after task is completed.
So I'm looking a way not to hold all messages in listbox and remove listbox scrollbar or to use some other method which does not waste memory.
4. After setting some properties to false, all icons from title bar disappear. Thank you.
Andrus
|
|
|
|
|
When I use ShowDialog directly from a form, it opens the second form and stops the first, but now I am trying do this by invoking it from a different thread with a timer in it and the call looks a bit like this now:
public partial class frmMain : Form
{
private delegate void ShowVoidDelegate();
private void ShowFrmList()
{
try
{
if (!FrmList.InvokeRequired)
{
FrmList.ShowDialog();
}
else
{
Invoke(new ShowVoidDelegate(ShowFrmList), null);
}
}
catch (Exception e)
{
Debug.WriteLine(e.ToString());
}
}
}
The problem now is, that frmMain doesn't wait anymore for the frmList form to close and executes all the code after the showdialog invoke inside frmMain.
How can I get the usual behavior back when using invoke, so that frmMain waits until frmList is closed ?
Thanks, Eike
|
|
|
|
|
Hi Eike,
if I understand you correctly, you have a main thread and a main form (obviously),
then have some job spun off into another thread, and all of a sudden that job needs
to interact with the user, hence wants to show a dialog, then has to continue with
its job.
I have three comments:
1.
The InvokeRequired/Invoke thing is all right; it operates in a synchronous mode, that is
Invoke will return only when the delegate it calls has finished. So that does not seem
to fit with your observation. I dont know what is wrong.
2.
There are several timer classes. I would recommend you look at the System.Windows.Forms.Timer
since that one fires on the main thread, so you probably would not need the Invoke stuff
at all.
3.
I am not fond of programs that throw modal dialogs at me without me asking them to do that.
If such app's functionality is anything less than exceptional, it will soon end up in
the trash bin.
Hope this helps.
|
|
|
|
|
Thanks, it is a compact framework project with several forms, and I want to control all the input and methods used in the different forms by an independent class, but maybe I just put all of it into the main form, if that is easier to manage after all.
With compact framework I can use only System.Windows.Forms.Timer or System.Threading.Timer (that's what I use right now). This controlling class gets all the input from the forms, and then checks what to do and sends out what the forms shall do back to them, or that was the plan at least.
Still, the problem remains, that the showdialog of the frmList does not make frmMain wait anymore with invoke, it just jumps right back into the code block that calls the ShowFrmList() function and continues while the frmList is still open.
The modal dialogs are useful where they are, for example things like user login at the start or after logout.
|
|
|
|
|
Hi Eike,
I have no experience with Compact Framework, I expect the subset it offers works the same
as on the classic Framework.
Manage all the forms from inside the main form (or possibly the static Main method)
seems the right approach.
If the timer's main job is GUI stuff, Forms.Timer is the right one.
If you were to use Forms.Timer and have its Tick handler create and ShowDialog() the
dialog, I am confident the main form would come to a halt until you close the dialog.
The behavior you describe is unfamiliar to me. Normally Application.Run() starts your
first message pump, the loop that keeps your GUI active. Calling ShowDialog() creates
a new message pump, that now gets all the messages, until the dialog gets closed.
You can interfere a bit by calling Application.DoEvents() but that is not recommended
in general (I use it only to restore a GUI after closing a dialog, when a short action
is to be executed on the main thread but you dont want to see the damaged GUI that long).
Did you by any chance try it also as a regular app on classic FrameWork ?
|
|
|
|
|
Hi Luc,
>Did you by any chance try it also as a regular app on classic FrameWork ?
No sorry, I didn't try that, the forms are all FormFactor PocketPC and I have some external compiled ARM .DLLs in it as well. I can't convert it to an ordinary Windows program that easy. But usually Compact and Full Framework behave the same way, just that a lot of nice methods and whole classes are missing in CF.
Nevertheless, if I actually change everything and use the timer in the main form, wouldn't it stop when other forms are opened as modal dialog ? I still need to control the other forms by some sort of timer, if the timer in the main form keeps running, that would work though.
Thanks, Eike
|
|
|
|
|
Hi Eike,
even with a modal dialog open, the main form stays alive: all its Window messages get handled
(e.g. it repaints when you move another window over it) and it keeps getting and executing
its timer ticks (watch the clock in apps that have it in the their status bar).
-- modified at 3:49 Tuesday 24th July, 2007
|
|
|
|