Calling controls from a hidden form in C# - c#

I am designing a Windows form application wherein I need to call, from Form A, a click event for a command button on Form B. Form B needs to remain hidden at all times. It was simple to do this in Visual Basic, I'd just call it like this: "FormName.ControlName.Event/Method".
This isn't working for me now in C#, Visual Studio 8. Can anyone help?

All you need to do is give Form A a reference to Form B. Presumably there is some startup code in your application that is aware of both forms. If so, you could have code like this:
// starting up
FormB b = new FormB();
b.Visible = false;
FormA a = new FormA();
a.FormBInstance = b; // you would have to add the 'FormBInstance' property to Form A class yourself
a.Show();
// Now, if Form A needs to do something with FormB, it just needs to use the FormBInstance property.
Make sense?

Sounds pretty wacky, but with a reference to the instance of Form B and the Button control being made public:
b.myButton.PerformClick();

You should create a public method on FormB that does what you need. This way, you get rid of the need to directly call the click event handler, which is not a great thing to do.

You can't raise events from a different class directly, they have special access level that means you can only subscribe/unsubscribe. You would need method on formB that can raise the event.

Related

Accessing Form components through a threaded method in a plain old C# class

Before getting to the question let me provide a little background. First MyMainForm starts which does two things it initializes a form called Form2 and then calls a method in a different class passing that method an instance of Form2 as a parameter. This can be seen from the figure below. The method then runs a different method say RunInThread in a new thread. Now what I want to know is how I can change data on a textbox on form2 through the RunInThread Method.The Picture also explain my scenario. I tried creating a delegate to a method which changes the text in the textbox and that delegate was in Form2 Class however it seems that you cannot call that delegate from the RunInThread method. Any suggestions on how I could change the text in the Textbox of Form2 through RunInThread method.
Inside the method, RunInThread(Form2 frm_) do something like this:
frm_.BeginInvoke( new System.Windows.Forms.MethodInvoker( () =>
{
frm_.myTextBox.Text = "Hey this updated!!";
}));
This will cause the myTextBox.Text property setter to be called via the windows forms GUI thread that frm_ was created on.

Chain a custom event to be passed back up through multiple forms to the parent

I have a MDImain(Form1) for that handles a custom event generated by children. When I create an instance of a child form I attach the child event to the parent handler. All works great parent catches the event generated by the child. Code in the parent looks like this.
ChildForm instanceChildForm = new ChildForm();
instanceChildForm.Feedback += new EventHandler<feedback>(MainMessageHandler);
then I show the child form... (The Main message handler is in the parent form)
Now I want my child form to show a third form call it child 2. It's instantiated from childForm, but I want the parent MDI to still catch this event. How to I get the vent back to the mdi parent.
All I can think of would be to make the MainMessageHandler routine public on the main form, but then I still need a ref to the main form ... child3.parent = child2parent then attach the event like so:
ChildForm2 instanceChildForm2 = new ChildForm2();
instanceChildForm2.Feedback += new EventHandler<feedback>(this.parent.MainMessageHandler);
or something like that.
OR would this be a good use for a delegate kind of thing? If so I'm not sure how to pull that off.
Thanks for your help !
There's a million and one ways to do it. In my opinion, in any Windows app, you need to be aware of all the forms, their state and be able to past messages between them without creating dependencies. Something like:
public class FormManager
{
List<Form> _forms = new List<Form>();
public void CreateForm<T>() where T : Form, new()
{
var form = new T();
_forms.Add(form);
AttachEvents(form);
form.Show();
}
...methods for attaching events, responding to them, and DETACHING on form.Closed
}
instead of new() ing up forms, you use FormManager.CreateForm<Form1>();
Now, when one of your forms raises an event, you have access to all the forms, both parent and children, and you can make decisions about what to do about that event. You can make those decisions in the FormManager if you want it to be smart, or you can push it down to the forms themselves.

FileSystemWatcher.SynchronizingObject without a form

