Solved

Display or hiding all forms associated with a thread

Posted on 2010-08-31
16
642 Views
Last Modified: 2013-12-17
In C# 4.0 I have an application that starts several threads. Each thread performs processing, opening and closing its own forms as necessary.

Each of these threads is intended to run independently (a dashboard using the Observer pattern summarizes the status of each thread). I want to be able to hide all the forms on a given thread and later make them all visible again, including any changes that might have taken place (forms opened or closed).

Right now what I'm doing is using Application.OpenForms. I can associate most of the open forms with a thread, so I can go thru the collection and display or hide the forms for a given thread. It's not perfect, but seems to be good enough.

The main problem seems to be that I can't preserve the z-order of the forms, so that when they are made visible, they're in the order of creation, not necessarily the z-order at the time of hiding. If I could record the current z-order state I'd probably be OK but I don't see how to do that.

On a technical note, I'm not really making the forms visible or invisible; I'm using TopMost and BringToFront() and SendToBack() to selectively move forms into or out of view with respect to a full screen form that acts as a visibility barrier (stuff on top is visible, stuff behind is not). I tried using Visible to hide or display forms, but recording the visibility state when hiding, and handling it when a form on a hidden thread was created turned out to be a bit tricky. Both approaches have the problem of distorting the z-order.

There are other problems with my OpenForms approach, but that's probably enough for now. I'm open to suggestions, either avoiding OpenForms entirely, or somehow dealing with the z-order problem.
0
Comment
Question by:BlearyEye
  • 8
  • 7
16 Comments
 
LVL 1

Expert Comment

by:zapacila89
Comment Utility
Why don't you retain the index the form had in the OpenForms collection when you removed it? And when you restore them sort by the that index
0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
Given a set of forms in OpenForms, I can't tell their current z-order. All I can tell is the order in which they were created. Operations can change the z-order after they're created.
0
 
LVL 4

Expert Comment

by:ricovox
Comment Utility
You can use the windows API function "EnumWindows" to find ALL windows open on the desktop, and then use the "GetWindowThreadProcessId" function to determine which thread each window belongs to.
The windows are always returned in highest to lowest Z-order, so you will be able to store them in the same order.

There are a number of good EnumWindows examples out there for .Net. You will have to do some P/Invoke, so it is not the easiest thing in the world, but it is not too difficult if you see some good examples.

I would recommend you download and include the following open source library:
http://mwinapi.sourceforge.net/

That provides a very good implementation of EnumWindows.

You would use something like this:

int threadID = ... //this is the id of the thread you want to find the windows for.

SystemWindow[] myWindows = SystemWindow.FIlterTopLevelWindows(
             win => (win.Thread == threadID)
   );

//now myWindows is an array of forms that have the required thread id.
//They are all in order by z-order, so you can store them etc.

foreach(SystemWindow w in myWindows)
    w.Hide();
or
foreach(SystemWindow w in myWindows)
     w.Show();

You can probably also sendtoback or sendtofront.
0
 
LVL 4

Expert Comment

by:ricovox
Comment Utility
Please see the code project I've attached.
 
