Cannot declare a UserControl in file code - c#

I have had a problem. I create an UserControl and I save it, it appears in ToolBox. I can drop it from ToolBox normally. However, I can not declare it as a variable in the file code. Can you help me, please? And it is file code of UserControl
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Music_Player_Project_IT008N13.Controls;
namespace Music_Player_Project_IT008N13.Music_design_User_Control
{
public partial class LocationPanel : UserControl
{
public LocationPanel()
{
InitializeComponent();
}
public delegate void DoEvent(string maSo, string tenSV, string khoa, string diemTB);
public event DoEvent RefeshDgv;
private void btnDelete_Click(object sender, EventArgs e)
{
}
}
}

When you "drop it from the ToolBox normally", the Designer generates a member declaration for a new user control and also adds it to the forms Control collection. As I understand it, your question states that you would like to declare your user control variable in code. If this is the goal, we have to do the same thing that the Designer would do and add it to the Controls collection of the container you want to put it in.
Example
Add a FlowLayoutPanel using code, then add 3 CustomUserControls to it also in code.
public partial class MainForm : Form
{
public MainForm() => InitializeComponent();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
// Declare a flow layout panel in code.
// Add it to the main form control collection
var flowLayoutPanel = new FlowLayoutPanel
{
Name = "flowLayoutPanel",
Dock = DockStyle.Fill,
};
this.Controls.Add(flowLayoutPanel);
for (char c = 'A'; c < 'D'; c++)
{
var userControl = new CustomUserControl
{
Name = $"userControl{c}", // No space, start with lowercase
Text = $"UserControl {c}", // Visible name
Margin = new Padding(10, 2, 10, 2),
Width = flowLayoutPanel.Width - 20,
};
flowLayoutPanel.Controls.Add(userControl);
}
// T E S T
CustomUserControl? loopback = GetUserControl("userControlA");
Debug.Assert(loopback != null, "Expecting to retrieve user control by name");
}
Then, to use the control, retrieve it from the Controls collection by name.
CustomUserControl? GetUserControl(string name)
{
var layoutPanel = Controls["flowLayoutPanel"] as FlowLayoutPanel;
return layoutPanel.Controls[name] as CustomUserControl;
}
}
Where:
public partial class CustomUserControl : UserControl
{
public CustomUserControl() => InitializeComponent();
public new string Text
{
get => label1.Text;
set => label1.Text = value;
}
}

Related

Textbox readonly property not working in TextBox made by me

