object disposed exception on DataGrid - c#

I have a DataGrid that for some reason I have to declare as a global. everything seems to be working fine at first use. But when I go back to the form for another try, an object disposed exception is called. Is there anyway for me to prevent this? like dispose the public datagrid or something? Here is a sample of my code:
public static DataGrid dataGrid = new DataGrid();
public myForm()
{
InitializeComponent();
dataGrid.Location = pt;
dataGrid.Font.Name = "Tahoma";
dataGrid.Font.Size = 9;
dataGrid.BackgroundColor = Color.Azure;
dataGrid.GridLineColor = Color.Black;
dataGrid.ColumnHeadersVisible = false;
dataGrid.RowHeadersVisible = false;
dataGrid.PreferredRowHeight = 60;
this.Controls.Add(dataGrid);
dataGrid.Height = 524;
dataGrid.Width = 468;
dataGrid.CurrentCellChanged += new
EventHandler(dataGrid_CurrentCellChanged);
}

A Form (or indeed any Control) disposes its child controls when it is disposed. So what you're seeing is normal.
To achieve what you want, you'd need to remove the DataGrid from the Form's Controls collection before it is disposed.
UPDATE
As #ctacke says in comments, there are almost certainly alternatives that will avoid your needing to make the DataGrid static, but without more detail it's difficult to make a recommendation.

If you are going to have a static control, at least provide a wrapper for it so that you can catch and handle your issues.
Consider modifying your code to being something like below. Once you have your bugs ironed out, you can eliminate any of the stuff you don't really need.
private static DataGrid dataGrid;
private static myForm myInstance;
public myForm()
{
InitializeComponent();
myInstance = this; // set 'myInstance' before DataGrid1 stuff
DataGrid1.Height = 524;
DataGrid1.Width = 468;
DataGrid1.CurrentCellChanged += new EventHandler(dataGrid_CurrentCellChanged);
}
public static DataGrid DataGrid1 {
get {
try {
if ((myInstance == null) || myInstance.IsDisposed) {
throw new Exception("myForm is already disposed. No controls available.");
}
if ((dataGrid == null) || dataGrid.IsDisposed) {
dataGrid = new DataGrid();
dataGrid.Location = pt;
dataGrid.Font.Name = "Tahoma";
dataGrid.Font.Size = 9;
dataGrid.BackgroundColor = Color.Azure;
dataGrid.GridLineColor = Color.Black;
dataGrid.ColumnHeadersVisible = false;
dataGrid.RowHeadersVisible = false;
dataGrid.PreferredRowHeight = 60;
this.Controls.Add(dataGrid);
}
} catch (Exception err) {
Console.WriteLine(err); // put a breakpoint HERE
}
return dataGrid;
}
set {
try {
if ((myInstance == null) || myInstance.IsDisposed) {
throw new Exception("myForm is already disposed. No controls available.");
}
if ((dataGrid == null) || dataGrid.IsDisposed) {
dataGrid = new DataGrid();
dataGrid.Location = pt;
dataGrid.Font.Name = "Tahoma";
dataGrid.Font.Size = 9;
dataGrid.BackgroundColor = Color.Azure;
dataGrid.GridLineColor = Color.Black;
dataGrid.ColumnHeadersVisible = false;
dataGrid.RowHeadersVisible = false;
dataGrid.PreferredRowHeight = 60;
this.Controls.Add(dataGrid);
}
} catch (Exception err) {
Console.WriteLine(err); // put a breakpoint HERE
}
dataGrid = value;
}
}
Finally, make sure your dataGrid_CurrentCellChanged event handler (and everything else in your program) references this public DataGrid1 object, and not the dataGrid - or you'll find yourself having those same errors all over again.

Related

TabPage from tabcontrol does not show data in C# Winforms

