I have created a Visual Studio Add-In that adds a form to an existing Project in the opened solution.
This is how I create the form:
string templatePath = sol.GetProjectItemTemplate("Form.zip", "csproj");
//sol is an EnvDTE80.Solution2
proj.ProjectItems.AddFromTemplate(templatePath, formName);
//proj is an EnvDTE.Project
After that I can successfully get the reference to the ProjectItem of the added form, then I can get a reference to the System.Windows.Forms.Form, and through this reference I can add a button to the form like this:
Button btn = new Button();
btn.Text = "my funky button";
btn.Name = "newButton";
btn.Size = new Size(150, 23);
btn.Location = new Point(30, 30);
frmNewForm.Controls.Add(btn);
//frmNewForm is a System.Windows.Forms.Form
And then the button is successfully added to the form:
However, when I try to save this form, it just won’t save. I click Visual Studio’s [save] button, it just doesn’t turn gray. Even if I click [Save All], the form won’t be saved. Then I close Visual Studio, reopen it, and open the project to which I have added the new form with my Add-In, and the new button simply isn’t there. Just an empty form.
I’ve even tried saving the project and the solution programmatically through the following code:
itemForm.Save(itemForm.Name);
//itemFrom is an EnvDTE.ProjectItem
proj.Save(proj.FullName);
//proj is an EnvDTE.Project
I’ve thought that this would be because the instance of the Visual Studio that I was using to test my Add-In is a debug one, opened right after I run my Add-In. But I’ve tried using the installed Add-In (which remained automatically after running it), and the problem persisted.
Update
I’ve just noticed two things:
1) the button only appears on the design of the form, and nowhere else. And it doesn’t even let me select it to see it’s attributes.
It’s name doesn’t appear in Intellisense, in the object list, or even on the design document of the form.
As a test, I’ve added a button manually, and this one I can select, and interact with it:
What I could get from that is that I am not adding the button properly.
Then the new question regarding the button would be: How can I add a new button to a form created through EnvDTE in a way that I can interact with it in design time ?
2) While trying to see the differences from my funky button and my Manually added button, I’ve attempted something I hadn’t before with a programmatically created form: instantiate and run it.
And here's how I've done it:
MyFunkyForm frm = new MyFunkyForm ();
frm.Show();
It flashes on the screen (apparently with none of my two buttons), and the execution ends. Even if I try to do something on it’s Form_load, it’s executed, then the form flashes, and the execution is ended (the form is closed and debugging is over), as if I had called the Close() method.
Then the additional question would be: Did I skip a step while adding the form, or am I not creating it properly at all ?
you are adding a form to a c# project, I think you should not instantiate the form alone by itself like you did but if you want to see it you should execute the application.
I don't know how to do this, never tried myself, found this, hopefully it's helpful:
http://www.mztools.com/articles/2006/mz2006016.aspx
Related
I'm having a strange issue that maybe being caused by my ignorance.
I have a treeview with an .AfterSelect and any time that i change the design of my form (in the deign view) the code gets removed for some reason.
here is my code
this.lstTreeView.AfterSelect += LstTreeView_AfterSelect; < this is the code that gets removed
this.lstTreeView.Location = new System.Drawing.Point(194, 56);
this.lstTreeView.Name = "lstTreeView";
this.lstTreeView.Size = new System.Drawing.Size(220, 498);
this.lstTreeView.TabIndex = 6;
this is the code that it allows to work.
private void LstTreeView_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{
TreeNode CurrentNode = e.Node;
string fullpath = CurrentNode.FullPath;
MessageBox.Show(fullpath);
NrDirSearch(fullpath);
}
if anyone can give me some advice on why the .AfterSelect is being removed that would be really helpful.
I suggest you:
in the windows form designer, click the tree view to select it
in the properties grid click the lightning bolt and scroll to find the AfterSelect event
right click the name AfterSelect and choose reset
hit save all
Close out of the soution entirely/shut down visual studio
restart/reload the solution
Go back to the AfterSelect event as above, the box for which should be empty
click the drop down and choose your existing event handler
save all, quit and restart vs and check that the setting stayed
If you're finding it didn't stick, check that you don't have your designer open in another program e.g. A text editor that keeps autosaving an old version of the file that lacks the event handler?
Incidentally, the above process is how you add event in Design view - click the relevant control, lightning bolt, scroll to event wanted, double click the name of the event and you will be transported to your own code behind with a new named eventhandler created and ready to be filled
If you don't write any code in it, and go back to the designer and Reset the event as per the bulleted list instructions then your event handler method in your code will disappear. If you write code into the event handler then it is not removed when doing a reset, only empty handler methods are removed during reset
Side note: be careful with Undo if you see a message saying something like "performing this undo will cause a loss of work elsewhere" it usually indicates that the windows form design or designer.cs code will change as a result of actioning the undo
Designer files are safe to edit manually and it's sometimes necessary if the contents have gotten into a state where they are crashing the designer. I most often encounter this when deleting event handler s from my code that are still referenced in the designer. A screen appears saying a problem is preventing the forms designer from appearing, indicating the error line in the designer file. I have additionally in the past edited the designer directly to set large numbers of properties without the faff of using the designer - be mindful not to have a windows forms designer open at the same time as editing the designer.ca file because the forms designer will probably overwrite your changes. So long as you keep in mind that opening the same file in any two different editors at the same time can lead to conflict and loss of work, and take steps to ensure that edits in one editor are reflected in another before proceeding with further edits in the other editor, you'll be fine :)
Edit: having said that paragraph above, Mickey D made me realise an important point I'd overlooked:
The designer.cs file is read by the forms designer and uses to build the contents of the form, buttons, properties etc. As such if you are going to edit the designer.cs in a text editor you should limit your edits to only those things the forms designer can make use of, understand, represent and preserve when it next writes the file. Adding a line to set a button to enabled is fine. Removing a line that is causing it to crash is also good. Putting 27 methods that implement your entire program's database access strategy in is not a good idea as it will not be heeded or used to build the form when the designer reads the file and hence lost when the designer writes the file. If you're unsure of the difference between what will and won't be preserved stick to removing or fixing existing lines only rather than adding new lines of code
You should never[1] modify *.designer.cs files. They are code generated. Any changes you make are subject to being overwritten.
Instead either use the WinForms GUI Forms Designer to visually setup event handlers or you can do so in code in your form’s code-behind .cs file.
There are plenty of resources on the Net on how to use the WinForms designer.
[1] see Caius Jard's comment below for an exception to the rule that I concur with
I'm working on a simple Outlook 2016 VSTO with a custom ribbon that contains a button and one custom form. I am currently trying to figure out how to display the custom form I created in button click action. I tried instantiating a new form of the custom form (FormAddGroups) type and .Show(); it, but there is something in the constructor I don't understand.
formAddGroups = new FormAddGroups(xxx);
formAddGroups.Show();
It asks me for a formRegion from the current project in the xxx arguement, but I'm not quite sure how to access it, or if it's even the right way of showing it.
I'm also considering creating a custom message class on that button click, but I'm not sure if that's even possible.
Is that the right approach or should I go back?
Call MAPIFOlder.Items.Add("IPM.Note.MyCustomClass") to create the new item and display it (MailItem.Display).
I'm struggling to find how to set up a multiple form project in Visual Studio with stack-like organization(ie undo,redo history / back,forward web browser/ mobile app navigation). So far, I have multiple forms that are related to each other but the subsequent item opens as a new window rather than replacing its preceding form.
That is to say that every time I click a button to navigate to the next page, a new window is generated with content when I'd rather have the content load on the same window, much like how web browsers usually behave.
There seems to be How to have a user navigate multiple "screens" within one form/window? which mentions MDI, which from what I've gathered is ideal for creating a situation where multiple sub-windows are created in one main window, which is different from what I'm shooting for. Although I'm building this using Visual Basic, I imagine that my issue is not tied to a specific .net language as it is tied to the GUI toolbox items in Visual Studio itself. Any assistance would be much appreciated.
Convert each form into a user-control and place all of those on a panel on a main-form and use their visibility property to hide and show as you need.
3 Steps to convert
1. Create New control,
2. copy all the textboxes etc from the old form to the control designer
3. copy the code behind as appropriate.
Then do a build, the control should appear in the toolbox for the main form
If each "page" depends on other pages, you may need to add methods to each control to handle that.. Like
Public Sub Refresh_Controls() or some such
NOTE:
You may only want to make the BODY part be on the user-control. The Navigation arrows etc should probably be their own "common" controls.
BTW: You could also do this by putting everything on the same form, with nested table layout panels, hiding or showing the appropriate panel. However, that gets really hard to work with in Visual studio if there are a lot of pages. It is a little easier to maintain with user-controls.
Try the following in a new project. Create a new VB Forms project. Before doing anything to it, create a User Control using "Project" | "Add User Control...". Give it the name "StackingControl". Add the following variables for the class:
Private TopText As New Label()
Private OurFormStack As New Stack(Of Form)()
In the "New" method after "InitializeComponent()" add:
TopText.Text = "The stack is empty"
Controls.Add(TopText)
We are creating a label ("TopText") and adding it to the User Control. I will explain later why we are doing that in code instead of the designer.
Also add the following methods:
Public Sub AddForm(ByVal f As Form)
If OurFormStack Is Nothing Then
Throw New ApplicationException("FormStack is null")
End If
Controls.Clear()
OurFormStack.Push(f)
f.FormBorderStyle = FormBorderStyle.None
f.TopLevel = False
f.ShowInTaskbar = False
f.Visible = True
f.Dock = DockStyle.Fill
Controls.Add(f)
End Sub
Public Sub RemoveForm(ByVal f As Form)
If OurFormStack Is Nothing Then
Throw New ApplicationException("FormStack is null")
End If
Controls.Clear()
If OurFormStack.Pop() IsNot f Then
Throw New ApplicationException("The current form is not being removed")
End If
If OurFormStack.Count = 0 Then
Controls.Add(TopText)
Return
End If
Controls.Add(OurFormStack.Peek())
End Sub
The AddForm method will show a form and add it to the stack. RemoveForm will do the reverse. In AddForm, first we check to ensure that the stack exists. That is probably unnecessary but I am being a little over-cautious. Then we clear what is currently in the User Control, so if the TopText is there then it will be cleared or any form will be cleared out. Then we push the new form onto our stack. Then we do a few things that are necessary for putting a form into the User Control; we remove the border, tell Windows that the form is not a top-level window and to not show it in the Task Bar. Then we make the form visible and set the "Dock" property to "Fill" so the form fills the User Control. Then we add the form to the controls in the User Control and the form is the only thing in the User Control.
You can now build that. You might have to build it because you need the User Control to be in the Toolbox. After building the project, go to Form1 and then look at the Toolbox. At the top of the Toolbox you should see our StackingControl. Drag it and drop it onto Form1. Set the Dock property to Fill.
Then create a Form2 and Form3. For each of them, just create a label saying what they are (such as "Form Two" and "Form Three") and a button. In the button click handler, just call "Close". You don't really have to have the button; you could close the forms just by clicking the "x" in the upper-right of the forms.
Then add a menu strip to Form1. Create menu items for "Form Two", "Form Three" and "Exit". For "Exit" just call "Close()". Use the following for the other two menu items:
Dim f As New Form2()
AddHandler f.FormClosed, AddressOf SubForm_FormClosed
StackingControl1.AddForm(f)
That is for Form2. Use the same for Form3 except change the number of course. Add following method:
Private Sub SubForm_FormClosed(sender As Object, e As FormClosedEventArgs) Handles MyBase.FormClosed
Dim c As Form = TryCast(sender, Form)
If c Is Nothing Then
MessageBox.Show("sender is not a Form")
Return
End If
Try
StackingControl1.RemoveForm(c)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
End Class
Notice that the menu item click handlers both use the "SubForm_FormClosed" method; that is what "AddHandler f.FormClosed, AddressOf SubForm_FormClosed" does. It sets the FormClosed event handler for the form so that Form1 knows when the other form is closed; the other forms don't need anything extra for this to work. In the FormClosed event handler we first check to be sure that we are being called for a form (it is nearly certain we are) then we call StackingControl to remove the form. StackingControl will remove the form that is in it, pop off the next one and ensure (just to be sure) that it is the one that is expected, then it will either put the TopText label into itself or it will show the next form from the stack.
I have a Winforms app written in C#.
On one form there is a button which on the Click event opens a second form using the following code -
frmConflicts check = new frmConflicts(c);
check.Show();
frmConflicts has lots of controls on it, yet the Form which opens on the click event is a default Visual Studio form. By that, I mean the very small blank form which VS gives you when you Add New Item and select Form. There are no controls on it.
I've stepped through my code and the frmConflicts constructor is called, so I can't understand why a blank form is appearing instead.
Any clues?
Is the method initializing your Controls (like InitializeComponents) called at any time (like in your constructor) ?
Try setting the TopLevel property to True:
frmConflicts check = new frmConflicts(c);
check.TopLevel=true;
check.Show();
I'm writing a shared addin for Excel. It adds a CommandBarButton that when clicked opens a WPF window to collect some information from the user.
I wanted to keep the same WPF dialog in memory and reuse it so that if the user clicks the CommandBarButton again their previous values would still be there.
So I made a reference to my WPF dialog as a private member of my addin object that implements Extensibility.IDTExtensibility2.
I created the window during OnStartupComplete(), but for some reason when I run Excel the window immediately opens even though I never called ShowDialog() and when I do call ShowDialog() when the CommandBarButton is clicked to reopen the window it fails to load.
Does anyone know why this happens and what the correct way to handle this is?
Thanks very much for any help.
CODE UPDATE:
public void OnStartupComplete(ref System.Array custom)
{
MyDialog dlg = new MyDlg(); //This will open the dialog ?!?!
}
....
public MyDialog()
{
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
OnLoaded just wires up some event handlers for buttons and sets some ItemSources. Even if I comment it out it still open the window.
I have picked up on the fact that once a WPF window is closed it can't be reoped and this is by design. But why it opens automatically when constructed inside an excel addin is a mystery.
I've been able to reproduce your problem. In the WPF designer, make sure that the form's Visbility property is set to Collapsed. If you have it as Visible, it will automatically show when the dialog is created.