Controls not working - c#

I have added my main class, from which I call buttons class, and that's where it's supposed to print out the button. The code is compiling ok, but I can't see the actual button. Seems to me it didnt inherit the controls properties. Thank you!
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Windows;
//main class
namespace Test
{
public partial class Form1 : Form
{
buttons button1;
public Form1()
{
InitializeComponent();
print_button();
}
private void print_button()
{
button1 = new buttons();
button1.print();
}
}//form
}//test
//---------------------------------------------------------------//
//buttons class
namespace Test
{
public class buttons : System.Windows.Forms.Control
class buttons
{
private Button button1;
public buttons()
{
}
public void print()
{
button1 = new Button();
button1.Location = new System.Drawing.Point(82, 44);
button1.Size = new System.Drawing.Size(977, 54);
button1.Text = "next";
Controls.Add(button1);
}
}//class
}//test

I have no idea what you are trying to accomplish with the code you have provided. In any event the reason this method doesn't work:
public void print()
{
button1 = new Button();
button1.Location = new System.Drawing.Point(82, 44);
button1.Size = new System.Drawing.Size(977, 54);
button1.Text = "next";
Controls.Add(button1);
}
is because the class 'buttons' does not define a Controls collection nor does it inherit from a class that exposes a controls collection. For example if you were to do this:
public class buttons : System.Windows.Form
{
...
}
Your code would then at least compile since the Form class exposes a Controls collection. It isn't entirely apparent what you are trying to accomplish though so this solution may not suit your needs. Post more information as appropriate and I will do what I can to help you.
-----Edit
It seems like you are trying to refactor your Form1 class from one of your comments above.
You could do something like this:
public class Form1 : Form
{
public void foo()
{
Controls.Add(buttons.print());
}
}
and modify your buttons class as:
public class buttons
{
public static Button print()
{
Button btn = new Button();
btn.Location = new System.Drawing.Point(82, 44);
btn.Size = new System.Drawing.Size(977, 54);
btn.Text = "next";
return btn;
}
}
This will then add a button to your main form's control collection once it is called. As wrote though this method is useless since it can only produce the same button over and over. I would modify the method so that it looks like this
public static Button print(Point buttonLocation, Size buttonSize, string buttonText)
{
Button btn = new Button();
btn.Location = buttonLocation;
btn.Size = buttonSize;
btn.Text = buttonText;
return btn;
}
And then the main form looks like this:
public void foo()
{
Controls.Add(buttons.print(new System.Drawing.Point(82, 44), new System.Drawing.Size(977, 54), "button text"));
}
Does this help?
--- Edit 2 ---
I am supplying this edit as a strictly academic example of how you could keep your main class (Form) 'cleaner' per the OP's request in the comments. I don't suggest using this method in production and would instead recommend using a pattern such as MVC, MVP, or MVVP. I am excluding examples of those patterns here because I think they exceed the skill level of the OP at this point in time and would only lead to more confusion.
Consider the following:
public class buttons
{
private Form _form = null;
public buttons(Form form)
{
_form = form;
}
public void print(Point buttonLocation, Size buttonSize, string buttonText)
{
Button btn = new Button();
btn.Location = buttonLocation;
btn.Size = buttonSize;
btn.Text = buttonText;
_form.Controls.Add(btn);
}
}
public class Form1 : Form
{
private buttons _buttons = null;
public Form1()
{
_buttons = new buttons(this);
}
public void foo()
{
buttons.print(new System.Drawing.Point(82, 44), new System.Drawing.Size(977, 54), "button text");
}
}
Now here is what is happening: when Form1 is instantiated it creates a new instance of the buttons class and passes a reference of itself into the buttons constructor (_buttons = new buttons(this)) internally the buttons class sets this reference to the local variable _form so, therefore, anything you do to the variable _form well be like if you were doing it directly to Form1. As you can see that is what happens in the print() method where a button is created and then added to the Controls collection of _form which is the same as calling Controls.Add from within Form1.
Does this make sense to you?

Your class buttons isn't a subclass of System.Windows.Forms.Control so it has no this.Controls member.
I suggest use use the WinForms Designer in VS instead of creating your own forms or controls by hand, at least while you're a beginner.
I also note that you should conform to .NET style conventions. Classes and public members should use TitleCase and should exist within a namespace. Change buttons to Buttons (if you want to use that name) and wrap it in a namespace block.

Related

Cannot declare a UserControl in file code

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;
}
}

Changing form control from user control