I am facing issue in tabcontrol of Windows application.
We have a tabcontrol on 1 windows form on which first tab is by default and other tabs we are adding dynamically at runtime.
In first case while we opening the form, we able to see all the controls in both the tabs i.e. (Default and other tabs)
Although, when we try opening the form for second time, data is being getting added into the form if we debug but while showing, it shows blank in other tabs which are getting added dynamically.
In CustomgroupControl class, i am adding controls dynamically like textbox, dropdown, grid and etc. Although this is working in first case, but not showing controls in second case. (Flow of code is same for both the cases)
Below is attached screenshot in link and shown sample source code
Screenshot for above query
public void renderTabpage(Dictionary<string, List<Field>> subHeaderMap, TabPage currentTabPage, AsynchTabRenderer asynchTabRenderer, DoWorkEventArgs e)
{
currentTabPage.SuspendLayout();
TableLayoutPanel headerTableLayout = createNewheaferTableLayoutPanel(currentTabPage.Name + TABLE_LAYOUT_NAME_SUFFIX);
currentTabPage.Controls.Add(headerTableLayout);
headerTableLayout.ColumnCount = 1;
headerTableLayout.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
headerTableLayout.RowCount = 0;
headerTableLayout.SuspendLayout();
foreach (string subHeaderName in subHeaderMap.Keys)
{
if (asynchTabRenderer != null && asynchTabRenderer.CancellationPending == true)
{
e.Cancel = true;
return;
}
else
{
CustomGroupControl customGroupControl = createAndPopulateSubheaderGroupControl(subHeaderMap[subHeaderName], subHeaderName);
headerTableLayout.RowCount = headerTableLayout.RowCount + 1;
headerTableLayout.RowStyles.Add(new RowStyle(SizeType.AutoSize));
headerTableLayout.Controls.Add(customGroupControl, 0, ++headerTableLayout.RowCount);
}
}
headerTableLayout.ResumeLayout(false);
headerTableLayout.PerformLayout();
currentTabPage.ResumeLayout(false);
currentTabPage.PerformLayout();
}
private void detailsTabControl_TabIndexChanged(object sender, EventArgs e)
{
tabIndexChangedEvent(((TabControl)sender).SelectedTab);
}
private void tabIndexChangedEvent(TabPage tabPage)
{
try
{
//WordApp.ScreenUpdating = false;
//WordApp.System.Cursor = Word.WdCursorType.wdCursorWait;
if (tabPage.Name == TabName.Replace(" ", "_").ToUpper())
{
FileUtilService service = FileUtilFactory.getInstance();
// service.clearIENetCache();
showForm(Window, forms);
}
//TabPage tabPage = ((TabControl)sender).SelectedTab;
if ((tabPage.Tag == null || true == (Boolean)tabPage.Tag) && !string.Equals(tabPage.Name, FieldConstants.TAB, StringComparison.CurrentCultureIgnoreCase))
{
var controls = WindowsFormControlUtils.GetControlHierarchy(tabPage);
foreach (Control control in controls)
{
if (control is CustomGroupControl)
{
CustomGroupControl customGroupControl = (CustomGroupControl)control;
customGroupControl.fieldRenderDelegater();
}
else
continue;
}
tabPage.Tag = false;
}
}
catch (Exception ex)
{
logger.Error(ex.Message);
}
}
internal TableLayoutPanel createNewheaferTableLayoutPanel(string headerName)
{
TableLayoutPanel subHeaderTableLayout = new TableLayoutPanel();
// resources.ApplyResources(subHeaderTableLayout, headerName.Replace(" ", "_").ToUpper());
subHeaderTableLayout.Name = headerName.Replace(" ", "_").ToUpper() + TABLE_LAYOUT_NAME_SUFFIX;
subHeaderTableLayout.Dock = DockStyle.Fill;
subHeaderTableLayout.AutoSize = true;
subHeaderTableLayout.AutoScroll = true;
subHeaderTableLayout.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowOnly;
subHeaderTableLayout.GrowStyle = TableLayoutPanelGrowStyle.AddRows;
return subHeaderTableLayout;
}
#Jimi & #Lucky
It works. Got the correct direction. Thanks.
Hint - Don't create controls on worker thread
Tried solution and worked - Removed creation of controls from parameterized constructor and added on form_load event.

Can´t check if array values are true from another class in main class

