I'm working on an application so i have write an dll which contain a form with some additional work and methods. so in the beginning of my program the thread launch this form (from my dll) to get some informations and then hide it and initialize some components and the application form and then show it. when the thread come the line where it define new instance of the exported form
"MyForm inputform = new MyForm();"
it throw an Exception called "Top-level control cannot be added to a control." so i don't know what to do ?!!. i tried to take the code of the form from the dll source code and put it in the main program and it works.... .but still i want to know what happen and what impede my application from run that form from my dll.
thanks.
The line that raises the error is possibly not the line you show above, but likely one of the lines that follows it. I.e., if you have something like the following:
currentControl.Controls.Add(inputForm);
it will not work and raise the error you mention.
Instead, use inputForm.Show(ownerForm) to show the form when you want it and you should be fine. A form (a top level control) cannot be added to a normal control, like a panel, a textbox or a picturebox.
Note: if the line in your post does raise the error, then inside the form initialization code lies a piece of code that raises the error, check there
Related
I've created a custom user control, that is essentially a custom button within my windows form app. I managed the redirect of the click event to using the following code:
Control[] customButtonControls = button.Controls.Find("buttonInUserControl", false);
Button nestedButton = (Button)customButtonControls[0];
nestedButton.Click += new System.EventHandler(this.button_click_handling_function);
I've appended this to the Window_Name.Designer.cs file below the generated code for the control with my button_click_handling_function being defined in my Window_Name.cs file.
The issue is that when I then click back to the Window_Name.cs[Design] page, I am met with an error page. I will include screen shots to better show the errors. Basically it is a super unhelpful page. It tells me that I have an index out of range error on my Array, but the stack call makes no sense.
If I try to build my Solution, I am met with NO compile errors and my program acts exactly as intended. The click event triggers the function just as before.
Thanks in Advance.
Portions of the designer code are run at design-time. The index out of range error is probably because at design-time there are no controls found yet by that Find call so the array is empty. You are not checking for 0 length so when you de-reference it you get the error.
It works at run-time because at that point the controls have been instantiated.
The secondary problem though is you should not put things into the Designer.cs files since that code is auto generated by the designer and could be regenerated at some point and your added code lost. Put that code in the Window_Name.cs after the InitializeComponent call.
I have a selection of TextBoxes that a user fills in when they wish to note that they have had contact with another person. Most of the TextBoxes are imply filled in by typing into them. However, for one of them I would like the user to be able to select from a list of People that appears when they click on a button.
This is where I am having problems. So far I have just made a DataGrid appear and handled it's SelectionChanged method to fill in the TextBoxes text property. This has worked fine, however now there is not enough space on the current page to show an entire DataGrid with all the people they can select from.
I've decided to show the People in a separate, smaller Window that appears when the user clicks a Button. The issue I have is that when the user selects the Person they wish to mark the contact for in the new Window, I have no idea how I can notify the original Window that a Person has been selected, close the new smaller Window and fill in the appropriate TextBox on the original Window.
What would be the most intuitive way to fill in the TextBox on the original Window, based on the selection on the Window that opens?
I would use delegates,which call a function of the original window and parse the changed variable with it. So you know when the user clicked something and you can directly react to this "event".
Link:
https://msdn.microsoft.com/en-us/library/ms173171.aspx
If you use a framework like Galasoft's MVVM Light (http://www.galasoft.ch/), they have a messenger system just for this purpose. It allows you to "broadcast" messages that can be "received" by any other part of the application
This is when considering using Domain, Model, Presentation (Winforms/WPF version of MVC formatting) to do your app.
You can have each form as its own class, well they are their own class. Create each form class but add some public members to it if the controls are private. Have them have "get" properties only and to return the values of whatever controls or variables are in that form. Your main form will be the controlling form. All forms will be handled by the main form so when you open it, it is a class the main form can access.
Now, if I remember (been doing more MVC and not any Winforms lately) I believe if you use the ShowDialog() method it will freeze the main thread so when you close out the main form you can continue and read in public members you have in your forms class you opened. Synchronous I believe it runs as. If you use just Show() the thread will keep on trucking, asynchronous. With asynchronous you may then have to use a main form in your startup code so there is always a window there but subscribe to the close event of your forms and have a method that can grab those public members out. Be sure to instantiate the extra forms at the root of the main class so it doesn't fall out of scope when it exists the method that calls it. You may even be able to make the method that calls is a async call and have an await before the command that runs the Show method on the form.
Summary, treat each form as its own class but add public members that can read the values from the controls and/or variables you want. Read that data from the class when it closes via an event or synchronously when the thread closes out from the form closing. The form closing doesn't discard the object, just the visualization of the form.
Oh, if you are passing info from the main form to a child for you are opening, either add a constructor for that form class that takes your input as a model or values to fill in the appropriate variables or forms before showing it or create a public property you can put your values you want to send in before showing the class.
Remember, everything is a class, once you look at it as such and treat it as such, the answer will come. :-)
I should warn, I am a long winded explainer.
At work putting all this down from memory so some errors may exist. Let me know if there are.
I think the problem is to access the controls of the main window, isn`t it?
You can define an event of changing user`s choise and access MainWindow control by using the following construction:
((MainWindow)Application.Current.MainWindow).MyTextBox
I've created a custom form that has a couple buttons and a Text box.
This custom form is opened by a click event button I have created on a Microsoft outlook add-in that I am working on attached to a 'Ribbon'. (Not sure if this matters, no problem here).
On the windows form, The first button simply saves the contents of the text file to disk.
The other button attempts to close the form. In this buttons click event I have tried the following two lines, separate and together
this.Close(); and this.Dispose();
When I use this button or the Form exit (the 'x' located in the upper right of a windows form) I receive the follow error,
COMException was unhandled by user
Exception from HRESULT: 0x800A01A8
When this error is thrown, it takes me to the 'Connect.cs' files following method,
public void OnBeginShutdown(ref System.Array custom)
{
this.toolbarButton.Delete(System.Reflection.Missing.Value);
this.toolbarButton = null;
}
I'm not sure how to begin troubleshooting this. I have done a fair amount of research but unfortunately haven't found much. I'm sure the problem might be the fact I have created a custom form with no experience and there are some 'housekeeping' or 'best practices' that I have not done or are aware of.
Anyone have insight into this?
I'm guessing a little here but that HResult for a COMException means Object Required,
So, when you are calling CommandBarButton.Delete one of two things is wrong.
Either you have already disposed the button instance or you should be passing true or false to the Delete call.
The button shouldn't be disposed until after it has been removed from the toolbar, and when it is disposed you may need to do a Marshal.ReleaeComObject to dereference it properly.
I wrote a bunch of code in the .cs file in c# for a winforms application. The application runs fine, and everything is in it's place.
Something like this:
using..
namespace Temp
{
public class Temp : Form
{
Button b1;
TextBox t1;
Temp()
{
b1.Text = "Some Text";
b1.Size = new Size(50,20);
...
}
void function1()
{
// stuff
}
static void Main()
{
Application.Run(new Temp());
}
}
}
How can I modify my code (or fix it somehow) so that the design view displays the elements in their correct positions and view so that I can visually edit them instead of having to trial/error everything.
Edit for Clarification
My application runs fine. The problem is, that I didn't use designer to create the application and so in the designer view, the app is empty. But not empty when I run it, since everything is positioned programmatically in the .cs file. My question is, how can I fix this, so that the designer shows the objects correctly.
There is no quick fix other than to redesign everything?
So to get this shown within the designer you have to know how the designer works.
For every MyForm.cs there will automatically be a file called MyForm.Designer.cs be created. Within this Designer file there will be only one function called InitializeComponents(). This function will be called within the constructor of your MyForm.cs file.
The design viewer itself is responsible for the Designer file, so any change to this file while the design view is open would normally be discarded. Also if you put some code into the designer file that is not needed be the designer will be truncated.
So the next question is, when will this truncation happen? When you freshly open the design viewer of a form, it will read in everything from the Designer.cs file without making any changes. If you make any changes onto the form by the designer the complete file will be rewritten with all the settings already read in including your latest changes.
This behaviour can be monitored if you open the designer file also as source code view, make some little changes in design mode and afterwards take a close look at the left of the source file. There will be the changes marked with a yellow or a green marker.
Now after all this stuff of informations, you can try the following procedure to get your code into the designer:
Open the design view and put some simple control onto your form (e.g. TextBox)
Save and close the design view and open the Designer.cs file as source file
Copy all your variables name of your controls at the end of the file, right below the textBox1 line
Copy all your control property settings within the InitializeComponent() function right below the property settings of the TextBox
Copy all your control constructors to the top of the file, right below the constructor of the TextBox
Save the file and open your form in design view
Select the dummy TextBox on the design view and delete it
This change within the DesignView leads to a complete rewrite of the designer.cs file, ordering all your manually added stuff the right way.
So this is the way to go. Last but not least another little trick:
Every programmer uses the using-statement to not write the whole path to every class (like System.Windows.Forms.TextBox), but the designer writes always the whole path. To make it a little easier for your copy and paste session you can also add a using statement at the top of the file. After saving and changing something in Design View all this stuff will be re-written automatically. So you don't need to add all this paths manually while your adding your stuff to the Designer.cs file.
Your best option is probably to use the properties panel in the designer to set the positions etc (or maybe just drag them?).
You could go digging around in the designer file for the form (something.Designer.cs), but this isn't a fantastic idea because it can be pretty sensitive to changing things in ways the designer doesn't expect. Having said that, it looks like you're not actually using the designer to make your form (the class would be partial, for one thing), in which case you're SOL.
In that case, you need to copy the designer code from CS to designer.cs. So that you can use designer. I think this is the simplest approach.
Looks like this file was hacked from a class file instead of being generated by the system when you create a new winform.
You need at least an InitializeComponent(); call in your constructor. However you are missing a lot of other code that is generated for you when you create the file such as Dispose().
Best bet would be to right click your project in the solution explorer and click Add Windows Form then start over.
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();
}
}