I have a base form containing some elements like this:
- pnlSearch of type Panel: search button
- pnlActions of type FlowLayoutPanel: add, edit, delete, export.. etc buttons
nothing is locked, both panels' modifiers are Private & buttons' modifiers are Protected
FlowLayoutPanel is used to customize options in the child forms (e.g. removing the delete option) without leaving empty spaces since the elements will flow accordingly.
In a child form, the search button only is accessible. Buttons in pnlActions are locked in the designer but by checking the properties Locked = False and Modifiers= Protected
Tried setting the pnlActions' modifiers to Protected but it's still the same.
Any idea what's causing this behavior?
what's the difference between Panel and FlowLayoutPanel other than inner controls layout?
I'd post code samples if I've hand-coded anything but it's all generated by designer
I'm using VS 2013 on Win7 if that would matter
Thanks in advance
this is a problem of the Designer. if you do your changes via code all work...
The problem won't be resolved because the platform is not mainteined by Microsoft anymore.
I know it's an old question, but I share a possible solution, in case someone needs it.
We will create a class that inherits FlowLayoutPanel, I name it FlowLayoutPanelHeritable. You can place it in the namespace that you consider appropriate, for this example the namespace is WindowsFormsApp.
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace WindowsFormsApp
{
[Designer(typeof(ParentControlDesigner))]
public class FlowLayoutPanelHeritable : FlowLayoutPanel
{
}
}
First we must set the modifiers of the FlowLayoutPanel that is in FatherForm, in Protected. Now we must make a modification by code in FatherForm, accessing FatherForm.designer.cs. We will replace each instance of FlowLayoutPanel, by FlowLayoutPanelHeritable (in the creation, and initialization of variables). Then we save, and recompile.
Now if you access ChildForm, you will see that you no longer have the modification restriction at design time.
Important: if you want to edit FatherForm, you will have to access FatherForm.designer.cs and replace all the FlowLayoutPanelHeritable to FlowLayoutPanel again; When you finish editing, perform the reverse process.
Related
I just started working with Visual Studio C# and to be honest I didn't fully understand what happens when we chose to hide a form or a user control.
My intuition tells me this hide/show method is kind of "inefficient" way to get an user through all the functions of my app.
So I am asking you guys if there is another workaround to "load" user control parts in a form.
Right now my main_menu form has all the user control objects placed on the form, but hidden, and I am using buttons to show them.
Is there a better way to achieve the same result? (I was thinking of a workaround like having an empty panel where I can load the User Control - not sure if possible)
Thank you!
You can create the controls on the fly and add them to or remove them from the Controls collection. On the class level, define this field
private Control _currentPanel;
You can use a more specific type here, if you are deriving all your panels from a common base type.
Then change the panel with
// Remove previous one.
if (_currentPanel != null) {
Controls.Remove(_currentPanel);
}
// Add new one
_currentPanel = new MyNewPanel();
//TODO: possibly set the panels Docking property to Fill here.
Controls.Add(_currentPanel);
In the example I am working with the form's Controls collection; however, you might have to use the Controls collection of some container control holding the panel.
Currently I'm creating a really big project in Visual Studio 2012, where there are some common settings for each form ("Cancel" and "Save" buttons, Methods that change in every form but have the same name, font sizes and types, form color etc.) it will save me a lot of time if I could do all the design a single windows form and when I edit or modify it, have the changes reflected in the other forms as well.
Let's say I need 10 forms, to create them I would choose this default format and have my menu and basic objects already placed and designed; then after 10 forms I decided to move a button a bit, but don't want to go to every form and move it; just change it in the original format, refresh and all my forms will have that button in the new location.
I used Templates as recommended by Can one set the default properties for new WinForms created in Visual Studio?. But I still have the issue that if I change something in the template it won't refresh in every other form created with the template to that point.
I've already thought of changing the InitializeComponent in the WinForm default format, but this is not recommended and I wouldn't want any errors from this later on.
Any ideas?
Thanks in advance
Inheritance will work for your solution.
Create "base" form with all "common" controls
Create new "derived" form and change form to inherit from your "base" form.
If you have some common logic in base form, which need to be "overridden" in derived forms - put it to the virtual method
// Base form
protected virtual void Close()
{
// Base logic
}
private void CloseButton_Click(object sender, EventArgs e)
{
Close();
}
// In derived form - just override "Close" method
protected override void Close()
{
// custom logic - will be executed when "Close" button clicked
}
In base form leave empty space for custom controls. Because you will not be able access baseform controls through designer in derived form.
Another approach - Model-View-ViewModel(MVVM)
- Introduce own UserControl with common controls(view) which have property - instance of ViewModel.(Viewmodel will contains behaviour logic and possibility to change "base" settings.)
- Add this user control to all "derived" forms and set UserControl.ViewModelProperty to instance which will represent logic for this particular form.
Without knowing "full" context of your goals - difficult to suggest more, but I am pretty sure you can build maintainable relations between forms, which can share common logic and view.
No, there is nothing you can do. Once you use a template to create a project or a file, it becomes a one-off. You have to edit it manually, or use a text editor that is powerful enough to employ a find and replace with pattern matching and capture group insertion.
A strange issue with Visual Studio 2008. I have a winforms application that contains several forms.
On one of my forms, the mouse pointer has a square shape around the arrow, like in the attached image. I cannot get rid of it, no matter what I tried. The square keeps moving along with the mouse pointer. Seems funny, but it's really frustrating, really, because I cannot use the drag-and-drop functionality at all. This prevents me from working with the designer. Imagine that I cannot grab the edge of any control to resize it. I can move controls, though...
What is particular about this form is that it is derived from another form, like this:
public partial class MyForm : BaseForm
BaseForm is also derived from Form. I'd say nothing too uncommon.
Thanks for any idea.
Later Edit:
I found why I got an error when entering into MyForm's designer.
BaseForm has an Microsoft.Reporting.WinForms.ReportViewer component. The component was added as a private member.
When working with MyForm's designer, VS was automatically generating a new Microsoft.Reporting.WinForms.ReportViewer member for MyForm, so I got 2 members with the same name. One defined in the base class, one in the derived class.
I solved this by declaring the base class's member as public and regenerating the derived class, so no need to duplicate things.
Anyway, unfortunately, this did not solve my designer issue with the mouse cursor...
Chances are that the BaseForm has soe logic in its constructor or other eventhandlers that is supposed to run at runtime but not at DesignTime.
You could use:
if (!this.DesignMode)
{
// runtime only
}
to block out some logic at design mode
Have you tried,
Cursor = Cursors.Default;
or setting it to some other Cursors value?
I have a lot of different UserControls and would like to maintain consistent UI settings (mainly colors and fonts). My first try was this:
public class UISettings
{
//...
public void SetupUserControl(ref UserControl ctrl)
{
ctrl.BackColor = this.BackColor;
}
}
to be called in every control like this:
settings.SetupUserControl(ref this);
As this is read-only it cannot be passed by ref argument so this does not work. What are other options to keep consistent UI without manually changing properties for every item?
Inheritance! If you have a form or control that will constantly be using the same styles and you want to set that as your base, just create your own user controls that inherit from a form/control. By default all of your forms will inherit from "Form". Instead of inheriting from the default form, create a new user control that inherits from Form, and then have that as your base class.
CustomForm : Form // Your custom form.
Form1 : CustomForm // Inherit from it.
...the same works for components. If you want a button to have the same styles across the board, create a user control and have it inherit from the button control -- then use the custom control.
Whenever you want to make a change to your base styles, or any settings, simply change your custom controls settings -- your new forms/controls will automatically be updated!
Do the same thing. Don't pass it by ref. UserControl is a reference object already, so there's no need to pass it into your method using the ref keyword.
You may also want to consider a recursive method that will find all the UserControls on the form and pass it into your method.
How about a base class which provides such settings?
Two answers:
You don't need ref, controls are objects are reference types. Just drop it.
Create a Base UserControl and derive your controls form that base. You can still do that, just edit the class definitions of the controls. For new controls you can follow the Wizard.
A tip: setup the styling in the baseControl. Then make sure the derived controls don't override, the best way to do that is scanning the *.Designer.cs files and remove all settings that you know should come from the base.
I am writing a Base UserControl, that will be inherited by a bunch of other UserControls. I need to enforce a certain design for all these descendant controls (e.g. a couple of buttons must be on the top along with a label or two).
The rest of the descendant UserControl area is free to have whatever on it.
Initially, I thought that I could just plop a Panel onto the Base UserControl, set the Dock=Fill and the designer of the descendant control would be forced to add all the UI into this said panel. Then, I could resize the panel to my content.
But that is not the case - when you drop a control (say a GridView) onto the descendant UserControl, it adds it to the .Controls collection of the descendant user control, not the Panel I added.
Is there a way to force a certain layout from the Base user control?
The short answer is "Yes"... However to get this behavior delves into the ugly world of writing your own designers which you have to associate with the each control which will need to inherit the special placement into the content panels..
The following link should be a good starting point as it gives an overview of what needs to be done as well as provides sample code.
http://support.microsoft.com/?id=813808
Be warned, however, this is not a trivial task. And there is a lot of code (30+ files) to sift through in order to understand how to implement a designer. It's been about 2 years since I have tried this.
On the other hand, have you considered changing your design to have a single parent control which has the labels and buttons, and which populates the content area with the appropriate child control(s)? Perhaps even having your child controls for the content area implement a specific interface to guarantee a contract so that the parent can interact with them without having to know a specific class name?
AngryHacker -
I went off thinking this was to be very easy, and found myself embarking on an interesting journey into WinForm design-time land. This is definitely not as easy as it was in VB6 :-) .
Anyhow, after a bit of research, I found a number of references to a method called EnableDesignMode(). However, this is not directly accessible from a WinForm component. This has to be called from a class that subclasses ParentControlDesigner, which is injected into the UserControl via a Designer attribute. In this project, I have called the subclass ButtonBarDesigner, and have overridden the Initialize() method, which allows me to tell the designer that the component ButtonBar has a child component fillPanel which can be accessed via the public property "FillPanel".
At this point, it seemed to be working. I managed to drop a control onto the ButtonBar and it was appearing in the fill panel. However, if you saved the form, and then reloaded it, it turned out that the control was instantiated, but not placed in the ButtonBar control. It seems that there was one sneaky last bit which the documentation for EnableDesignMode() conveniently leaves out. You need to have the DesignerSerializationVisibility attribute on the FillPanel property. Adding this attribute makes this work.
You need a reference to System.Design in your project for the design time stuff to work.
The following code is for the putative base class, ButtonBar:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Threading;
namespace ForceUserControl
{
[Designer(typeof(ButtonBarDesigner))]
public partial class ButtonBar : UserControl
{
public ButtonBar()
{
InitializeComponent();
}
/// <summary>
/// Returns inner panel.
/// </summary>
/// <remarks>Should allow persistence.</remarks>
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Panel FillPanel
{
get { return fillPanel; }
}
}
private class ButtonBarDesigner : ParentControlDesigner
{
public override void Initialize(IComponent component)
{
base.Initialize(component);
Panel fillPanel = ((ButtonBar)component).FillPanel;
// The name should be the same as the public property used to return the inner panel control.
base.EnableDesignMode(fillPanel, "FillPanel");
}
}
}