Embedding User Controls a bad idea? - c#

I am embedding usercontrols in a panel and using DevExpress Navigator control to navigate from one to the other. What I am concered about is any implications to this method?
I would give examples of what I am concerned about but then I wouldn't need to ask this question...
I have a primary form, ShellForm that has a docked Navigator Control on the left and a docked Panel Control for the rest. I then dock a User Control, say ucSearchPage, in the Panel when the link is clicked.
public partial class ShellForm : XtraForm
{
private ucSearch searchPage = new ucSearch();
private ucEnrollments enrollmentPage = new ucEnrollments();
private ucGeneral generalInfoPage = new ucGeneral();
private ucContacts contactPage = new ucContacts();
public ShellForm()
{
InitializeComponent();
}
private void ShellForm_Load(object sender, EventArgs e)
{
this.pnlShellHost.DockControl(this.searchPage);
}
private void navSearch_LinkClicked(object sender, DevExpress.XtraNavBar.NavBarLinkEventArgs e)
{
this.pnlShellHost.DockControl(this.searchPage);
}
private void navEnrollment_LinkClicked(object sender, DevExpress.XtraNavBar.NavBarLinkEventArgs e)
{
this.pnlShellHost.DockControl(this.enrollmentPage);
}
The code for DockControl() is as follows -->
public static void DockControl(this Control control, UserControl userControl)
{
userControl.Dock = DockStyle.Fill;
control.Controls.Clear();
control.Controls.Add(userControl);
}
Are there any implications to this approach? Is it just plan stupid?
I am one of those programmers that had to learn to run before walking so I have a tendency to fall flat on my face!
There will be about 30 User Controls in all.
Any insight is welcomed and appreciated!

IMO it is not a bad idea at all to embed user controls. In fact, that is exactly what they were meant for. Because every control inherits from the same base class you can build a tree structure of controls using the Composite pattern. This will allow you to create just about anything you would like.
If you think of a basic web page, this is actually what you are doing anyways: placing one element in another, or embedding them. You can have multiple divs in other divs etc. This is essentially what you are doing when you embed user controls as the user controls render to basic HTML.
Hope this helps.
EDIT: To address the concerns in your comment... I don't think you will have a problem from the data entry standpoint. The reason why is because you are using different user controls for your enrollment control and search control. I'm assuming you are overriding the OnLoad event in each of those user controls right? What happens on post back is that the Search's OnLoad will be hit if the search control was loaded, while the enrollment's OnLoad will be hit if that was loaded.
Because of the polymorphism of the user controls, you can handle the data for those controls separately.

Related

user control that other developers can add controls to it and "inherit" the behavior of all controls on my control

hi all and sorry for the confusing title... can't find the right words yet.
just out of curiosity, I am playing with c# user control, I created a control that is built from a panel, a textbox that is being used as a filter, and some labels / buttons/ etc... that are being filtered.
when ever you change the text of the textbox, all the controls on the panel are visible / invisible depending if their Text property contains the Text of the textbox. very simple.
but I want this user control to be such that the user that uses it can drop more labels or controls to it and they will behave the same, I can't figure out how to do that..
when I am editing the control (adding controls to it), it works as expected and the new controls behave as the old ones without code modifications, but only when I am editing the user control and not when using it.
when I am dragging the user control to a form, I can not add controls to it... when I try to add a label to the control - it is just added to the form and not to the control and therefore the text box is not influencing the added label. what should I do if I want to be able to add the control to a form and then add some controls to the control?
I will be happy for some pointers.
here is the relevant code:
private void textBox1_TextChanged(object sender, EventArgs e)
{
foreach (Control c in panel1.Controls)
{
if (c.Text.Contains(textBox1.Text))
{
c.Visible = true;
}
else
{
c.Visible = false;
}
}
}
edit - pictures added.
as you can see - i typed 1 in the filter text box and all the controls except button1 are now invisible - and of course the bad behaving label.
Thanks,
Jim.
This problem can be solved easily by following the guidelines in
https://support.microsoft.com/en-us/kb/813450 which decribes step by step How to make a UserControl object acts as a control container design-time by using Visual C#
In order to modify the user control as a design time control container
add the following code to the Declarations section:
using System.ComponentModel.Design;
Apply the System.ComponentModel.DesignerAttribute attribute to the control as follows:
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public class UserControl1 : System.Windows.Forms.UserControl
{
...
}
Then build the solution.
the control will appear as usual in the Toolbox and can be added to forms. Additional controls such as buttone , text boxes etc.. can be added to the control as required.
You describe one of the reasons why I almost never use UserControls. Anything that isn't done to the original UC must be done in code..
You can instead make it a class that is not a UserControl, ie make it a simple subclass of Panel (or FlowLayoutPanel as I do here merely for convenience, while dropping stuff on it during my tests).
class FilterPanel : FlowLayoutPanel
{
TextBox tb_filterBox { get; set; }
Label st_filterLabel { get; set; }
public FilterPanel()
{
st_filterLabel = new Label();
st_filterLabel.Text = "Filter:";
this.Controls.Add(st_filterLabel);
tb_filterBox = new TextBox();
this.Controls.Add(tb_filterBox);
// st_filterLabel.Location = new Point(10, 10); // not needed for a FLP
// tb_filterBox.Location = new Point(100, 10); // use it for a Panel!
tb_filterBox.TextChanged += tb_filterBox_TextChanged;
}
void tb_filterBox_TextChanged(object sender, EventArgs e)
{
foreach(Control ctl in this.Controls)
{
if (ctl != tb_filterBox && ctl != st_filterLabel)
ctl.Visible = ctl.Text.Contains(tb_filterBox.Text);
}
}
}
Now after placing it on a form (or whatever) you (or whoever) can drop Controls onto it in the designer and they'll be part of its Controls collection, just like you want it and will behave as expected..
Two notes on subclassing Controls:
If you break one during developement, the Form(s) using it will be broken, too, until you fix the problem. So take a little extra care!
For the Designer to display the Control it always needs to have one parameterless constructor, like the one above. Even if you prefer to have the ability to hand in parameters, one parameterless constructor must still be there or the designer will get into trouble!

Having UserControl signing up for event in MainForm

I am currently working on a Winforms solution where I have a Main Form containing a ToolStrip and a Panel. The solution is meant as an administrative tool.
The panel is filled with a user control, normally containing an input form or a ListView of some sort.
Depending on which button is clicked the user control in the Panel is replaced with another user control.
So far so good. Now the trickier part is that the user can be administrator of one or more departments, and if the user is admin of more than one departments, some of the user controls will be displaying a ComboBox where the admin can choose which department to admin. However some of the user controls are independent of the department and therefore does not contain the ComboBox.
Now the thing is that instead of adding the ComboBox to the user control that are department-specific I have been thinking about adding it to the Main Form and have the user controls, when instantiated, look at what department is picked and populate the data accordingly.
But my problem is: When a user then is picking another department in the ComboBox I will have to tell the child (user control) that the value has changed.
My first thought was to have the user control - when instantiated - sign up for the change-event. But that I can not seem to figure out how to get working (it is easier going the other way around).
Another approach that I have been thinking about is to call a method in the user control from the Main Form whenever the value has changed. However there will be no guarantee that such method exists as not all user controls need this functionality.
Is there a preferred/golden solution to this? Something I am missing or is this just bad practice/design?
Thanks in advance!
When childcontrols needs to be notified, i would implement an Interface. You should avoid crosscalling methods/event handling because events could lead to "ghost controls" and unreadable code.
I would do something like this: (pseudo/not tested)
public interface IDepartmentChanged
{
void DepartmentChanged(int departmentId);
}
public class UserControl1 : UserControl, IDepartmentChanged
{
public void DepartmentChanged(int departmentId)
{
// refresh data
}
}
public class Form1 : Form
{
// Add all UserControls to a List => _controls
private List<UserControl> _controls = new List<UserControl>();
public Form1()
{
InitializeComponent();
_controls.Add(userControl11);
}
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
int selectedDepartmentId = ((MyData)comboBox1.SelectedValue).Id;
foreach (UserControl control in _controls)
if (control is IDepartmentChanged)
((IDepartmentChanged)control).DepartmentChanged(selectedDepartmentId);
// or even shorter:
foreach (IDepartmentChanged departmentChanged in _controls.OfType<IDepartmentChanged>())
departmentChanged.DepartmentChanged(selectedDepartmentId);
}
On this method the childs functionality is totally separated from the parent.(OOP)
i created a form and a userenter code hereControl (called UserControl1) and added it to the form. i've added a comboBox to the form and then did:
public Form1()
{
InitializeComponent();
comboBox1.SelectedValueChanged += userControl11.comboBox1_SelectedValueChanged;
}
and then when the comboBox1 the user control knows about it and can re initiate

custom user control

I have designed custom user control in c# .This user control is include :
textbox,check box,button.
Now I want to consume designed user control in my project but the problem is I can't access to the textbox,checkbox,button EVENTS when consume user control in my form and there are only EVENTS for user control.how can I make it possible that each object events become accessible when consuming designed user control ?
In your user control set your control like "text-box" Modifiers property to Public.so when you add this user control to your form. you can access to your text box evens:
public Form1()
{
InitializeComponent();
userControl11.textBox1.TextChanged += new EventHandler(textBox1_TextChanged);
}
void textBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show("user control textbox.text changed");
}
you might need to manually create public events for the events of those controls which you want to be accessible from outside.
another way is, when initializing those controls in you user control, using public instead of private (which is automatically generated by VS), these code should be located in the xxx.Designer.cs, and they looks likeprivate System.Windows.Forms.Button button1. Then it can be accessed through MyUserControl.button1. But doing so, the entire control will be accessible from outside of your user control, which does not feel very well personally.
I think you should add public events to your custom control class, and make subscribing and unsubscribing there. Just like that:
public event EventHandler ComboboxClick
{
add { _combobox.Click += value; }
remove { _combobox.Click -= value; }
}
For more information see http://msdn.microsoft.com/en-us/library/8627sbea(v=vs.71).aspx
Edit: I would not recomend setting inner controls of your custom control as public properties, because it's a violation of encapsulation principle. You design your own control to do some specific job and clients of the control should stay unaware of its inner composition. Should you change the inner composition of your control in future (switch to some 3rd party textbox control, for example), you would only need to make changes in your custom control class, and its clients would still work properly as if nothing has happend. Here's a good koan about encapsulation =)