I have a textbox (TextBoxMoeda) made by me, but, even when the textbox property readonly is set true. nothing happens. Anyone knows how to implement the code to resolve this problem?. Please help me?
public class TextBoxMoeda : TextBox
{
private double dp;
private string fmt = string.Empty;
private int _CasasDecimais = 0;
[Category("TextBoxMoeda")]
public virtual bool SomenteLeitura
{
get => base.ReadOnly;
set
{
base.ReadOnly = value;
Invalidate();
}
}
//Code Continues .......
}
WPF
You want the IsReadOnly property, not the ReadOnly property.
For example:
Create a new WPF App (.NET Framework) project called DeleteMe
In MainWindow.xaml, delete the Grid
In MainWindow.xaml.cs, use this code:
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace DeleteMe
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var tm = new TextBoxMoeda();
this.AddChild(tm);
tm.SomenteLeitura = true;
}
public class TextBoxMoeda : TextBox
{
[Category("TextBoxMoeda")]
public virtual bool SomenteLeitura
{
get => base.IsReadOnly;
set
{
base.IsReadOnly = value;
}
}
}
}
}
The textbox will be readonly (i.e. I can't type anything into the textbox).
WinForms
The code already appears to work in WinForms. These steps will produce a working project:
Create a new Windows Forms App project called DeleteMeAgain
Overwrite all of the Form1.cs code with this:
using System.ComponentModel;
using System.Windows.Forms;
namespace DeleteMeAgain
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var tm = new TextBoxMoeda();
this.Controls.Add(tm);
tm.SomenteLeitura = true;
}
public class TextBoxMoeda : TextBox
{
[Category("TextBoxMoeda")]
public virtual bool SomenteLeitura
{
get => base.ReadOnly;
set
{
base.ReadOnly = value;
Invalidate();
}
}
}
}
}
The textbox will be readonly (i.e. I can't type anything into the textbox).
Windows Form: User Control
Do this:
Create a new Windows Forms App called DeleteMe3
Set Target Framework to .NET Core 3.1 (Long-term support)
In your project, create a new UserControl with the filename TextBoxStack.cs
Overwrite all of the code for that user control with this:
using System.ComponentModel;
using System.Windows.Forms;
namespace DeleteMe3
{
public partial class TextBoxStack : TextBox
{
[Category("TextBoxStack")]
public virtual bool SomenteLeitura
{
get => base.ReadOnly;
set
{
base.ReadOnly = value;
Invalidate();
}
}
}
}
An error will appear. Go to the source of the error and delete that line.
Build the solution
Add your new user control to Form1
Select the new user control on the form
Change the SomenteLeitura property to True
Run the project. The textbox should be grey and readonly.

Generate custom C# code in Form.cs while dropping user control in Form1.cs at design time

I have a user control that I can drag and drop in the Form1.cs[Design] mode. The designer will auto-generate code for this user control in the Form1.Designer.cs
What I would like to get aswell is: at the moment I am adding the user control to the form by dragging I wont to have code generated in my Form.cs that is pointing to the properties and controls on that user control.
Example of user control:
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public string TextInTextBox
{
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
}
So now when I drag it on the form in the Form1.cs[Design]. I won't part of code like this to be generated in my Form1.cs:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
AddText();
}
// this code below to be auto-generated
private void AddText()
{
userControl11.TextInTextBox = "";
}
}
I think I should be looking for something like inheritance or interface but I would like this to happen for each instance of that user control.
If someone could point me direction what to look for it would be great. Thanks.
Usually you don't need to generate code manually when you want to assign a property when dropping a control from toolbox, for example you can easily do this:
public MyUserControl()
{
InitializeComponent();
MyTextProperty = "Something";
}
And it will be serialized automatically.
But there are more options for more advanced requirements.if you know the options that you have, you may choose based on your requirement. Here is some options:
Assign some value in constructor or to the property
Assign value to properties using ToolboxItem, it will overwrite the value which you assign in constructor.
Generate some code for Load event of form and initialize property there. It's useful for complex code generations, for example when you drop a data source it will generate some code to load data and add to load event of form.
Assuming you have assigned Something to MyTextProperty in constructor, then when you drop the control in form, here is what will be generated in designer.cs:
this.myUserControl1.MyTextProperty = "Something";
If you use the ToolboxItem solution to assign Something else to the property, the result in designer.cs file will be:
this.myUserControl1.MyTextProperty = "Something else";
And if you decide to use third option and generate event handler code, the result in designer.cs file will be:
this.Load += new System.EventHandler(this.Form1_Load);
and the result in cs file will be:
private void Form1_Load(object sender, EventArgs e)
{
myUserControl1.MyTextProperty = "Even something else!";
}
Example
Here is a full code of MyUserControl, MyUserControlToolboxItem and MyUserControlDesigner. You can comment Designer and/or ToolboxItem attributes and close all designers and clean and rebuild the solution and drop an instance of the control on the form to see how it works.
using System.CodeDom;
using System.Collections;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing.Design;
using System.Linq;
using System.Windows.Forms;
using System.Windows.Forms.Design;
[Designer(typeof(MyUserControlDesigner))]
[ToolboxItem(typeof(MyUserControlToolBoxItem))]
public partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public string MyTextProperty { get; set; } = "Something";
}
public class MyUserControlToolBoxItem : ToolboxItem
{
protected override IComponent[] CreateComponentsCore(IDesignerHost host)
{
IComponent[] componentsCore = base.CreateComponentsCore(host);
if (componentsCore != null && componentsCore.Length > 0
&& componentsCore[0] is MyUserControl)
(componentsCore[0] as MyUserControl)
.MyTextProperty = "Something else"; ;
return componentsCore;
}
}
public class MyUserControlDesigner : ControlDesigner
{
public override void InitializeNewComponent(IDictionary defaultValues)
{
base.InitializeNewComponent(defaultValues);
var component = Control;
var eventBindingService = (IEventBindingService)this.GetService(
typeof(IEventBindingService));
var componentChangeService = (IComponentChangeService)this.GetService(
typeof(IComponentChangeService));
var designerHostService = (IDesignerHost)GetService(typeof(IDesignerHost));
var rootComponent = designerHostService.RootComponent;
var uiService = (IUIService)GetService(typeof(IUIService));
var designerTransaction = (DesignerTransaction)null;
try
{
designerTransaction = designerHostService.CreateTransaction();
var e = TypeDescriptor.GetEvents(rootComponent)["Load"];
if (e != null)
{
var methodName = "";
var eventProperty = eventBindingService.GetEventProperty(e);
if (eventProperty.GetValue(rootComponent) == null)
{
methodName = eventBindingService
.CreateUniqueMethodName(rootComponent, e);
eventProperty.SetValue(rootComponent, methodName);
}
else
methodName = (string)eventProperty.GetValue(rootComponent);
var code = this.GetService(typeof(CodeTypeDeclaration))
as CodeTypeDeclaration;
CodeMemberMethod method = null;
var member = code.Members.Cast<CodeTypeMember>()
.Where(x => x.Name == methodName).FirstOrDefault();
if (member != null)
{
method = (CodeMemberMethod)member;
method.Statements.Add(
new CodeSnippetStatement($"{Control.Name}" +
$".MyTextProperty = \"Even something else!\";"));
}
componentChangeService.OnComponentChanged(rootComponent,
eventProperty, null, null);
eventBindingService.ShowCode(rootComponent, e);
}
designerTransaction.Commit();
}
catch (System.Exception ex)
{
if (designerTransaction != null)
designerTransaction.Cancel();
uiService.ShowError(ex);
}
}
}