I am programming a basic writing game in C#. The game will randomly show picture in a picturebox. The pictures is stored in an array in a different class than the main class.
The code to the class looks like this :
public class bildelisteDyr
{
public static Bitmap bildeListe (int index)
{
Bitmap[] bildeListe = new Bitmap[21];
bildeListe[0] = Properties.Resources.ål;
bildeListe[1] = Properties.Resources.ant;
bildeListe[2] = Properties.Resources.bird;
bildeListe[3] = Properties.Resources.bear;
bildeListe[4] = Properties.Resources.butterfly;
bildeListe[5] = Properties.Resources.cat;
bildeListe[6] = Properties.Resources.chicken;
bildeListe[7] = Properties.Resources.dog;
bildeListe[8] = Properties.Resources.elephant;
bildeListe[9] = Properties.Resources.fish;
bildeListe[10] = Properties.Resources.goat;
bildeListe[11] = Properties.Resources.horse;
bildeListe[12] = Properties.Resources.ladybug;
bildeListe[13] = Properties.Resources.lion;
bildeListe[14] = Properties.Resources.moose;
bildeListe[15] = Properties.Resources.polarbear;
bildeListe[16] = Properties.Resources.reke;
bildeListe[17] = Properties.Resources.sheep;
bildeListe[18] = Properties.Resources.snake;
bildeListe[19] = Properties.Resources.spider;
bildeListe[20] = Properties.Resources.turtle;
return bildeListe[index];
}
}
When calling on the values in the array to show picture randomly in the picturebox it all works well. This is done like this :
pictureBox1.Image = bildelisteDyr.bildeListe(r.Next(0, 20));
But I have three times where I need the code to check the value of the picturebox to do a something. I have one play sound button, one button that give a label a text and one button to check given answer from a textbox. None of them seems to work. Here are some code :
Give text to label :
if (pictureBox1.Image == bildelisteDyr.bildeListe(0))
{
svarPåOppgave.Text = "ÅL";
}
else if (pictureBox1.Image == bildelisteDyr.bildeListe(1))
{
svarPåOppgave.Text = "MAUR";
}
// etc.
Play sound button :
if (pictureBox1.Image == bildelisteDyr.bildeListe(0))
{
SoundPlayer player = new SoundPlayer();
player = new SoundPlayer("lyd/dyr/ål.wav");
player.PlaySync();
}
else if (pictureBox1.Image == bildelisteDyr.bildeListe(1))
{
SoundPlayer player = new SoundPlayer();
player = new SoundPlayer("lyd/dyr/enmaur.wav");
player.PlaySync();
}
// etc.
Checking if correct answer is given :
if (pictureBox1.Image == bildelisteDyr.bildeListe(0))
{
if (textBox1.Text.Trim().ToLower() == "ål")
{
riktigLyd.Play();
poengInt += 1;
textBox1.Text = "";
pictureBox1.Image = bildelisteDyr.bildeListe(tilfeldigBildet);
tekstTilLabel();
svarPåOppgave.Visible = false;
}
else
{
feilLyd.Play();
poengInt -= 1;
textBox1.Text = "";
}
String poengString = poengInt.ToString();
label1.Text = poengString;
textBox1.Select();
}
else if (pictureBox1.Image == bildelisteDyr.bildeListe(1))
{
if (textBox1.Text.Trim().ToLower() == "maur")
{
riktigLyd.Play();
poengInt += 1;
textBox1.Text = "";
pictureBox1.Image = bildelisteDyr.bildeListe(tilfeldigBildet);
tekstTilLabel();
svarPåOppgave.Visible = false;
}
else
{
feilLyd.Play();
poengInt -= 1;
textBox1.Text = "";
}
String poengString = poengInt.ToString();
label1.Text = poengString;
} // etc.
I would guess there was something wrong with the if statements like
if (textBox1.Text.Trim().ToLower() == "ål")
But I can´t seem to understand what?
To sum it up, when I debug the program I get the random picture from the other class. But when I press the buttons on the program nothing happens. No sound, no text to label and no checking of answer.
There's some unusual architectural choices here, but the specific problem you're facing is that you're re-creating the Bitmaps every time, and comparisons are performed by reference, not by value.
Change your bildelisteDyr class as follows:
public class bildelisteDyr
{
static Bitmap[] bildeListeInternal;
static bildelisteDyr() {
bildeListeInternal = new Bitmap[21];
bildeListeInternal[0] = Properties.Resources.ål;
//...
bildeListeInternal[20] = Properties.Resources.turtle;
}
public static Bitmap bildeListe (int index) {
return bildeListeInternal[index];
}
}
Some more resources on the conceptual problem:
== Operator
Value vs Reference Types