I'm trying to changing a user control informations (labels, pictures etc.) from auto added user control. But i cant do it.
Here's my code;
private void KitapButton_Click(object sender, EventArgs e)
{
BıtıkForm BForm = new BıtıkForm();
BForm.kitapGoruntuleme.Visible = true;
}
public partial class BıtıkForm : Form
{
//create controls public instance
public Label label;
public BıtıkForm()
{
InitializeComponent();
//initialize the control
label = new Label();
}
}
Now you can access it from other place like;
BıtıkForm BForm = new BıtıkForm();
BForm.label.Visible = true;
/////// But my Suggestion do not do it like that instead do it like below ///////
BıtıkForm BForm = new BıtıkForm(controlVisible);//Pass the bool value as parameter to the constructor of form
BForm.Show();
And then in form
public partial class BıtıkForm : Form
{
public BıtıkForm(bool controlVisible)
{
InitializeComponent();
//Set Control Visibility
someControl.Visible = controlVisible;
}
}
I didn't use C# too much but It's eventually object oriented. The mistake I made is; I was creating a new instance of 'BıtıkForm' everytime event fired. It could be solved by adding new property where event belongs, and property will carry 'BıtıkForm' object. So It can be managed trough all over the program.

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.

Unsure of the actual implementation of events/delegates across multiple classes

I've read through several pages here on Events and Delegates and understand the idea behind them but am unsure of how to use them across multiple classes. Until now, I've simply relied on the IDE to set everything up for me and I didn't realize it worked inside a single class alone.
public class MyForm : Form
{
public MyForm()
{
...
this.Controls.Add(menuBuilder.GenerateMenuForMyForm());
//load other controls into the form to visualize/manipulate data
}
public void UpdateDataInControls()
{
//reloads info into controls based on data in serializable class.
}
}
public class MenuBuilder
{
public MenuStrip GenerateMenuForMyForm()
{
MenuStrip menu = new MenuStrip();
...
ToolStripMenuItem loadfile = new ToolStripMenuItem();
loadfile.name = "loadfile";
loadfile.text = "Load File";
loadfile.Click += new EventHandler(loadfile_Click);
file.DropDownItems.Add(loadfile);
...
return menu;
}
void loadfile_Click(object sender, EventArgs e)
{
//Open a file dialog and deserialize file
//Need to send an event to MyForm letting it know that it needs to
//update controls in the form to reflect the deserialized data.
}
}
So in this instance, I have events working within a single class, but I'm unsure how to set things up so MyForm can receive an event from MenuBuilder. I have tried something like
loadfile.Click += new EventHandler(myFormObject.loadfile_Click);
and make the loadfile_Click() function in MyForm, but that seems counter-intuitive to the idea of driving functionality through events themselves since it needs the form's object itself to be passed into the constructor. If that's the case, I might as well just call the function directly.
Here is one simple way to achieve what your'e looking for. Its a basic event model where a class declares its events, and an observer class subscribes to it.
using System;
using System.Windows.Forms;
public class MyForm : Form
{
public MyForm()
{
var menuBuilder = new MenuBuilder();
menuBuilder.FileLoaded += (sender, args) => UpdateDataInControls();
Controls.Add(menuBuilder.GenerateMenuForMyForm());
//load other controls into the form to visualize/manipulate data
}
public void UpdateDataInControls()
{
//reloads info into controls based on data in serializable class.
}
}
internal class FileLoadedEventArgs : EventArgs
{
// customize event arguments if need be
// e.g. public string FileName {get;set;}
}
public class MenuBuilder
{
// declare event delegate
internal delegate void FileLoadedEvent(object sender, FileLoadedEventArgs e);
// declare event for observers to subscribe
internal event FileLoadedEvent FileLoaded;
public MenuStrip GenerateMenuForMyForm()
{
MenuStrip menu = new MenuStrip();
/*
ToolStripMenuItem loadfile = new ToolStripMenuItem();
loadfile.name = "loadfile";
loadfile.text = "Load File";
loadfile.Click += new EventHandler(loadfile_Click);
file.DropDownItems.Add(loadfile);
*/
return menu;
}
void loadfile_Click(object sender, EventArgs e)
{
// fire the event
FileLoaded(this, new FileLoadedEventArgs());
}
}

Accessing Form's Controls from another class

