Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Display or hiding all forms associated with a thread

Posted on 2010-08-31
16
Medium Priority
?
679 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 8
  • 7
16 Comments
 
LVL 1

Expert Comment

by:zapacila89
ID: 33572879
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
ID: 33573044
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
ID: 33573161
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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Expert Comment

by:ricovox
ID: 33573456
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 2000 total points
ID: 33573465
Here is the attachment. It didn't upload properly in my previous post.

FindWindowsByThreadID.zip
0
 
LVL 4

Expert Comment

by:ricovox
ID: 33573478
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
ID: 33575477
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
ID: 33576307
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
 
LVL 4

Assisted Solution

by:ricovox
ricovox earned 2000 total points
ID: 33576399
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
ID: 33577266
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
ID: 33610521
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
ID: 33794513
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
ID: 33992481
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
ID: 33993653
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
ID: 33993679
Here's the screencast.
BlearyEye-363001.flv
0
 
LVL 1

Author Comment

by:BlearyEye
ID: 34075783
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

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

In my previous two articles we discussed Binary Serialization (http://www.experts-exchange.com/A_4362.html) and XML Serialization (http://www.experts-exchange.com/A_4425.html). In this article we will try to know more about SOAP (Simple Object Acces…
A long time ago (May 2011), I have written an article showing you how to create a DLL using Visual Studio 2005 to be hosted in SQL Server 2005. That was valid at that time and it is still valid if you are still using these versions. You can still re…
In this video, Percona Director of Solution Engineering Jon Tobin discusses the function and features of Percona Server for MongoDB. How Percona can help Percona can help you determine if Percona Server for MongoDB is the right solution for …
Are you ready to place your question in front of subject-matter experts for more timely responses? With the release of Priority Question, Premium Members, Team Accounts and Qualified Experts can now identify the emergent level of their issue, signal…

604 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