Remove label created on Run-time CF C#

I create a label "label1" dynamically in a method. Then when I click a button I want to remove that label created but if I write Controls.Remove(label1) it says that the control doesn't exist in the context.
How could I do to achieve this?
EDIT: Following Jon suggestion I implemented the foreach loop but it doesn't do anything. This is my code, the panel which I use is created by design:
void GenerateControls() {
Label labelOne = new Label();
Button btnContinue = new Button();
panel.SuspendLayout();
SuspendLayout();
//btnContinue
btnContinue.BackColor = System.Drawing.Color.Black;
btnContinue.ForeColor = System.Drawing.SystemColors.Menu;
btnContinue.Location = new System.Drawing.Point(145, 272);
btnContinue.Name = "btnContinue";
btnContinue.Size = new System.Drawing.Size(95, 28);
btnContinue.TabIndex = 13;
btnContinue.Text = "Continue";
btnContinue.Visible = true;
Controls.Add(btnContinue);
btnContinue.Click += new System.EventHandler(btnContinue_Click);
//labelOne
labelOne.Location = new Point(0,65);
labelOne.Size = new System.Drawing.Size(100,20);
labelOne.Text = "labelOne";
labelOne.Name = "labelOne";
labelOne.Visible = true;
labelOne.TextChanged += new System.EventHandler(this.lbl_TextChanged);
labelOne.BackColor = System.Drawing.Color.PaleGreen;
Controls.Add(labelOne);
//panel
panel.Controls.Add(labelOne);
panel.Visible = true;
panel.Location = new Point(0,0);
panel.Size = new Size(240, 320);
//
Controls.Add(panel);
panel.ResumeLayout();
ResumeLayout();
}
And then in when I click on btnContinue:
private void btnContinuar_Click(object sender, EventArgs e) {
foreach (Control control in panel.Controls) {
if (control.Name == "labelOne"){
panel.Controls.Remove(control);
break;
}
}
}
I debug it and in the panel.Control it continues as if it were empty panel.
Thanks for your help!
I suspect it says the variable doesn't exist in that context. You'll have to find the label by its text, or knowing something else about it. For example, when you create it you could set the Name property and find it by that when you want to remove it:
panel.Controls.RemoveByKey("YourLabelName");
EDIT: As noted in the comments, RemoveByKey doesn't exist in the compact framework. So you'd either have to remember the reference yourself (in which case you don't need the name) or use something like:
foreach (Control control in panel.Controls)
{
if (control.Name == "YourLabelName")
{
panel.Controls.Remove(control);
break;
}
}
EDIT2: And to make it even more "generic" and desktop compatible, you could keep the RemoveByKey call and add this to your app:
public static class FormExtensions
{
public static void RemoveByKey(this Control.ControlCollection collection,
string key)
{
if(!RemoveChildByName(collection, key))
{
throw new ArgumentException("Key not found");
}
}
private static bool RemoveChildByName(
this Control.ControlCollection collection,
string name)
{
foreach (Control child in collection)
{
if (child.Name == name)
{
collection.Remove(child);
return true;
}
// Nothing found at this level: recurse down to children.
if (RemoveChildByName(child.Controls, name))
{
return true;
}
}
return false;
}
}
After 20 edits to the OP question, and Jon's answer with no resemblance to the original problem, you are left with one small glitch.
Your Not adding labelOne to the panel you are adding it to the Form.
Change
Controls.Add(labelOne);
to
panel.Controls.Add(labelOne);
Then everything should work

create custom object (combination of two objects)

hello creating a custom object may be a widely published topic, but my lack of coding skills proves problematic in actually implementing what i'm trying to do.
in a nutshell i'm adding controls at runtime in a flowpanelLayout. right now it's just listboxes, that code is all working fine. i would like a way to label the listboxes that are getting added, i can't think of a better way to do this than to use a text label. i was thinking it would be slick to create some sort of custom control (if possible) which is a listbox and a textlabel like one above the other or something. this way i can add the new custom control in my current code and assign the listbox attributes and label text, etc all in one motion.
this is what i was thinking, maybe there's even a better way to do this.
my current listview creation code:
public void addListView()
{
ListView newListView = new ListView();
newListView.AllowDrop = true;
newListView.DragDrop += listView_DragDrop;
newListView.DragEnter += listView_DragEnter;
newListView.MouseDoubleClick += listView_MouseDoubleClick;
newListView.MouseDown += listView_MouseDown;
newListView.DragOver += listView_DragOver;
newListView.Width = 200;
newListView.Height = 200;
newListView.View = View.Tile;
newListView.MultiSelect = false;
flowPanel.Controls.Add(newListView);
numWO++;
numberofWOLabel.Text = numWO.ToString();
}
maybe the actual best answer is simply to also add a textlabel here and define some set coordinates to put it. let me know what you think.
if a custom control is the way to go, please provide some resource or example for me - i'd appreciate it.
Here is a custom user control that can do that:
You just need to set TitleLabelText to set the title.
[Category("Custom User Controls")]
public class ListBoxWithTitle : ListBox
{
private Label titleLabel;
public ListBoxWithTitle()
{
this.SizeChanged +=new EventHandler(SizeSet);
this.LocationChanged +=new EventHandler(LocationSet);
this.ParentChanged += new EventHandler(ParentSet);
}
public string TitleLabelText
{
get;
set;
}
//Ensures the Size, Location and Parent have been set before adding text
bool isSizeSet = false;
bool isLocationSet = false;
bool isParentSet = false;
private void SizeSet(object sender, EventArgs e)
{
isSizeSet = true;
if (isSizeSet && isLocationSet && isParentSet)
{
PositionLabel();
}
}
private void LocationSet(object sender, EventArgs e)
{
isLocationSet = true;
if (isSizeSet && isLocationSet && isParentSet)
{
PositionLabel();
}
}
private void ParentSet(object sender, EventArgs e)
{
isParentSet = true;
if (isSizeSet && isLocationSet && isParentSet)
{
PositionLabel();
}
}
private void PositionLabel()
{
//Initializes text label
titleLabel = new Label();
//Positions the text 10 pixels below the Listbox.
titleLabel.Location = new Point(this.Location.X, this.Location.Y + this.Size.Height + 10);
titleLabel.AutoSize = true;
titleLabel.Text = TitleLabelText;
this.Parent.Controls.Add(titleLabel);
}
}
Example use:
public Form1()
{
InitializeComponent();
ListBoxWithTitle newitem = new ListBoxWithTitle();
newitem.Size = new Size(200, 200);
newitem.Location = new Point(20, 20);
newitem.TitleLabelText = "Test";
this.Controls.Add(newitem);
}

How to use VisualTreeHelper#HitTest and TagVisualizer correctly

In my application I want to ensure that a TagVisualization is only displayed if the tagged object is placed on a Ellipse. So I used this code to do that:
private void TagVisualizer_VisualizationAdded(object sender, TagVisualizerEventArgs e)
{
Console.WriteLine("Hitlist");
//Notes
if (e.TagVisualization.GetType() == typeof(NoteVisualization))
{
bool found = false;
Point pt = e.TagVisualization.Center;
hitResultsList.Clear();
VisualTreeHelper.HitTest(RootLayer, null, new HitTestResultCallback(MyHitTestResult), new PointHitTestParameters(pt));
if (hitResultsList.Count > 0)
{
foreach (DependencyObject o in hitResultsList)
{
if (o.GetType() == typeof(Ellipse))
{
Console.WriteLine("Placed on a Sourcefile");
SourceFile sf = (((o as Ellipse).Tag) as SourceFile);
GroupBox gp = e.TagVisualization.FindName("GroupHeader") as GroupBox;
gp.Header = sf.getFullName();
e.TagVisualization.Tag = sf;
SurfaceButton save = e.TagVisualization.FindName("NoteSave") as SurfaceButton;
save.Tag = sf;
found = true;
break;
}
}
}
if (!found)
{
e.TagVisualization.Visibility = System.Windows.Visibility.Collapsed;
Console.WriteLine("Placed somewhere else");
}
}
}
I'm not really sure if this is the correct way, since I don't avoid that the TagVisualization is displayed, but instead I instantly set the Visibility to collpased. I think there have to be better ways to do that?
official guidance for how to do this is shown in one of the sdk samples:
http://msdn.microsoft.com/en-us/library/ee804861(v=Surface.10).aspx
-robert (former program manager for the surface dev platform)

Categories