Application with Chrome-Style Tabs using EasyTabs in WinForms

I am trying to create a C# Application with Chrome-Style Tabs using EasyTabs in WinForms, but I am getting the following error code:
The designer must create an instance of type 'EasyTabs.TitleBarTabs' but it cannot because the type is declared as abstract.
I have followed the Youtube-tutorial beneath as a guideline.
https://www.youtube.com/watch?v=WVFjegJK8EY
Code:
using System;
using EasyTabs;
namespace WindowsFormsApp1
{
public partial class AppContainer : TitleBarTabs
{
public AppContainer()
{
InitializeComponent();
AeroPeekEnabled = true;
TabRenderer = new ChromeTabRenderer(this);
}
public override TitleBarTab CreateTab()
{
return new TitleBarTab(this)
{
Content = Form1
{
Text = "New Tab"
}
};
}
private void AppContainer_Load(object sender, EventArgs e)
{
}
}
}
It is normal to see this error when you try to view AppContainer.cs directly.
The designer must create an instance of type 'EasyTabs.TitleBarTabs' but it cannot because the type is declared as abstract.
Let that not deter you from achieving what you wanted to achieve. Ignore the error and simply right click on AppContainer.cs and select View Code
using EasyTabs;
namespace WindowsFormsApp1
{
public partial class AppContainer : TitleBarTabs
{
public AppTabs()
{
InitializeComponent();
AeroPeekEnabled = true;
TabRenderer = new ChromeTabRenderer(this);
Icon = mBible.Properties.Resources.appico;
}
public override TitleBarTab CreateTab()
{
return new TitleBarTab(this)
{
Content = new Form1
{
Text = "New Tab"
}
};
}
}
}
That should be enough to generate new tabs for you.
Now to create tabs easily lets assume you have a form 'MainForm' and the tab you want to be generating is 'Form1' here is what we do
using System;
using System.Windows.Forms;
using EasyTabs;
namespace WindowsFormsApp1
{
public partial class MainForm : Form
{
public static AppContainer tabbedApp = new AppContainer();
public MainForm()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
tabbedApp.Tabs.Add(new TitleBarTab(tabbedApp)
{
Content = new Form1
{
Text = "New Tab"
}
});
tabbedApp.SelectedTabIndex = 0;
TitleBarTabsApplicationContext applicationContext = new TitleBarTabsApplicationContext();
applicationContext.Start(tabbedApp);
this.Hide();
}
}
}
You can always add to your tabs a new tab easily by calling this code on another form
AppContainer.tabbedApp.Tabs.Add(new TitleBarTab(AppContainer.tabbedApp)
{
Content = new Form2 { Text = "Another Tab" }
});
AppContainer.tabbedApp.SelectedTabIndex = 0;
I hope that helps and anyone looking for help on similar issues.

Inheriting from a form c#

everybody. My plan is to create a separate class, in which I would declare all the labels and textbox values. But to do so I have to inherit from a form. The problem is that when I inherit from a form my class becomes a form and calls elements from itself. Setting the properties of labels and textboxes to public did not help. Any ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Assignment2v3
{
class Declarations : Form1
{
public List<Label> ErrRep
{ get; set; }
public List<TextBox> TextBoxes
{ get; set; }
public List<ComboBox> ComboBoxes
{ get; set; }
public Declarations()
{
ErrRep = DeclareErrorReports();
TextBoxes = DeclareTextBoxes();
ComboBoxes = DeclareComboBoxes();
}
List<Label> DeclareErrorReports()
{
var ER = new List<Label>();
ER.Add(errorReport1);
ER.Add(errorReport2);
ER.Add(errorReport3);
return ER;
}//Would be used if try catch worked
List<TextBox> DeclareTextBoxes()
{
List<TextBox> TextBoxes = new List<TextBox>();
TextBoxes.Add(textBoxPizza1);
TextBoxes.Add(textBoxPizza2);
TextBoxes.Add(textBoxPizza3);
return TextBoxes;
}//Puts all textBoxes into a list
List<ComboBox> DeclareComboBoxes()
{
var ComboBoxes = new List<ComboBox>();
ComboBoxes.Add(comboBoxPizza1);
ComboBoxes.Add(comboBoxPizza2);
ComboBoxes.Add(comboBoxPizza3);
return ComboBoxes;
}//Puts all comboboxes into a list
// ^ Boring declarations
}
}
You should probably inherit from UserControl instead. With your own UserControl, you can add it to one or more forms in one or more places.
There are plenty of tutorials out there which guide you in creating your own WinForms UserControl.

