I want to access fdtlc.Controls instead of fdtlc.flpFlightList.Controls
public partial class FlightDetailListControl : UserControl
{
public ControlCollection Controls //Error circular control reference has been made
{
get
{
return flpFlightList.Controls; // flpFlightList is a FlowLayoutPanel
}
}
public FlightDetailListControl()
{
InitializeComponent();
}
}
FlightDetailListControl and FlowLayoutPanel are both Controls, so they both already have a ControllCollection named Controls inherited from UserControl. You'll have to pick another name for your property in FlightDetailListControl.
Related
I am developing a set of custom controls for a specific application. I want to define properties which is universal over the set of controls for appearance purposes, for argument's sake let's make it CustomCtrl.AccentColor
I want to define that same property for my Windows form i.e. Form1.AccentColor and when I change it, all the custom controls' AccentColor should change, exactly like when I change the ForeColor of my form, all labels' and buttons' etc ForeColor changes with it.
Is it at all possible to do this or do I have to settle for the effort of looping through all custom controls and changing it one-by-one?
Short Answer
Since you can have a common base class for all your controls as you mentioned in comments, as an option you can create a base class and then add some properties with behavior like ambient properties (like Font) to the base control class.
Detailed Answer
An ambient property is a property on a control that, if not set, is retrieved from the parent control.
In our implementation, we get the value from parent Form using FindForm method. So in the implementation, when getting the property value, we check if the value equals to default value and if the parent from has the same property, we return the property value of the parent form, otherwise we return the property value of the control itself.
After adding XXXX property, in this scenario we also should implement ShouldSerializeXXXX and ResetXXXX methods to let the designer when serialize the property and how to reset value when you right click on property and choose reset.
MyBaseControl
using System.Drawing;
using System.Windows.Forms;
public class MyBaseControl : Control
{
public MyBaseControl()
{
accentColor = Color.Empty;
}
private Color accentColor;
public Color AccentColor
{
get
{
if (accentColor == Color.Empty && ParentFormHasAccentColor())
return GetParentFormAccentColor();
return accentColor;
}
set
{
if (accentColor != value)
accentColor = value;
}
}
private bool ParentFormHasAccentColor()
{
return this.FindForm() != null &&
this.FindForm().GetType().GetProperty("AccentColor") != null;
}
private Color GetParentFormAccentColor()
{
if (ParentFormHasAccentColor())
return (Color)this.FindForm().GetType()
.GetProperty("AccentColor").GetValue(this.FindForm());
else
return Color.Red;
}
private bool ShouldSerializeAccentColor()
{
return this.AccentColor != GetParentFormAccentColor();
}
private void ResetAccentColor()
{
this.AccentColor = GetParentFormAccentColor();
}
}
MyBaseForm
public class BaseForm : Form
{
[DefaultValue("Red")]
public Color AccentColor { get; set; }
public BaseForm()
{
this.AccentColor = Color.Red;
}
}
Form1
public partial class Form1 : BaseForm
{
public Form1()
{
InitializeComponent();
}
}
i think you can create inherited class from Control class and define your common properties on there then inheriting your custom controls from that class and use parent property to access container (like Form) and get property value from it
Basically I have 2 projects, a form and a user control.
I need both of them to be in different projects but the form need to refer to the user control as it is using the user control. And the user control will need to refer to the form as it is using one of the form class. When I add the second one because it need the , VS will complain circular dependency which is understandable. How do I solve this?
Logically the form should depend on the user control. You could create an interface to replace the form within the user control project, and then have the form implement that interface.
Example user control project;
public interface IForm
{
string MyString { get; }
}
public class MyUserControl : UserControl
{
public IForm Form { get; set; }
private void ShowMyString()
{
String myString = Form.MyString;
...
}
}
Example Form project
public class MyForm : Form, IForm
{
public MYString { get "My String Value"; }
}
I think the root cause of your problem is that you haven't separated your concerns between the form and the control properly.
Since you have a (somewhat generic) control, it shouldn't depend on the form. All of the logic of the control should reside within the control itself. The form should only black-box consume the control: add it, set public fields, call public methods, etc. anything else is a violation of encapsulation.
Sometimes, controls may need to know things about their parent form. In this case, I would suggest something as simple as adding a Parent field to the child control.
if you need something more specific from the form, you can always add an interface; the interface should only list those things that the control needs from the form. For example, if you need the size, you can add:
public interface IControlParent {
int Width { get; }
int Height { get; }
}
This way, you clearly see the dependencies (what the control needs from the parent), and if the parent type/contract changes, you don't need to do as much to change your control class.
You must sepárate your code, its never a good idea to have a reference to an application assembly, if you try to reuse it in the future, the applications exe should go with the control.
So, take the class from the form project and move it to the control project or create a library project, put the class on it and reference it from your control and your app projects.
You should use an event (delegate). Let's assume that inside your form project you created one class: Form1. And inside user control you defined UserControl1.
UserControl1 needs to instantiate and call a method from Form1:
public class Form1
{
public void Execute(string sMessage)
{
Console.WriteLine(sMessage);
Console.ReadLine();
}
}
UserControl1:
public class UserControl
{
public Func<object, object> oDel = null;
public void Execute()
{
oDel?.Invoke("HELLO WORLD!");
}
}
And from the class that instantiate UserControl, let's call it ParentClass:
public class ParentClass
{
public void Execute()
{
UserControl oUserControl = new UserControl();
oUserControl.oDel = Form1Action;
oUserControl.Execute();
}
public object Form1Action(object obj)
{
string sObj = Convert.ToString(obj);
Form1 oForm = new Form1();
oForm.Execute(sObj);
return null;
}
}
This approach gives the responsibility of handling an event to the high level class.
I have a combobox on a usercontrol. I can expose the datasource however I cant expose the actual bindings.
If you add a normal combobox to a form and go to the databindings property you can choose selected value, text etc.
After this is chosen the designer automatically creates a
combobox.databindings.add("SelectedValue", datasource, columname, true));
How can I expose a combobox on a user control so that it has the above behavior
It's probably not considered best practice to expose your controls like this since after all, part of the point of using a UserControl is to hide the details of the child controls.
Try exposing the control on the UserControl as a property:
public partial class UserControl1 : UserControl {
public UserControl1() {
InitializeComponent();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ComboBox ComboBox {
get {
return this.comboBox1;
}
}
}
If you are only interested in the control's DataBindings, then try to just expose that information:
public partial class UserControl1 : UserControl {
public UserControl1() {
InitializeComponent();
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ControlBindingsCollection ComboDataBindings {
get {
return this.comboBox1.DataBindings;
}
}
}
I need to understand how to utilize a ToolTip with a custom UserControl. Just creating the ToolTip on a form and assigning the specific control a ToolTip (via SetToolTip) obviously will not work.
What properties do I need to give the custom UserControl in order to assign ToolTip text to it? Do I need to add a ToolTip on the usercontrol form? How can I go about doing this?
Please provide a code sample or something for me to visualize.
Thank you!
Put a ToolTip on your UserControl (use the designer, just like you would put one on a form), and add a public property to your UserControl like:
public string TextBoxHint
{
get
{
return toolTip1.GetToolTip(textBox1);
}
set
{
toolTip1.SetToolTip(textBox1, value);
}
}
Create SetToolTip method in user control and set tooltip for each user control's subcontrol:
public partial class SomeUserControl : UserControl
{
public void SetToolTip(ToolTip toolTip)
{
string text = toolTip.GetToolTip(this);
toolTip.SetToolTip(subControl1, text);
toolTip.SetToolTip(subControl2, text);
// ...
}
}
Set tooltip text for user control instance in parent control designer. This adds in .designer file:
this.toolTip1.SetToolTip(this.someUserControl1, "Some text.");
Call SetToolTip method of user control instance with ToolTip parent control instance from parent control's constructor:
public partial class ParentForm : Form
{
public ParentForm()
{
InitializeComponent();
someUserControl1.SetToolTip(toolTip1);
}
}
This is the correct way to implement a serialized ToolTip property:
public partial class YourControlClass : UserControl
{
// Serialized property.
private ToolTip toolTip = new System.Windows.Forms.ToolTip();
// Public and designer access to the property.
public string ToolTip
{
get
{
return toolTip.GetToolTip(this);
}
set
{
toolTip.SetToolTip(this, value);
}
}
Why can't I access the tabcontrol from within myclass.cs?
The tabcontrol is in form1.cs and my code that tries to create a new tabpage is in myclass.cs. I've even tried setting tabcontrol property to public but that didn't work.
just change the modifier on the control to public.
Once you do that and you have Form myForm = new Form();
you will be able to do:
myForm.myTAB.TabPages.Add(myTabPage);
(You will need to create the TabPage of course.
I'd suggest to wrap the TabControl in an public readonly property on the form's codebehind file, rather than making the control itself public. Just for the sake of code security (like being able to reassign your TabControl to something new).
public TabControl MyTabControl {
get {
return privateTabControl;
}
}
Also, don't forget you'll need an instance to your form in MyClass, otherwise you can't access instance members like "MyTabControl" or even public instance fields if you've chosen so.
I suggest you embed a reference to the TabControl on the Form in the Class myclass.cs.
You could do this either by defining a constructor for myclass that took a TabControl as a parameter, or, by defining a Public Property in myClass that holds a reference to a TabControl. Both ways are illustrated here :
public class myclass
{
// using "automatic" properties : requires C# 3.0
public TabControl theTabControl { get; set; }
// parameter-less 'ctor
public myclass()
{
}
// optional 'ctor where you pass in a reference to the TabControl
public myclass(TabControl tbControl)
{
theTabControl = tbControl;
}
// an example method that would add a new TabPage to the TabControl
public void addNewTabPage(string Title)
{
theTabControl.TabPages.Add(new TabPage(Title));
}
}
So you can set the TabControl reference in two ways from within the Form with the TabControl :
myclass myclassInstance = new myClass(this.tabControl1);
or
myclass myclassInstance = new myClass();
// do some stuff
// now set the TabControl
myClassInstance.theTabControl = this.tabControl1;
An alternative is to expose a Public Property of type TabControl on Form1 : but then you have to think about how myclass will "see" the current "instance" of Form1 ... if there is more than one instance of Form1 ? In the case there is one-and-only-one TabControl you could use a static Property on Form1 to expose it.
In this case "who is creating who" becomes of interest : if the Form is creating myclass; if myclass is creating the Form; if both myclass and the Form are being created by another entity in the application : I think all these "vectors" will bear on what is the best technique to apply.
Are you creating an instance of form1 in myclass.cs and checking the existence of tabControl on that instance? If you want to access form1.tabControl in myclass.cs then you will need to make the tabControl as public static in form1.cs
This might be an overly simple suggestion, and you've probably solved this by now, but did you remember to include using System.Windows.Forms at the top of the class file? Visual Studio may not include that reference automatically when adding a new class file.