I have an windows form application written in C# in which I use a FileSystemWatcher to monitor a folder for new files and then perform some processing on them. My application is designed to run in the system tray and therefore does not instantiate any forms at startup. The problem is that the Created event is firing on a separate thread and when I try to create an instance of a form in the Created event I get an ThreadStateException that states I need to be running in SingleThreadApartment. I think I need to set the FileSystemWatcher.SynchronizingObject property but don't know what to use since there is no main form in my application.
You will have to call Application.Run() in your Main() method to get the Windows Forms synchronziation machinery in place so that FileSystemWatcher can properly marshal the call to the main thread. The problem you'll have then is that the main form will become visible. Fix that by pasting this code into the class:
protected override void SetVisibleCore(bool value) {
if (!this.IsHandleCreated) {
this.CreateHandle();
value = false;
}
base.SetVisibleCore(value);
}
There are no restrictions on what your form looks like if you do this.
You don’t need to pass any forms to Application.Run at all. Then you can save having to mess around with form visibility. Just do this:
var InvokerForm = new Form();
var dummy = InvokerForm.Handle; // force handle creation
Application.Run();
Just one gotcha there - the form handle creation needs to be forced by accessing it once.
The simplest way to do this is to make a hidden form and pass it to Application.Run.
You can then set the SynchronizingObject property to the hidden form.
To make sure it's a hidden form, set the ControlBox and ShowInTaskbar properties to false.

manually firing the event in c#

i want to fire an event manually using c#. For instance, say if i want to fire a Form_closing event of Form A from Form B. How to do it ??
After getting some comments. I think i need to explain more on this.
Since my Form A is reference to a .dll which creates a custom taskbar in the desktop,
There is a situation for me to close the that custom taskbar from Form B.
i already tried FormA.Close() from Form B. when i do this, the .dll is unloaded from the app domain and due to this the space occupied by the custom task bar is blocked.
But that is not the case when i click the close button in the custom task bar. when i do this the space is freed up.
This is the reason i want to fire the close event of Form A manually from Form B which will solve my issue.
Thanks.
We did the following in one project:
There was a GlobalNotifier class, which defined events we wanted to use in different modules of the application, like this
public static class GlobalNotifier
{
public static event VoidEventHandler EnvironmentChanged;
public static void OnEnvironmentChanged()
{
if (EnvironmentChanged != null)
{
EnvironmentChanged();
}
}
}
Then, you could raise this event anywhere when you needed to let the rest of the application know that the environment has changed, like this
GlobalNotifier.OnEnvironmentChanged();
And also you could subscribe to this event wherever you wanted to be notified about the fact that the environment has changed.
public ReportingService()
{
GlobalNotifier.EnvironmentChanged += new VoidEventHandler(GlobalNotifier_EnvironmentChanged);
}
void GlobalNotifier_EnvironmentChanged()
{
//reset settings
_reportSettings = null;
}
So, whenever you changed the environment, you raised the event, and everyone who needed to know about that and perform some actions, was notified.
Might be similar to what you need to achieve.
Also, if you need to pass parameters, you can define the event any way you like, basically -
public static event VoidEventHandler<SomeObject, List<OtherObject>> SomethingUpdated;
public static void OnSomethingUpdated(SomeObject sender, List<OtherObject> associations)
{
if (SomethingUpdated != null)
{
SomethingUpdated(sender, associations);
}
}
// ...
MyClass.SomethingUpdated+= new VoidEventHandler<SomeObject, List<OtherObject>>(MyClass_SomethingUpdated);
// ...
void MyClass_SomethingUpdated(SomeObject param1, List<OtherObject> param2)
{
//do something
}
You would call the OnFormClosing() method of the Form class. You can do this with any event that has a paired On...() method.
It sounds to me, from your comments, like you don't want to raise one form's event from the other; you just want to handle one form's event from the other.
Yes, you can do that. FormB needs to have a reference to FormA. There are several ways you can do this; one easy way is to have a FormA type property in your FormB class, like this:
public FormA TheOtherForm { get; set; }
You set that property to your instance of FormA, and then you add the event handler as you've described in the comments.
You don't have to use FormA as the type of your property; any form has the FormClosing event, so you can just use Form as the type if you want.
Close the form. That will raise the event. If you want to raise the event separately from closing the form, you're doing something wrong; move that code to a separate method that you can call from the event and from FormB.
FormAInstance.Close()
Starting with Visual Studio 2005 (.Net 2.0), forms have automatic default instances. It sounds like that's what you're using. You should know that this feature exists mainly for backwards compatibility with VB6. You're really better off creating and using a new instance of the form. When you do that, you should just be able to call the .Close() method on that instance without it's app domain closing.
If you want to re-use this space, you might also try simply .Hide()-ing the form rather than closing it.

