C# Trouble instanciating controls - c#

I'm attempting to make an array of control in C# but Visual Studio Express doesn't cooperate.
I'm getting a message at run time:
Object reference not set to an instance of an object.
The error occurs at the arrow below. How do I make this work?
public partial class Protocoltool : Form
{
// ... other stuff
// doesn't seem to make instances as I expect it would
// class String_Entry is defined lower
public String_Entry[] pt_entries = new String_Entry[NB_ENTRIES];
// Constructor for class protocol tool
public Protocoltool()
{
InitializeComponent();
// tried to make instances here but still doesn't work
//pt_entries = new String_Entry[NB_ENTRIES];
// Add the supposedly instanciated control in a tableLayoutPanel
EntriesGuiAdd();
// ... other stuff
}
private void EntriesGuiAdd()
{
for (int i = 0; i < NB_ENTRIES; i++)
{
// tried to make instances here but still doesn't work
//pt_entries[i].Create();
// tried to make instances here directly, but still doesn't work
-----------> pt_entries[i].textbox = new System.Windows.Forms.TextBox();
pt_entries[i].send = new System.Windows.Forms.Button();
//tableLayoutPanel1.Controls.Add(pt_entries[i].textbox, 0, i);
//tableLayoutPanel1.Controls.Add(pt_entries[i].send, 1, i);
}
}
} // end of protocoltool class
public class String_Entry
{
public TextBox textbox;
public Button send;
public int sequential_counter;
// A constructor here doesn't work at all
/*
... so I put the constructor here instead, but still it doesn't work
public void Create()
{
Console.WriteLine("creating entry");
// tried to make instances here but still doesn't work
textbox = new TextBox();
send = new Button();
send.Click += new System.EventHandler(this.bSend_Click);
}
*/
// ... other functions
}

You need to initialize pt_entries[i] before you can reference any properties of it.
pt_entries[i] = new String_Entry();
pt_entries[i].textbox = new System.Windows.Forms.TextBox();
pt_entries[i].send = new System.Windows.Forms.Button();

Related

ObjectDisposedException: Cannot access a disposed object