I included a very stripped-down version of the ManagedWindows API (LGPL, http://mwinapi.sourceforge.net/) so that it only includes the SystemWindow class you need to filter open windows.
 
This project nicely demonstrates how you can very easily obtain a list of all windows on the desktop and you can filter them by ThreadID to find only the ones you are interested in.
The windows are always returned in Z-order (Top windows First)
 
So you can store them in that order. Then when you hide/show them, just do it in reverse order so that the ones you show last will be in the top of the z-order.

Here are the instructions: Build and run the project.
Then click "Launch", which will launch a new thread and will create several windows on that thread (you specify how many). Those windows will pop up, and will be color-coded based on which thread they belong to.

Then hit "Refresh Now" on the list, and it will list all open windows that belong to any of the threads that were launched by your program.

Try launching about three threads, each with 3 Forms. Then bring some of the Forms to the top of the Z-order and see how the order in the list changes when you click Refresh.
0
 
LVL 4

Accepted Solution

by:
ricovox earned 500 total points
Comment Utility
Here is the attachment. It didn't upload properly in my previous post.

FindWindowsByThreadID.zip
0
 
LVL 4

Expert Comment

by:ricovox
Comment Utility
Of course, this isn't exactly what you want because I didn't demonstrate hiding and showing the forms. But you should be able to get a good idea of what is possible.

One more important note: in order for you to figure out which of your OpenForms corresponds to a particular SystemWindow in the list, just use the SystemWindow's hWnd property, which corresponds to a .Net Form's Handle property.
0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
Sweet. I'll give this a try as soon as I can (after Labor Day weekend). It looks like this will solve the z-order issue.

So as far as managing visibility goes, it looks like I'm still on my own to hide or show the forms, right? My main objection to the approach I'm using now is that it assumes that the thread application doesn't manipulate TopMost; this guarantees that only the desired forms are on top of the barrier. If that's not true, my approach can fail.

Using Hide() and Show() on the other hand requires me to modify the source for each instance so that desired visibility status (from the thread app's point of view) is recorded whenever it changes.

Any ideas on managing visibility itself?
0
 
LVL 4

Expert Comment

by:ricovox
Comment Utility
I think I see what you are saying.
Just to be clear, you mean that each individual thread will hide and show its forms throughout the process, so you don't want to use hide/show from the control app because you won't know when the "worker" thread has hidden a window or when the "main" thread has done so.

I think that TopMost shoud work fine. It's not an ideal situation, but there's nothing wrong with it. One alternative might be to set the "Opacity" of a form to 0 to hide it or to 1 to show it. I don't believe that Opacity affects the "Visible" property.

...oh, I just thought of this..in the code I sent you, it would be a good idea to search for only "Visible" windows, because there are sometimes hidden windows that are created on one of the threads you are looking for.

you could use this code:


			SystemWindow[] myWindows = SystemWindow.FilterToplevelWindows(

				win => _threadIdList.Contains(win.Thread.Id) && win.Visible

					);

Open in new window

0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 4

Assisted Solution

by:ricovox
ricovox earned 500 total points
Comment Utility
And as I mentioned before, you will have to find the .Net forms by using the hWnd property.

So here are two functions you might find useful. You could put these directly into the code I sent you.

The first function simply finds a .Net Form given its window Handle (hWnd) that you get from a SystemWindow.

The second function would be useful in your scenario, where you could pass in an array of SystemWIndows (which you get by using SystemWindow.FilterTopLevelWindows with whatever criteria you want..e.g. ThreadID)...and it will either show or hide all of the corresponding Forms (by using the TopMost property...you could just as easily use Opacity or whatever else you want)





private Form FindForm(IntPtr hWnd) {
			foreach (Form f in Application.OpenForms)
				if (f.Handle == hWnd)
					return f;
			return null; //not found
		}
	
		void ShowForm(SystemWindow[] windows, bool show) {
			foreach (SystemWindow win in windows) {
				Form f = FindForm(win.HWnd);
				if (f != null)
					f.TopMost = show;
			}
		}

Open in new window

0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
You said:
I think I see what you are saying.
Just to be clear, you mean that  each individual thread will hide and show its forms throughout the  process, so you don't want to use hide/show from the control app because  you won't know when the "worker" thread has hidden a window or when the  "main" thread has done so.
Yes, that exactly the problem.

Will work over your suggestions after the weekend. Thanks.
0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
I haven't tried this yet -- still out of town -- but there's going to be a related issue that I didn't mention originally. A parent thread can create another thread, and that child thread can create forms. Hence I need to deal with the forms on the child thread.

I know I can get a list of the threads associated with the current process (Process.GetCurrentProcess().Threads) and I have a list of the parent threads, so those left over must be children; but I don't know how to associate a child with its parent.

Given I can do that, the second issue is to preserve the z-order of the forms associated with a parent and its children.
0
 
LVL 1

Assisted Solution

by:BlearyEye
BlearyEye earned 0 total points
Comment Utility
Sorry ... I worked on this but somehow neglected to post a follow-up.

I implemented the Managed Windows API approach but the performance was pretty poor ... it took several seconds to build the SystemWindow list - a very noticeable length of time; too long for me to use.
0
 
LVL 4

Expert Comment

by:ricovox
Comment Utility
Hi BlearyEye,

Thank you for accepting my answer. I'm sorry you had performance issues, and I'd like to help you improve them. The SystemWindow list should be completely built within a matter of milliseconds, even if you have many windows open.

So maybe something else is taking a long time or maybe the list could be built more efficiently. When you used my example project, did it also take a long time? It took only milliseconds for me. I would be happy to review some of your code that is relevant to this discussion to see if I can improve it.

Also, as I suggested before, you can use Opacity to "hide" or "show" a form (set Opacity to 0 to hide and to 1 to show a form). That way you can track which forms are hidden or shown, and it is very unlikely that the forms will set opacity themselves. By using opacity, you do not have to use Z-order.

Thanks!
0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
That's very kind of you. Yes, the problem occurred with the sample code you sent me.

I just modified it to measure & display the elapsed time (see code below). It takes about 2.5 seconds, give or take a bit. Will send a screencast separately.
private void btnRefresh_Click(object sender, EventArgs e) {
            DateTime begin = DateTime.Now;
	    RefreshList();
            DateTime end = DateTime.Now;
            TimeSpan diff = end - begin;
            DateTime diffTime = new DateTime(diff.Ticks);
            string totalTime = diffTime.ToString("ss.fff");
            lstWindows.Items.Add("Time required: " + totalTime);
		}

Open in new window

0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
Here's the screencast.
BlearyEye-363001.flv
0
 
LVL 1

Author Comment

by:BlearyEye
Comment Utility
I tried FindWindowsByThreadID on a Win 7 machine (I'm using Vista). Lo and behold, the performance was snappy; about 0.2 seconds.

Since the target for my application is Win 7, I'm going to go ahead and try this solution.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

This document covers how to connect to SQL Server and browse its contents.  It is meant for those new to Visual Studio and/or working with Microsoft SQL Server.  It is not a guide to building SQL Server database connections in your code.  This is mo…
Entity Framework is a powerful tool to help you interact with the DataBase but still doesn't help much when we have a Stored Procedure that returns more than one resultset. The solution takes some of out-of-the-box thinking; read on!
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

17 Experts available now in Live!

Get 1:1 Help Now