Adding controls to a custom form

I created a custom form (FormBorderStyle = FormBorderStyle.None).
I draw my own caption bar at the top with my own custom caption buttons (Close, Maximize ...).
Now my only problem is adding normal user controls to that form. If I give these controls a location, the locations are relative to the form's top (including the caption bar).
I override the default ClientSize & ClientRectangle using the 'new' keyword, which allows me to adjust it (thus removing the caption bar out of it).
This does not seem to work and I haven't been able to figure out how to do this properly without 'hacking' the ControlAdded event (which is still buggy).
protected override void OnControlAdded(ControlEventArgs e)
{
base.OnControlAdded(e);
if (e.Control.GetType() != typeof(VlufiCaptionButton /* Caption buttons: close, minimize & maximize, should not be included */))
{
e.Control.Location = new Point(e.Control.Location.X + ClientRectangle.X, e.Control.Location.Y + ClientRectangle.Y);
e.Control.LocationChanged += Control_LocationChanged;
}
}
private void Control_LocationChanged(object sender, EventArgs e)
{
if (!childControlLocationChangedHandled)
{
System.Diagnostics.Debug.WriteLine("changing");
Control cControl = (Control)sender;
childControlLocationChangedHandled = true;
cControl.Location = new Point(cControl.Location.X + ClientRectangle.X, cControl.Location.Y + ClientRectangle.Y);
}
else
childControlLocationChangedHandled = false;
}
This is the code I currently use, but it's superbuggy & I'm still having other problems with my customly drawn border.
Does anybody know how I should correctly handle this ?
I found a decent solution: I added a ContainerControl to the form & I position & size this according to the form, then whenever adding a control to the form, it should be added to the ContainerControl. Still not a proper solution, but it's the best one so far.
I'd still appreciate if someone came up with another solution.
read comments for detail:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public partial class Form1 : Form
{
int dy = 0;
public Form1()
{
InitializeComponent();
//i add a panel to top form
//( for simulating your caption bar) and get its height
dy = panel1.Height; //for yours its your caption bar height
}
private void button1_Click(object sender, EventArgs e)
{
//adding button control between form top and panel end area
//( simulate in your caption bar )
Button btn = new Button();
btn.Location = new Point(panel1.Location.X+40,panel1.Location.Y+10);
btn.Text = "Salam";
this.Controls.Add(btn);
}
//in control added event i add dy ( height of ignored area) to control Location
private void Form1_ControlAdded(object sender, ControlEventArgs e)
{
e.Control.Location = new Point(e.Control.Location.X, e.Control.Location.Y + dy);
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
}
}
Ok after all, I have finally found a working and pretty nice solution.
What I did is override the Controls property of my custom Form, using my own custom ControlCollection.
So this is what I got in my custom form:
public Control.ControlCollection RealControls
{
get
{
return base.Controls;
}
}
public new CustomControlCollection Controls { get; private set; }
public ContainerControl ControlContainer { get; set; }
And this is the custom ControlCollection:
public class CustomControlCollection
{
public VlufiForm Owner { get; private set; }
public CustomControlCollection (VlufiForm pOwner)
{
Owner = pOwner;
}
public void Add(Control c)
{
Add(c, false);
}
public int Count
{
get
{
return Owner.ControlContainer.Controls.Count;
}
}
public Control this[int index]
{
get
{
return Owner.ControlContainer.Controls[index];
}
}
public void Add(Control c, bool isUsable)
{
if (isUsable)
Owner.RealControls.Add(c);
else
Owner.ControlContainer.Controls.Add(c);
}
public void SetChildIndex(Control c, int nIndex)
{
Owner.ControlContainer.Controls.SetChildIndex(c, nIndex);
}
}
This is just an example custom control collection, you could add more methods in it (thus kind of inheriting ControlCollection more).
I haven't found any bugs in this system yet, it works perfectly at the moment.
EDIT: found a bug, if you dock a control in Visual Studio's Designer Mode, it will dock in the whole form, this doesn't appear when running though.

Categories