Load a form without showing it

Short version: I want to trigger the Form_Load() event without making the form visible. This doesn't work because Show() ignores the current value of the Visible property:
tasksForm.Visible = false;
tasksForm.Show();
Long version: I have a WinForms application with two forms: main and tasks. The main form is always displayed. The user can either click a button to open the tasks form, or click some buttons that just run a task directly without opening the tasks form.
When a user asks to run a task directly, I'd like to just call some public methods on the tasks form without showing it. Unfortunately, the task logic depends on stuff that happens in the Form_Load() event. The only way I can find to trigger Form_Load() is to call Show(). The best I've been able to do is to show the form in the minimized state:
tasksForm.WindowState = FormWindowState.Minimized;
tasksForm.Show();
I suppose the cleanest solution would be to pull the tasks logic out of the tasks form and into a controller class. Then I can use that class from the main form and from the tasks form, and only load the tasks form when I need it visible for the user. However, if it's an easy thing to load the form without displaying it, that would be a smaller change.
Perhaps it should be noted here that you can cause the form's window to be created without showing the form. I think there could be legitimate situations for wanting to do this.
Anyway, good design or not, you can do that like this:
MyForm f = new MyForm();
IntPtr dummy = f.Handle; // forces the form Control to be created
I don't think this will cause Form_Load() to be called, but you will be able to call f.Invoke() at this point (which is what I was trying to do when I stumbled upon this SO question).
It sounds to me like you need to sit down and re-think your approach here. I cannot imagine a single reason your public methods need to be in a form if you are not going to show it. Just make a new class.
I totally agree with Rich B, you need to look at where you are placing your application logic rather than trying to cludge the WinForms mechanisms. All of those operations and data that your Tasks form is exposing should really be in a separate class say some kind of Application Controller or something held by your main form and then used by your tasks form to read and display data when needed but doesn't need a form to be instantiated to exist.
It probably seems a pain to rework it, but you'll be improving the structure of the app and making it more maintainable etc.
From MSDN:
Form.Load
Occurs before a form is displayed for the first time.
Meaning the only thing that would cause the form to load, is when it is displayed.
Form.Show(); and Form.Visible = true; are the exact same thing. Basically, behind the scenes, Show checks for various conditions, then sets Visible to true. So obviously, setting visible to false (which it already is) before showing the form is meaningless.
But let's forget the technicalities. I completely agree with Rich B and Shaun Austin - the logic shouldn't be in that form anyway.
Sometimes this would be useful without it being bad design. Sometimes it could be the start of a migration from native to managed.
If you were migrating a c++ app to .NET for example, you may simply make yourwhole app a child window of the .NET form or panel, and gradually migrate over to the .NET by getting rid of your c++ app menu, status bar, toolbar and mapping teh .NEt ones to your app using platform invoke etc...
Your C++ app may take a while to load, but the .NET form doesn't..in which you may like to hide the .NEt form until your c++ app has initialised itself.
I'd set opacity=0 and visible=false to false after calling show, then when your c++ app loads, then reverse.
If you make the method public, then you could access it directly.... however, there could be some unexpected side effects when you call it. But making it public and calling it directly will not draw the screen or open the form.
Move mandatory initialization code for the form class out of the Load event handler into the constructor. For a Form class, instantiation of an instance (via the constructor), form loading and form visibility are three different things, and don't need to happen at the same time (although they do obviously need to happen in that order).
None of the answers solved the original question, so, add the below, call .Show() to load the form without showing it, then call .ShowForm() to allow it to be visible if you want to after:
private volatile bool _formVisible;
protected override void SetVisibleCore(bool value)
{
base.SetVisibleCore(_formVisible);
}
public void ShowForm()
{
_formVisible = true;
if (InvokeRequired)
{
Invoke((Action) Show);
}
else
{
Show();
}
}

Categories