I have a windows forms application with some controls added to the designer. When I want to change something (LIKE) enabling a text box from inside the Form1.cs, I simply use:
textBox1.Enabled = true;
but now I have a separated class called class1.cs.
How could I enable textBox1 from a static function class1.cs?
NOTE: I did not try any code because I am totally clueless about doing this.
EDIT: Lot of edit.
public partial class Form1 : Form
{
// Static form. Null if no form created yet.
private static Form1 form = null;
private delegate void EnableDelegate(bool enable);
public Form1()
{
InitializeComponent();
form = this;
}
// Static method, call the non-static version if the form exist.
public static void EnableStaticTextBox(bool enable)
{
if (form != null)
form.EnableTextBox(enable);
}
private void EnableTextBox(bool enable)
{
// If this returns true, it means it was called from an external thread.
if (InvokeRequired)
{
// Create a delegate of this method and let the form run it.
this.Invoke(new EnableDelegate(EnableTextBox), new object[] { enable });
return; // Important
}
// Set textBox
textBox1.Enabled = enable;
}
}
This is just another method:
TextBox t = Application.OpenForms["Form1"].Controls["textBox1"] as TextBox;
You shouldn't really change UI controls in your Form from your class1, but instead create a method or a property in class1 that would tell if the textbox should be enabled or not.
Example:
// I changed the name class1 to MySettings
public class MySettings
{
public bool ShouldTextBoxBeEnabled()
{
// Do some logic here.
return true;
}
// More generic
public static bool SetTextBoxState(TextBox textBox)
{
// Do some logic here.
textBox.Enabled = true;
}
// Or static property (method if you like)
public static StaticShouldTextBoxBeEnabled { get { return true; } }
}
Then in your form:
MySettings settings = new MySettings();
textBox1.Enabled = settings.ShouldTextBoxBeEnabled();
// Or static way
textBox1.Enabled = MySettings.StaticShouldTextBoxBeEnabled;
// Or this way you can send in all textboxes you want to do the logic on.
MySettings.SetTextBoxState(textBox1);
You can pass the instance of your Form to the class
MyForm frm = new MyForm();
MyClass c = new MyClass(frm);
Then your class can take that instance and access the textbox
public class MyClass
{
public MyClass(MyForm f)
{
f.TextBox1.Enabled = false;
}
}
The design does not look OK
It is better to call the class in your form and based on the value returned, manipulate the textbox
//MyForm Class
MyClass c = new MyClass();
c.DoSomethings();
if(c.getResult() == requiredValue)
textBox1.enabled = true;
else
textBox1.enabled = false;
//MyForm Class ends here
UPDATE
public class Class1
{
public static int SomeFunction()
{
int result = 1;
return result;
}
public static void SomeFunction(out int result)
{
result = 1;
}
}
Usage
if(Class1.SomeFunction() == 1)
textBox1.Enabled = true;
else
textBox1.Enabled = false;
OR
int result = 0;
Class1.SomeFunction(out result);
if(result == 1)
textBox1.Enabled = true;
else
textBox1.Enabled = false;
You could let your class1 have an event to enable the Textbox.
public class Class1
{
public event Action<object, EventArgs> subscribe ;
private void raiseEvent()
{
var handler = subscribe ;
if(handler!=null)
{
handler(this,EventArgs.Empty);//Raise the enable event.
}
}
}
Let the class containing the TextBox subscribe to it somehow. In TextBox wrapper class
public class TextBoxWrapper
public void EnablePropertyNotification(object sender, EventArgs args)
{
TextBox1.Enabled = true ; //Enables textbox when event is raised.
}
public TextBoxWrapper()
{
class1Instance.subscribe+=EnablePropertyNotification ;
}
To access/modify a Form Element property, just write this in your outside Class.
Form1.ActiveForm.Controls["textBox1"].Enabled = true;
Where textBox1 is the variable name of TextBox.
What this actually does: Gets the active Form object's control specified by the name in string.
WARNING: Active form means the form which is currently open and focused on. If you do something else on your computer, with your minimized WindowsForm application, the Form1.ActiveForm will not get the form, instead, it will give null, which can lead to errors later. Be careful!
based on the answer from #vr_driver you can do that to avoid problems with other containers like groupbox, panels...
TextBox t = Application.OpenForms["Form1"].Controls.Find("textBox1", true)[0] as TextBox;
In this example you have a form called Main.cs and a class called MyClass:
In MyClass (Note: the name of my Form Class = 'Main'):
Main ui = new Main();
ui.toolStripProgressBarStickers.PerformStep();
In (FormName).Designer.cs so in my case Main.designer.cs change the appropriate control from 'private' to 'public':
public System.Windows.Forms.ToolStripProgressBar toolStripProgressBarStickers;
This solved it for me.
Thanks, Ensai Tankado
I had to do this at work and didn't find that any of these answers matched what I ended up doing, so I'm showing how I made it work.
First, initialize a copy of your class in your load event.
NameOfClass newNameofClass;
Then you want to bind to your class (in the load event):
textBox1.DataBindings.Add(new Binding("Enabled", newNameofClass, "textBox1Enabled"));
In your class, do the following:
private bool textBox1Enabled = false;
public bool TextBox1Enabled
{
get
{
return textBox1Enabled;
}
set
{
textBox1Enabled = value;
}
}
The false setting will initialize your textbox to being disabled
Set textBox1Enabled to true if you want to enable by default.
If you have other logic to enable/disable the textbox, simply modify the value of textBox1Enabled accordingly.
Very easy:
Create an Instance of your Form Object where want to access the Elements from.
Form1 ui = new Form1();
and now change the Form Elements to "public" - like this in the Designer Code:
...
public System.Windows.Forms.TextBox textBox6;
...
Now you can access them like this in your Code:
ui.textBox6 ...
I had the same problem. I used windows forms & Visual Studio to generate a UI in a utility with textbox, checkbox, and button controls but ALL the code was in the same class.
I'm rewriting the utility now that I know "more" OOP concepts and created actual objects and separate classes. I too had problems getting the separate classes to be able to access the form controls and any shared methods that are in the form class. I tried the various suggestions in this thread as well as other threads but none of those solutions worked for me.
What worked for me (not sure if its the right thing to do or not) was I had each class that needed to access the controls and forms methods inherit from the Form.
Here is the relevant part of the Form.cs file:
namespace Utility
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public void WriteNote(string noteText, bool asHeading = false)
{
//Writes Messages to the Message box in the UI
Font font1 = new Font(this.ResultsTB.Font, FontStyle.Bold);
Font font2 = new Font(this.ResultsTB.Font, FontStyle.Regular);
if (asHeading)
this.ResultsTB.Font = font1;
else
this.ResultsTB.Font = font2;
this.ResultsTB.AppendText(noteText + "\r\n");
}
My Form contains a textbox called DirTB and a method called "WriteNote" that writes info to another textbox called ResultsTB. Here is the class (at least as far down as the first successful call of the WriteNote method from the Form:
namespace Utility
{
public class AppServerDTO : Form1
{
#region App Server attributes
//attributes listed here
#endregion App Server attributes
#region AppServerDTO Constructor
public AppServerDTO()
{
//These methods verify and set all the attributes
VerifyInstallFolder();
}//end of constructor AppServer
#endregion AppServerDTO Constructor
#region AppServerDTO class methods
public void VerifyInstallFolder()
{
string keypath = string.Empty;
string locationVerification = DirTB.Text + #"\SomeText";
for (int i = 0; i < 4; i++) //allows 3 attempts to get the install folder right
{
if (Directory.Exists(locationVerification))
{
i = 4;//Kills the loop
}
else if (!Directory.Exists(locationVerification))
{
locationVerification = DirTB.Text + #"\SomeMoreText";
}
else if (!Directory.Exists(locationVerification))
{
WriteNote("The directory listed in the Install Directoy box is not reachable.");
WriteNote("Please select the correct directory.");
WriteNote("The correct directory is the folder that contains the ApplicationUpdates & UpdateManager folders.");
WriteNote(#"i.e. C:\Somewhere or D:\Someplace\Somewhere");
var folderpath = FolderPrompt(#"C:\");
DirTB.Text = folderpath; //updates the install folder textbox to the new location
keypath = folderpath;
i++;
}
}//end for loop
}//end VerifyInstallFolder
As long as you are very careful with what you mark as public vs private, it should be ok.
This is how you should do :
I wrote the code below in my form class :
public static Form1 form = null;
private delegate void SetImageDelegate(Image image);
public Form1()
{
InitializeComponent();
form = this;
}
public static void SetStaticImage(Image image)
{
if (form != null)
form.pic1.Image = image;
}
private void setImage(Image img)
{
// If this returns true, it means it was called from an external thread.
if (InvokeRequired)
{
// Create a delegate of this method and let the form run it.
this.Invoke(new SetImageDelegate(setImage), new object[] { img });
return; // Important
}
// Set textBox
pic1.Image = img;
}
and the code below should be in anouther class :
Form1 frm= Form1.form;
frm.pic1.Image = image;
Note that i changed private static Form1 form = null; to public static Form1 form = null;
Good Luck ... Written by Hassan Eskandari :)

Categories