I am trying to create a program for my project in school, and I have come across a problem. I am using LinqPad premium and when I launch the program it starts fine. However, when I try and start it for the second or third time it throws the exception:
"ObjectDisposedException: Cannot access a disposed object."
"Object name: 'Form'."
Here is my code:
void Main()
{
MenuClass.Main();
}
class MenuClass
{
static public Form MenuWindow = new Form();
static public void Main()
{
MenuWindow.Height = 300;
MenuWindow.Width = 300;
MenuWindow.Text = "Menu";
Button btnPlay = new Button();
btnPlay.Left = 10;
btnPlay.Top = 290;
btnPlay.Text = "Reset";
//btnPlay.Click += btnReset_click;
Button btnTakeTurn = new Button();
btnTakeTurn.Left = 10;
btnTakeTurn.Top = 270;
btnTakeTurn.Text = "Take Turn";
//btnTakeTurn.Click += btnTakeTurn_click;
Graphics g = MenuWindow.CreateGraphics();
MenuWindow.Controls.Add(btnPlay);
MenuWindow.Controls.Add(btnTakeTurn);
//MenuWindow.Paint += f_Paint;
MenuWindow.Show();
}
}
The error occurs where it says "Graphics g = MenuWindow.CreateGraphics();"
and also when i take that out it does it on "MenuWindow.Show();"
Please help, as I am powerless in this situation.
Change:
static public Form MenuWindow = new Form();
static public void Main()
{
to:
static public void Main()
{
var MenuWindow = new Form();
to ensure that each invocation generates a new form.

C# Adding controls to a non-static form from a static class

In C#.NET, I am trying to add controls from a static class to a non-static class.
This is my code:
public static void AddMediaToPanel(string Title, string Description, string Source, string Cover, string Genre, int Rating)
{
PictureBox MediaCanvas = new PictureBox();
MediaCanvas.BackColor = Color.LightGray;
MediaCanvas.BorderStyle = BorderStyle.FixedSingle;
MediaCanvas.Size = new Size(150, 235);
MediaCanvas.Padding = new Padding(10);
try
{
MediaCanvas.ImageLocation = Source;
}
catch { }
var gui = new GUI();
gui.Controls.Add(MediaCanvas);
}
The GUI method stands for a Windows Form called 'GUI'.
I'm trying to make an open-source media center that allows you to add movies
to a repository.
The static void AddMediaToPanel must be static, because of this class:
public static void RetrieveMedia(string XMLFile)
{
// Declare the Media Collections
MediaCollection media = null;
// Declare the XML-readers
XmlSerializer serializer = new XmlSerializer(typeof(MediaCollection));
StreamReader sr = new StreamReader(XMLFile);
try
{
media = (MediaCollection)serializer.Deserialize(sr);
}
catch(Exception ex)
{
MessageBox.Show("The following media repository could not be loaded:\n" +
XMLFile + "\n" +
"Please check your code and try again later.\n\n" +
"Error Information: " + ex.Message, "Repository error",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
// Create new instance of the media class
sr.Close();
// Return properties
try
{
foreach (Video video in media.Video)
{
GUI.AddMediaToPanel(video.Title, video.Description, video.Source, video.Cover, video.Genre, video.Rating);
}
}
catch { }
}
I'm using .NET Framework 4.5.2.
Thanks in advance!
~ Kees van V.
This can't work this way. In your loop you are calling your static method:
foreach (Video video in media.Video)
{
GUI.AddMediaToPanel(video.Title, video.Description, video.Source, video.Cover, video.Genre, video.Rating);
}
But your static method creates a new Form each time, adds a control to it, then throw it away:
var gui = new GUI();
gui.Controls.Add(MediaCanvas);
You need to create your form once (outside of your static method), then have your static method return a control that you can add to your single Form instance.
Your instance method with the loop could look like:
var gui = new GUI();
foreach (Video video in media.Video)
{
var control = GUI.AddMediaToPanel(video.Title, video.Description, video.Source, video.Cover, video.Genre, video.Rating);
gui.Controls.Add(control);
}
In your current code you just create and throw away the gui form:
var gui = new GUI();
gui.Controls.Add(MediaCanvas);
You have to find the form instance you want the controls be added to:
public static GUI CurrentGui {
get {
GUI gui = Application
.OpenForms
.OfType<GUI>()
.LastOrDefault();
// no such form found, you may want to create the form
if (null == gui) {
gui = new GUI();
gui.Show(); // <- let's show it up
}
return gui;
}
}
...
public static void AddMediaToPanel(...) {
...
CurrentGui.Add(MediaCanvas);
}

How to use custom class with dynamic compilation

I have a form that i dynamicly compiled and i have a style class. When i copy this style class to my form source and compile it all works fine. But how can i use this style class without copy it to my form source. My main program that compile this form has this class, how can i use it? Maybe i can pass style class to this for with i compile it, like a var?
Program source:
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using Microsoft.CSharp;
namespace dynamic
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(newForm).Start();
}
public void newForm()
{
using (CSharpCodeProvider provider = new CSharpCodeProvider(new Dictionary<string, string>
{
{"CompilerVersion", "v4.0"}
}))
{
var parameters = new CompilerParameters
{
GenerateExecutable = false, // Create a dll
GenerateInMemory = true, // Create it in memory
WarningLevel = 3, // Default warning level
CompilerOptions = "/optimize", // Optimize code
TreatWarningsAsErrors = false // Better be false to avoid break in warnings
};
parameters.ReferencedAssemblies.Add("mscorlib.dll");
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
parameters.ReferencedAssemblies.Add("System.Data.dll");
parameters.ReferencedAssemblies.Add("System.Drawing.dll");
parameters.ReferencedAssemblies.Add("System.Xml.dll");
parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
var source = File.ReadAllText("form.txt");
CompilerResults results = provider.CompileAssemblyFromSource(parameters, source);
Type type = results.CompiledAssembly.GetType("myForm.Form1");
object compiledObject = Activator.CreateInstance(type);
type.GetMethod("ShowDialog", new Type[0]).Invoke(compiledObject, new object[] {});
MessageBox.Show("formClosed");
}
}
}
}
Style folder:
Form source:
using System;
using System.Windows.Forms;
namespace myForm
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var newTmr = new Timer { Interval = 1000 };
newTmr.Tick += count;
newTmr.Enabled = true;
}
private void count(Object myObject, EventArgs myEventArgs)
{
timer.Value2 = (Int32.Parse(timer.Value2) + 1).ToString();
}
private void button1_Click(object sender, System.EventArgs e)
{
MessageBox.Show("clicked");
}
private void nsButton1_Click(object sender, EventArgs e)
{
MessageBox.Show("button");
}
}
}
namespace myForm
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.nsTheme1 = new myForm.NSTheme();
this.nsButton1 = new myForm.NSButton();
this.timer = new myForm.NSLabel();
this.nsControlButton1 = new myForm.NSControlButton();
this.nsTheme1.SuspendLayout();
this.SuspendLayout();
//
// nsTheme1
//
this.nsTheme1.AccentOffset = 0;
this.nsTheme1.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(50)))), ((int)(((byte)(50)))), ((int)(((byte)(50)))));
this.nsTheme1.BorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.nsTheme1.Colors = new myForm.Bloom[0];
this.nsTheme1.Controls.Add(this.nsControlButton1);
this.nsTheme1.Controls.Add(this.timer);
this.nsTheme1.Controls.Add(this.nsButton1);
this.nsTheme1.Customization = "";
this.nsTheme1.Dock = System.Windows.Forms.DockStyle.Fill;
this.nsTheme1.Font = new System.Drawing.Font("Verdana", 8F);
this.nsTheme1.Image = null;
this.nsTheme1.Location = new System.Drawing.Point(0, 0);
this.nsTheme1.Movable = true;
this.nsTheme1.Name = "nsTheme1";
this.nsTheme1.NoRounding = false;
this.nsTheme1.Sizable = true;
this.nsTheme1.Size = new System.Drawing.Size(284, 274);
this.nsTheme1.SmartBounds = true;
this.nsTheme1.StartPosition = System.Windows.Forms.FormStartPosition.WindowsDefaultLocation;
this.nsTheme1.TabIndex = 0;
this.nsTheme1.Text = "nsTheme1";
this.nsTheme1.TransparencyKey = System.Drawing.Color.Empty;
this.nsTheme1.Transparent = false;
//
// nsButton1
//
this.nsButton1.Location = new System.Drawing.Point(100, 166);
this.nsButton1.Name = "nsButton1";
this.nsButton1.Size = new System.Drawing.Size(75, 23);
this.nsButton1.TabIndex = 0;
this.nsButton1.Text = "nsButton1";
this.nsButton1.Click += new System.EventHandler(this.nsButton1_Click);
//
// timer
//
this.timer.Font = new System.Drawing.Font("Segoe UI", 11.25F, System.Drawing.FontStyle.Bold);
this.timer.Location = new System.Drawing.Point(91, 82);
this.timer.Name = "timer";
this.timer.Size = new System.Drawing.Size(101, 23);
this.timer.TabIndex = 1;
this.timer.Text = "nsLabel1";
this.timer.Value1 = "Timer: ";
this.timer.Value2 = "0";
//
// nsControlButton1
//
this.nsControlButton1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
this.nsControlButton1.ControlButton = myForm.NSControlButton.Button.Close;
this.nsControlButton1.Location = new System.Drawing.Point(262, 4);
this.nsControlButton1.Margin = new System.Windows.Forms.Padding(0);
this.nsControlButton1.MaximumSize = new System.Drawing.Size(18, 20);
this.nsControlButton1.MinimumSize = new System.Drawing.Size(18, 20);
this.nsControlButton1.Name = "nsControlButton1";
this.nsControlButton1.Size = new System.Drawing.Size(18, 20);
this.nsControlButton1.TabIndex = 2;
this.nsControlButton1.Text = "nsControlButton1";
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(284, 274);
this.Controls.Add(this.nsTheme1);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.Name = "Form1";
this.Text = "Form1";
this.nsTheme1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private NSTheme nsTheme1;
private NSButton nsButton1;
private NSControlButton nsControlButton1;
private NSLabel timer;
}
}
Style source:
http://pastebin.com/CjmQQ9ND
Project source - https://yadi.sk/d/ChtMacrsraD4g
If you compile this source, all will work fine. That because i use style at form.txt file. I separated form from style at form.txt file. I have this style at my main program (you can see that at screenshot). How can i send this style class to my dynamicly compiled form, so form can use it.
You should be able to simply append the style to the source like so:
var source = File.ReadAllText("form.txt");
source += Environment.NewLine;
source += File.ReadAllText("style.txt");
Inside Form.txt file instead of the classes in order prescribes the macro:
namespace myForm
{
<%THEME%>
}
namespace myForm
{
<%THEMEBASE%>
}
Before compile, load style files and replace them in the code form:
//Load style files
var NSThemeSource = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"..\..\Class\Style\NSTheme.cs"));
var themeBaseSource = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"..\..\Class\Style\ThemeBase154.cs"));
var source = File.ReadAllText(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Form.txt"));
//Substitute in the form styles
source = source.Replace("<%THEME%>", NSThemeSource);
source = source.Replace("<%THEMEBASE%>", themeBaseSource);
P.S.
You can switch build action for style files at Embedded Resource so you can get style class from exe.
And use this helper - http://www.vcskicks.com/embedded-resource.php
Than you need to change code to:
var NSThemeSource = ResourceHelper.GetEmbeddedResource("Class/Style/NSTheme.cs");
var themeBaseSource = ResourceHelper.GetEmbeddedResource("Class/Style/ThemeBase154.cs");
First, you need to make classes, enums, and etc. public in NSTheme.cs and ThemeBase154.cs.
(it is better to put into some namespace, rather than having them in the global (dynamic) namespace).
Then, add parameters.ReferencedAssemblies.Add("dynamic.exe"); to you exe file (you might want to put your styles in a separate dll).
After it, in your form.txt add using dynamic; and remove qualifiers from new myForm.NSTheme() (so, it becomes new NSTheme()).
Now you can use your styles without coping them to your form class.
In case you miss something, check the CompilerResults results errors for particular problems.

How to get access to form's controls from class C#

I've got problem when I am trying to get access to form's controls from another class. My program is hanging in infinite loop. I know why, but I don't know how to write this correctly.
Here is Form1.cs (to my Form)
public Form1()
{
InitializeComponent();
Load config = new Load();
string[] data = config.readConfig("config.ini");
if (data.Length == 4) { //client
Client run = new Client();
run.startClient(data[1], Convert.ToInt32(data[2]));
}
else if (data.Length == 3) //server
{
Server run = new Server();
run.startServer(Convert.ToInt32(data[1]));
}
}
public void addLog(string dataLog){
richTextBox1.Text += dataLog;
}
and here is Client.cs file:
class Client
{
public void startClient(string ipAddr, int port)
{
Form1 form1 = new Form1();
TcpClient client = new TcpClient();
try
{
form1.addLog("Connecting...");
client.Connect(ipAddr, port);
form1.addLog("Connected to server: " + ipAddr + ":" + port.ToString());
}
catch
{
MessageBox.Show("We couldn't connect to server");
}
}
}
How can I change text value without running each time new form. Maybe There is something like run_once?
The infinite loop is here:
Form1:
//Always runs if the config file is a certain length
Client run = new Client();
Client:
Form1 form1 = new Form1();
Each constructor creates the other object, which in turn creates the first object, ad infintum.
If you need to get the form object to the client don't create a new one!. It doesn't work anyways, as your new form object knows nothing about the old one. Just pass it in:
public Client(Form1 form)
{
//Do whatever with it
}
//Form class
Client c = new Client(this);
Disclaimer: There are usually far better ways to do this, but you'll learn those as you get more familiar with design patterns/architecture.

ObjectDisposedException while Showing a Form

I keep getting an ObjectDisposedExpection when I need to get a Form to show.
Do you guys maybe know how to do this? In the foreach by NotitiesForm.Show() I get the error ObjectDisposedExpection. I am programming in Visual Studio Ultimate 2012 C#.
RichTextBox NotitiesTB = new RichTextBox();
private Form NotitiesForm;
/// <summary>
///
/// </summary>
/// <param name="label"></param>
///
public void NotitiesLatenZien()
{
if (filename != null)
{
BRTSignal signal = new BRTSignal(filename);
BRTEventRepository Notities = new BRTEventRepository(signal);
List<IBRTNote> note = Notities.ReadNotes();
BRTEventService TijdNotities = new BRTEventService(signal);
TijdNotities.MakeNoteTimesRelativeToTrack(note, 1);
//TextBox NotitiesTB = new TextBox();
//NotitiesTB.Name = "Notities";
if (NotitiesForm == null)
{
NotitiesForm = new Form();
}
NotitiesForm.Height = 600;
NotitiesForm.Width = 1000;
NotitiesForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
NotitiesForm.MaximizeBox = false;
NotitiesForm.Disposed +=NotitiesForm_Disposed;
NotitiesForm.Text = "Notities";
NotitiesTB.Multiline = true;
NotitiesTB.Height = 600;
NotitiesTB.Width = 980;
NotitiesTB.ReadOnly = true;
NotitiesTB.Clear();
//NotitiesTB.Click += NotitiesTB_Click;
//NotitiesTB.SelectionStart = Convert.ToInt32(referenceLineSelectedPage);
NotitiesTB.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Both;
NotitiesTB.Name = "Notities";
NotitiesForm.Controls.Add(NotitiesTB);
foreach (IBRTNote notes in Notities.ReadNotes())
{
//string test = Convert.ToString((notes.Time));
//textBox1.Text = String.Concat(textBox1.Text, string.Concat(Environment.NewLine, notes.Text));
if (NotitiesTB.Text == "")
{
NotitiesTB.Text += new BRTToDotNET.RTDateTime((long)notes.Time).ToDotNet().ToString() + " " + notes.Text;
}
else
{
NotitiesTB.Text += "\r\n" + new BRTToDotNET.RTDateTime((long)notes.Time).ToDotNet().ToString() + " " + notes.Text;
}
//MessageBox.Show("\r\n" + notes.Text);
NotitiesForm.Show();
NotitiesForm.BringToFront();
}
}
else
{
MessageBox.Show("Er blijkt een .sig file te missen. Controleer of u een .sig file heeft ingeladen.");
}
}
private void NotitiesForm_Disposed(object sender, EventArgs e)
{
NotitiesForm = null;
}
The code you posted seem "good enough". That is, you set the NotitiesForm variable when the object is disposed, and you create a new one if it's null. As long as all this code executes in the main UI thread, that part is fine.
But note that all controls in a Form are disposed of when the Form is disposed. So your NotitiesTB control will be disposed of the first time your NotitiesForm is closed. You then add that control to the next Form instance you create, and when it's shown, you get the exception because you're trying to show a Form containing a control that has already been disposed.
The right way to do this would be to design an actual Form subclass that already contains the RichTextBox instance you want. Then you don't have to keep adding a new instance to each new instance of the Form you create.
Barring that, then you need to create a new RichTextBox instance to go with each new Form instance you create, e.g. in the same place where you have the NotitiesForm = new Form(); statement.

Categories

Resources