|
Well see I can't abort WMI.
ALL I can do is basically tell my code NOT to write the data to form if it sees the Handle isn't there. Now on the events do you mean something like this:
MAIN THREAD:
public delegate void UserRetrievalDelegate();
public event UserRetrievalDelegate UserRetrievalFinished;
private void frmMain_Load(object sender, EventArgs e)
{
UserRetrievalFinished += new UserRetrievalDelegate(frmMain_UserRetrievalFinished);
}
void frmMain_UserRetrievalFinished()
{
PopulateUsers();
}
USER RETRIEVAL THREAD (Not Main thread):
private void FillUsers()
{
users = new List<User>();
LDAP ldap = Login();
if (ldap != null)
{
PrincipalSearchResult<Principal> usrs = ldap.AllADUsers();
foreach (Principal principal in usrs)
{
User temp = ldap.GetUserInfo(principal.Name, "name");
users.Add(temp);
temp = null;
}
UserRetrievalFinished();
}
}
So the thread fires the event which calls my populateusers method from the main thread?
|
|
|
|
|
Nope.
The way you have it, PopulateUsers is not "from the main thread". It will be executed by the caller, on the caller's thread, as always. You need a delegate and a Control.Invoke to force the method to be called on the main thread; just moving some code from one source location to another cannot solve this.
You may want to read this[^]; you do not really need Control.InvokeRequired here, as you are certain the caller is some other thread.
|
|
|
|
|
Uhm. I see what you are saying also.... but how do I do that if the main thread has been disposed of? Basically in my spawned thread I need to double check and make sure the main thread is not disposed of.. if it is then basically don't try to write anything to it (because you can't), and if it is there then write the data to it
|
|
|
|
|
You seem to be very confused; a .NET program consists of two things: objects and threads;
objects contain code and data however they don't do a thing (they are the cookbook and the ingredients); threads execute code and operate on data (like chefs reading cookbooks and using ingredients), so it is threads that give live to objects (make soup).
If it is your Form that is to display the results of a long-wielding action (which you therefore have relegated to another thread), then you need Invoke() to pass the action back to the main thread (the thread is still alive, all that could have happened is that your Form got closed, disposed, and maybe collected); if your Form no longer exists, then you must prevent the Invoke from happening, so use a boolean flag, or set the delegate to null, or whatever other way you choose to tell the helper thread the results are no longer wanted.
|
|
|
|
|
Oh I understand I must invoke. I also read the article you have sent. So I know I must invoke controls that want to display data from another thread. What I didn't know was how to basically tell the thread NOT to invoke if the main thread wasn't here anymore.
if your Form no longer exists, then you must prevent the Invoke from happening
That is what I'm trying to figure out.. how to tell the form doesn't exist anymore and just not write anything. I just looked and was wondering if this.IsDisposed was a way to make it work
|
|
|
|
|
simplest is using the delegate itself: have the form set up the delegate, and when it decides to go away (you might use its finalizer, I would prefer a real event though, maybe FormClosing), clear the delegate; in the relegated code, check the delegate isn't null.
|
|
|
|
|
What is the harm of this:
private void GetServices()
{
WMI_Commands wmi = new WMI_Commands(Username, Password,
System.Management.ImpersonationLevel.Impersonate, System.Management.AuthenticationLevel.Default);
List<Services> services = wmi.GetServices(NetBios);
if (!this.IsDisposed)
{
foreach (Services s in services)
{
AddServices(s);
}
SetPBVisible("pbservices", false);
}
services = null;
}
I'm testing it right now... (process still running)
Basically I check and make sure that the form isn't disposed.. if it IS then I basically do nothing.. no need to write anything out, but if IsDisposed comes back false then I write it out.
|
|
|
|
|
With the original code you showed, I would normally put it into its own class, but if you didn't something like this:
private delegate void ApplicationsLoadedDel(List<Product> apps);
private event ApplicationsLoadedDel ApplicationsLoaded;
private void frmMain_Load(object sender, EventArgs e)
{
appThread = new Thread(new ThreadStart(GetApplications));
appThread.IsBackground = true;
this.ApplicationsLoaded += AddApplications;
appThread.Start();
}
private void LoadApplications()
{
WMI_Commands wmi = new WMI_Commands(Username, Password,
System.Management.ImpersonationLevel.Impersonate,
System.Management.AuthenticationLevel.Default);
List<Product> products = wmi.InstalledApplications(NetBios);
ApplicationsLoaded(products);
}
Delegate void AddApplicationsDel(List<Product> products)
private void AddApplications(List<Product> products)
{
if (this.InvokeRequired)
this.Invoke(new AddApplciationsDel(Address of AddApplications),
new Object() {products});
foreach (Product p in products)
{
AddApplication(p);
}
products = null;
SetPBVisible("pbapplications", false);
}
|
|
|
|
|
Uhm...
I see what you are doing.. but how does that solve the problem with a user closing the thread before its finished? Because that is somewhat like I thought I had it but the problem is it would still try to write to the form even when it was gone.
Calling ApplicationLoaded from the thread doesn't that not make it on the main thread? Which would end up with the thread still trying to write to a form that isn't there?
|
|
|
|
|
You could set up your Form_close like this:
public void form_close(Object sender, FormClosingEventArgs e)
{
this.Hide();
this.ApplicationsLoaded -= AddApplications;
this.ApplicationsLoaded =+ CloseFormOnCompletion;
}
public void CloseFormOnCompletion(List<Product> products)
{
this.Close();
}
So, the thread will continue to run, but nothing will be written to the form because you've changed what happens when the event is fired off.
|
|
|
|
|
Ah that is a pretty good idea to.. but I think just a simple MyDelegate != null would be easier?
|
|
|
|
|
Solution from all of your guys help:
I have tested this a couple times and it has yet to throw any errors on closing the form early. Still have plenty more testing to do though.
I create my event for when the applications have been loaded and start my threads
private delegate void ApplicationsLoadedDelegate(List<Product> products);
private event ApplicationsLoadedDelegate ApplicationsLoaded;
private void frmCompInfo_Load(object sender, EventArgs e)
{
ApplicationsLoaded += new ApplicationsLoadedDelegate(frmCompInfo_ApplicationsLoaded);
ServicesLoaded += new ServicesLoadedDelegate(frmCompInfo_ServicesLoaded);
InfoLoaded += new InfoLoadedDelegate(frmCompInfo_InfoLoaded);
appThread = new Thread(new ThreadStart(GetApplications));
appThread.Start();
driveThread = new Thread(new ThreadStart(GetInfo));
driveThread.Start();
serviceThread = new Thread(new ThreadStart(GetServices));
serviceThread.Start();
}
This is what I call which makes the call to the WMI DLL file I created for querying the data of a remote computer. It will return a List of my custom structure <product>. Before I do anything else with this I check and make sure that my ApplicationsLoaded is not null. If it is null that means the form has been closed. I do the invoke required blah blah blah because of another thread. I know you suggested not doing it, but I might call this from the main thread also (for the future). Plus the article you sent me the author was really fond of sticking to this technique.
private void GetApplications()
{
WMI_Commands wmi = new WMI_Commands(Username, Password,
System.Management.ImpersonationLevel.Impersonate, System.Management.AuthenticationLevel.Default);
List<Product> products = wmi.InstalledApplications(NetBios);
if (ApplicationsLoaded != null)
ApplicationsLoaded(products);
products = null;
}
private void frmCompInfo_ApplicationsLoaded(List<Product> products)
{
if (lstApplications.InvokeRequired)
lstApplications.Invoke(new ApplicationsLoadedDelegate(ApplicationsLoaded), new object[] { products });
else
{
lstApplications.BeginUpdate();
foreach (Product p in products)
{
ListViewItem item = new ListViewItem();
item.Text = p.Name;
item.SubItems.Add(p.Version);
item.SubItems.Add(p.Vendor);
item.SubItems.Add(p.InstallLocation);
lstApplications.Items.Add(item);
}
lstApplications.EndUpdate();
SetPBVisible(pbApplications, false);
}
}
On form closing I unload all of the events.
private void frmCompInfo_FormClosing(object sender, FormClosingEventArgs e)
{
ApplicationsLoaded -= frmCompInfo_ApplicationsLoaded;
ServicesLoaded -= frmCompInfo_ServicesLoaded;
InfoLoaded -= frmCompInfo_InfoLoaded;
}
I've taken a couple of your suggestions and kind of compiled them together I think. Like I said I have tested this only a couple times by loading the form and watching it start the thread and closing the form before the thread was completed. I never saw any kind of error messages at all. (which is what I wanted)
|
|
|
|
|
You posted whilst I was composing the message below! Hope it helps anyway
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
Reading through the messages above, you don't seem to have grasped the 'unsubscribe from event' way of dealing with this.
If you make sure that your thread updates the UI only via an event then by unsubscribing to that event, the UI update code will not get called! All the InvokeRequired stuff should be in the event consumer's handler method.
It's not clear whether you wish to let the thread complete naturally after the application closes or terminate it immediately. By setting IsBackground to true , it will terminate. Not setting (or setting to false ) will allow it to continue.
Here's some demo code which may help explain!
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Threading;
using System.Windows.Forms;
namespace ThreadingDemo
{
public partial class FormMain : Form
{
MyThreadedClass myThreadedClass;
public FormMain()
{
InitializeComponent();
myThreadedClass = new MyThreadedClass();
myThreadedClass.GotDataCompleted += myThreadedClass_GotDataCompleted;
FormClosing += FormMain_FormClosing;
Shown += new EventHandler(FormMain_Shown);
}
void FormMain_Shown(object sender, EventArgs e)
{
}
private void FormMain_FormClosing(object sender, FormClosingEventArgs e)
{
myThreadedClass.GotDataCompleted -= myThreadedClass_GotDataCompleted;
}
private void myThreadedClass_GotDataCompleted(object sender, GotDataCompletedEventArgs e)
{
if (InvokeRequired)
Invoke(new MethodInvoker(delegate { myThreadedClass_GotDataCompleted(sender, e); }));
else
{
foreach (string item in e.Data)
Text = item;
}
}
private void RunThread()
{
myThreadedClass.Begin();
}
private void RunThreadAsBackground()
{
myThreadedClass.SetAsBackground();
myThreadedClass.Begin();
}
}
public class MyThreadedClass
{
public event EventHandler<GotDataCompletedEventArgs> GotDataCompleted;
private Thread thread;
public MyThreadedClass()
{
thread = new Thread(new ThreadStart(Start));
}
public void Begin()
{
thread.Start();
}
protected virtual void OnGotDataCompleted(GotDataCompletedEventArgs e)
{
EventHandler<GotDataCompletedEventArgs> eh = GotDataCompleted;
if (eh != null)
eh(this, e);
}
private void Start()
{
GotDataCompletedEventArgs e = new GotDataCompletedEventArgs();
e.AddData("Data 1");
Thread.Sleep(10000);
e.AddData("Data 2");
OnGotDataCompleted(e);
}
public void SetAsBackground()
{
thread.IsBackground = true;
}
}
public class GotDataCompletedEventArgs : EventArgs
{
private List<string> data;
public GotDataCompletedEventArgs()
{
data = new List<string>();
}
public ReadOnlyCollection<string> Data
{
get { return data.AsReadOnly(); }
}
internal void AddData(string item)
{
data.Add(item);
}
}
}
DaveIf this helped, please vote & accept answer!
Binging is like googling, it just feels dirtier. (Pete O'Hanlon)
BTW, in software, hope and pray is not a viable strategy. (Luc Pattyn)
|
|
|
|
|
The line in my form is flickering.
The form is DoubleBuffered which made me kind of lost .
Help?
using System;
using System.Windows.Forms;
using System.Threading;
using System.Drawing.Design;
namespace Threading
{
public partial class Form1 : Form
{
Pen pen = new Pen(Color.Black);
Thread t;
public Form1()
{
InitializeComponent();
pen.Width = 3;
pen.StartCap = System.Drawing.Drawing2D.LineCap.SquareAnchor;
pen.EndCap = System.Drawing.Drawing2D.LineCap.RoundAnchor;
t = new Thread(new ParameterizedThreadStart(Commando));
t.Start(true);
}
public void Commando(object obj)
{
while (true)
{
Graphics x = this.CreateGraphics();
x.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
x.DrawLine(pen, new Point(0, 0),
new Point(
MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y));
this.Refresh();
}
}
}
}
Any help is appreciated.
|
|
|
|
|
nbgangsta wrote: this.Refresh();
This will not work, you are trying to refresh the form from a different thread. It will throw a cross thread reference error.
nbgangsta wrote:
t = new Thread(new ParameterizedThreadStart(Commando)); <br />
t.Start(true);
Not sure what you are trying to do. But I would override the form's OnPaintMethod and use the MouseMove event to draw the line rather than using a different thread to draw it.
Tarakeshwar Reddy
There are two kinds of people, those who do the work and those who take the credit. Try to be in the first group; there is less competition there. - Indira Gandhi
|
|
|
|
|
Flickering is a sign that it is not doublebuffered or you are drawing on the wrong surface or flipping too soon.
Double buffering is:
Create a primary surface with one backbuffer (essentially 2 display surfaces)
Always draw on the backbuffer (it is not visible) and when all drawing is complete swap the 2 surfaces.
the swapping makes the backbuffer the primary and the primary becomes the backbuffer
this is what prevents flickering, the instantanious swap of the source display surface.
I haven't used the above drawing methods only DirectX and some GDI so i could be totally wrong about your code.
It appears you are creating/initializing your drawing surfaces (this.CreateGraphics()) repeatedly....this should only be done once.
- Where does it create your drawing surface Doublebuffered?
- How does x.DrawLine know which surface of X to draw on?
I also see "new" several times within you while(true) loop but no "delete" unless their is some sort of garbage collection for memory eventually you'll run out.
Another issue you could have is since the drawing is in it's own thread....when the main form/window needs to refresh, it needs to know what to draw (the primary surface) or let the drawing thread know it needs to refresh the display area that it is handling.
Hope this helped.
|
|
|
|
|
I can't say for sure what's causing it, but I was curious about something in your code:
public void Commando(object obj)
{
while (true)
{
Graphics x = this.CreateGraphics();
x.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
x.DrawLine(pen, new Point(0, 0),
new Point(
MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y));
this.Refresh();
}
}
you set it up as a parameterized void , and you passed it true, but then you never actually check the object. obj does absolutely nothing in this example.
I don't think you're going to be able to get away from the flicker the way you're doing it.
Why, can't you just put the code into the MouseMove? It will flicker a tiny bit while you're moving, but when the mouse is stopped, no flicker.
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
this.Refresh();
Graphics x = this.CreateGraphics();
x.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
x.DrawLine(pen, new Point(0, 0),
new Point(
MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y));
}
Oh, and I modified your code to be more thread friendly:
public void Commando(object obj)
{
while (true)
{
Graphics x = this.CreateGraphics();
x.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
x.DrawLine(pen, new Point(0, 0),
new Point(
MousePosition.X - this.Location.X, MousePosition.Y - this.Location.Y));
if (this.InvokeRequired)
{
RefreshMe = RefreshForm;
this.Invoke(RefreshMe);
}
}
}
private delegate void RefreshFormDel();
private RefreshFormDel RefreshMe;
private void RefreshForm()
{
this.Refresh();
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (t != null)
if (t.IsAlive)
t.Abort();
}
|
|
|
|
|
Am not sure how can I describe it or what does Microsoft call it but listen...
When you start Windows Vista and you get the login screen it will show the user picture and the password textbox with the work password in light color so when you click inside it will disappear then whenyou clear the text it will show again..
first, what do you call it please.
then how can I do it for both user id and password textbox?
|
|
|
|
|
It's easy enough to crete your own custom TextBox control that does this. There several different ways of doing it, but they all start with creating a seperate class that inherits from TextBox and probably provides some custom painting code and a couple of extra properties to show what you want light-shaded if the Text property is an empty string AND the control does not have the focus.
|
|
|
|
|
but does this thing has a name so I can at least get guide from internet?
|
|
|
|
|
|
|
I have a network application built using C# and for the most part 99% of my users have no problems with it.
I have a few users that don't have IE installed and are using Firefox as their main browser and they have reported strange behavior in my application. One user was savvy enough to install IE and saw the display issues went away. This puzzled me since I would assume when you distribute a .NET 3.5 application that it would install all of the required components. Why would an installation of IE 7 or 8 improve the look inside my application? More importantly, why is the application not working properly without IE installed. I guess that is the bigger question here. Also, I have users telling me they can't click buttons and such.
I am puzzled by this since it is merely a browser control. They should be able to click buttons and navigate as they wish. 99% of my user base is funtioning flawlessly, so I know it is not the application, but the environment.
Any ideas where to look? The WebControl seems to be part of the 2.0 Framework.
|
|
|
|
|
Your users mostly likely have an older version of IE that was preinstalled on the machine.
The .net framework and IE are two separate things, just because you install the framework components you don't automatically get the latest IE. The WebBrowser control will use whatever version of IE is available.
I know the language. I've read a book. - _Madmatt
|
|
|
|