Passing Mouse Events to Base Control, search of a good solution

Hallo,
Thank you for reading. The Answers i get realy helped me, A LOT!
But to the Problem. I have UserControl as a base Class. The child Class adds its Controls on the UserControl, lets call first BaseControl and the second ChildControl.
At BaseControl Level i have some Delegates attached on some MouseEvents.
The Problem is that they will not fire, if there is an Child control added to them. So I know i can Take all the Mouseevents from all the the Childrensevent and tunnle them through. But thats first very dirty an second not enough. Cause i want to like Paint a Border around or move the BaseControl.
So my Question is realy: Is there a way to gain full access to the MouseEvents in at Base Control, if there are ChildControls added?
Thank you lots!
Thomas
EDIT:
Here is the snippets, hope you understand:
public partial class baseControl : UserControl
{
public baseControl()
{
InitializeComponent();
//will not be called
this.MouseUp += delegate(object sender, MouseEventArgs e)
{
// some code
};
}
}
public partial class child : baseControl
{
secretControl childControl;
public child()
{
InitializeComponent();
this.childControl= new secretControl ();
this.childControl.Visible = true;
//... ,more
this.forChildUsePanel.Add(this.childControl);
// works fine , as it will be called
this.childControl.MouseUp += delegate(object sender, MouseEventArgs e)
{
// some code
};
}
}
Reminder: This are snipptes, so for understanding purpose it cut some corners.
Simpelput:
I want to get some Mouse Event on every Control added to the BaseControl.
I believe you should attach the event handler to every single child control and not to the parent control, if you want to intercept it in the child.
What kind of controls are you adding? It might be a solution to customize these controls. If you add a Label for example, make a new MousePassthroughLabel which inherits from Label und whose inbuild MouseEvent simply fires the one of its parent control. Do this once for every type of control and use you own "MousePassthrough"-Controls instead of the native controls.
There is this new Microsoft technology, Reactive Extensions, which will make event-driven programming easier.

Calling Methods from seperate usercontrols in the same form

I really had no idea what to title this question.
Assume I have a windows form application. The GUI is complex enough to require two custom user controls, "LeftSide" and "Rightside" which each are composed from various buttons, labels, and maybe even another custom user control.
My question:
I am in in the scope of the "Rightside" control. How would I call a method from the "Leftside" control?
I am using Visual Studio 2008.
The simplest solution is to make a property on the RightSide control of type LeftSide, then set it to the LeftSide instance in the form designer.
You can then call public methods on the property.
However, this is poor design.
Each usercontrol should be a self-contained block that doesn't need to directly interact with other usercontrols.
You should consider restructuring your form.
Exact equivalent with standard WF controls: how to keep the text of one text box in sync with another:
private void textBox1_TextChanged(object sender, EventArgs e) {
textBox2.Text = textBox1.Text;
}
Necessary ingredients: an event on your user control that is fired when something interesting happens. And public properties.

Categories

Resources