I'm using a public static variable in C# Windows forms application. I have two files as Audits.cs and Findings.cs. I have created a public static variable as F_Status in Audits.cs file and made it to assign to the value '1' when an item is selected in a listView. I'm going to use this variable in Findings.cs file in an if statement. My coding in the Findings.cs file is as follows.
if (Audits.F_Status==1)
{
// Do something
}
I have made some break points and tested the coding. In Audits.cs file the variable get assigned to the value '1' and however when it come to the if statement in Findings.cs file the value of the F_Status become '0'. I cannot understand why? If anyone can help me it will be great.
looks like the value is set somewhere else. To find out where this happens, implement the variable as property and set a break-point on it. Of course, don't use an auto property as this wont hit the break point
My guess is that you set F_Status = 1 inside a handler for event ListView.ItemSelectionChanged. ListView raises the event multiple times when the selected item changes: probably the last of these indicates unselected for the previously selected item.
MSDN's reference ListView.ItemSelectionChanged includes example code to debug the event behaviour. But the example calls MessageBox.Show which to me defeats the purpose of analyzing an event's behaviour - when it's a window event. I'd add at the top of the file:
using System.Diagnostics;
And inside the event handler add appropriate calls to Trace.WriteLine, to see how the value of IsSelected changes.
As a commenter noted, there are better designs for telling form B that an item on form A's ListView is selected. The public static variable in form A is undesirable because form B can change the value, which is probably not what you want, and often leads to disaster. There are lots of examples on the web for designing interaction between forms - using a structured programming approach.
Related
I have a datagridView on Form1. When I double-click on an item in that Datagridview, I go to a detailform where I get to see the details of the line in the datagridview. (I get them based on the id of the record I keep in the datagridview). Now I want to make prev/next buttons on the detailform so that the user doesn't have to go back to form1.
I can access the datagridview (which is public), but I can't see the row info.
In the debugger I can see the row info if I start from
this.Owner.Controls[0].Controls[2].Controls[0] and then click to open the Rows properties. When I enter this.Owner.Controls[0].Controls[2].Controls[0].Rows[0], I get error CS1061.
How can I fix this?
This is a data type issue. Looking at this expression:
this.Owner.Controls[0].Controls[2].Controls[0].Rows[0]
We can follow the data type of each part of the expression from beginning to end to see the problem.
First, the type of this is the current Form, which will be something inherited from System.Windows.Forms.Form. From there, we check that type's .Owner property, and see it is also a (nullable) System.Windows.Forms.Form.
Now we start looking at the Form type's .Controls member. We find the datatype here by understanding that Form inherits from System.Windows.Forms.Control, which leads us to the property definition. Now we learn we're looking at a System.Windows.Forms.ControlCollection. This type has an indexer property that allows you to make the [0] and [2] lookups (probably better to do this by name, fwiw). The documentation for this property tells us the result of the indexer expression is back to System.Windows.Forms.Control.
Now we know enough to understand that when we take this expression:
this.Owner.Controls[0].Controls[2].Controls[0]
the data type chain for the expression looks like this:
this .Owner .Conrols [0] .Controls [2] .Controls [0]
Form > Form > ControlCollection > Control > ControlCollection > Control > ControlCollection > Control
It shows the final result is a System.Windows.Forms.Control. From there we go look for the .Rows property and find... nothing. The basic Control type does not provide this property.
So why does it work in the debugger? At run time, we aren't dealing with base Control objects. We are dealing with types that inherit from Control, like Panel, TextBox, or DataGridView. It just so happens the DataGridView control does provide a Rows property. The debugger allows you to resolve this to use the run time type, but the compiler doesn't know what's going to happen once the program starts running; it has to be more strict. For example, you might have a button to remove the gridview and put something else there instead, and now the Rows expression would no longer be valid.
You can smooth over the compiler issue with a cast:
var dgv = (DataGridView)this.Owner.Controls[0].Controls[2].Controls[0];
var row = dgv.Rows[0];
But this is tightly-coupled to the form layout. Move something around in the designer and suddenly you're tracing through a lot of code to find out what went wrong. You will be better off setting a reference directly to the DataGridView in the child form before even showing it on the screen.
var child = new detailForm(this);
child.ParentGrid = this.DataGridView1; // assuming you declare a public property named "ParentGrid" and your control is named DataGridView1
child.ShowDialog();
Finally, you may be wondering whether you're expected to work through a data type expression chain like that for every line of code you use. I'd say you are expected to understand what data types you're working with at every level of every expression. Fortunately, this doesn't mean you need to have it all memorized. It doesn't take much experience to understand how the Windows Forms types fit together generally, so you can understand these data types without having to go chase through the documentation on every single thing. And speaking of "chasing through the documentation", when you really don't know, you are expected to know how to read the docs to find the answer.
Assuming this is a read-only operation, I would pass the DataGridView to the detail form. You could create a constructor for the detail form that takes a DataGridView as a parameter, or create some kind of public void Populate(DataGridView dgv) { } function that you call after the form constructor.
If you intend on changing data in the DataGridView from the detail page, and expect it to reflect on the main form, then you can either create a event on the detail form that the main form listens for, or after the detail form closes, retrieve the stored DataGridView and look for changes (or just overwrite).
What is a quick way to reset all the Controls inside a panel to their initial states (Compile-time state)? I have TextBoxes, RadioButtons, ComboBoxes, and CheckBoxes to reset. I'd like them to reset to the values when the program first ran. I'd like a solution that does not involve looping or recursion mainly because I don't want to reimplement the same thing over again when I start witha new project. I'm simply finding a set of methods to call that will do the job. Are there any?
Your controls have no compile time state, because state is a runtime concept.
I think you mean you want controls re-initialized to the state as shown on your property sheets. This state is applied by the generated code located in InitializeComponent, so to re-apply that state, you could just call it again.
The only problem is InitializeComponent also wires up events, and you probably don't want to do that twice. You could possibly work around this by deregistering all of your events before calling it, or by deduplicating the invocation list afterward (see this answer).
I don't recommend any of this. The best approach would be to write your own method that sets the properties the way you want them, one by one. Sometimes ya gotta write code.
I am creating an interface for an XNA game and can't seem to figure something out. I'm new to programming, and feel like I have to be missing something obvious.
I'm creating a grid of levels, much like something you'd see in Angry Birds.
The number of levels will be variable, so I don't want to statically program them.
All of the buttons I use for level icons are created dynamically at runtime, based on a list of level objects. As I create the buttons I set up all of the click events to point to one method that is supposed to determine which button they clicked on, and load that specific level.
My problem is I can't seem to figure out a reliable way to actually tell which button they clicked on and associated that with one of my level objects in the list. I feel like I must be missing something extremely obvious.
Things I've tried so far:
As I generate the buttons dynamically I add them as children to a grid. So I tried using the index number of the sender as the index number in my list of levels (because they should both have the same number of elements).
For example:
App.CurrentLevel = PuzzleLevelsGrid.Children.IndexOf(sender as Button);
This worked great the first time I navigate to the level picking screen, but whenever I come back to it the children of my grid gets reset to a count of 0 for some reason, so it breaks down.
I've set break points and I can't explain how it gets set to 0. I load the children in my onNavigatedTo(), and sometime between the end of that and me pressing a button to load a level it gets wiped.
The other thing I tried was setting up a button object inside my actual level object, then when dynamically creating the level buttons I actually make changes to the button property in the appropriate level.
Then when I need to find out which button was the sender I just loop through all levels and match the sender to the button property. This method actually worked pretty well... until I started trying to load my levels using a background worker thread. The worker thread can't deal with the Button because it's a UI thread thing, and crashes.
Like I said, I'm a new programmer, so I welcome any and all feedback.
Thanks in advance.
The button, like almost every UI control, has a "Tag" property. This property has been designed for you, and only for you, so that you can put any value you like to identify the control.
For instance, you can put your level object in the Tag property of the button, then just read this value back in the click event.
I'm trying to use the selected value of a ListBox control to populate a TextBox with its Text property, and a HiddenField with its value property. It sounds simple enough, and I went with this:
currentGroupTextBox.Text = currentSiteGroupList.SelectedItem.Text;
currentGroupHiddenField.Value = currentSiteGroupList.SelectedValue;
But upon execution, ASP.NET returns an error:
Object reference not set to an instance of an object.
And highlights the first line. currentGroupTextBox and currentGroupHiddenField are two controls which are enabled in the ASPX file so I'm not too sure why ASP.NET would complain about instancing them.
I'm going to try and pull together answers to all of your questions, including those in the comments.
Even if SelectionMode="Single", the listbox starts out without anything being selected, unless you specify which item should be selected in your code.
To test if the SelectedItem is null, use the following code:
if (currentGroupSiteList.SelectedItem != null) {
currentGroupTextBox.Text = currentSiteGroupList.SelectedItem.Text;
currentGroupHiddenField.Value = currentSiteGroupList.SelectedValue;
}
What does your Page_Load code that loads the listbox look like? Is it wrapped with a if (!Page.IsPostBack) check? If not, pressing the button and initiating a postback will reload the listbox, thus losing the SelectedItem that the user selected.
I'd be willing to bet that your first line is choking on referencing currentSiteGroupList.SelectedItem, as that seems the most likely candidate for being a null reference. Make sure your code is executing in the right place within the ASP.NET page lifecycle, such that the SelectedItem is set properly behind the scenes.
SelectedItem from your currentSiteGroupList.SelectedItem is likely to be null (what represents no selection). You need to test it before assigning it to currentGroupTextBox.Text
Is it currentGroupTextBox or currentGroupTextBox that is null?
In debug if stop on that line..is it one or both that are not existing?
A common issue I find is that controls are placed on an asp formview or similar and so the reference to that control is not actually its id/name, but more likely you need to do;
TextBox myTextBoxReference = (TextBox) formName.FindControl("currentGroupTextBox")
string theValue = myTextBoxReference.Text
Another often issue is the page life cycle. So if your object is not on a form but maybe you are referencing it before it exists in the postback.
hth
Ok, here's the deal.
I have a graph, that "listens" to some labels' textfields, and graphs their values. It does this by adding the values on the TextChanged event.
The problem:
TextChanged only fires when the text has actually changed (obviously), and not when it has been assigned a new value.
What I need:
A way to detect if the Text field of label has been updated (assigned to), and all I have to work with is a reference to the Control (ie the Label).
I realize TextChanged wasn't designed for this, which is why I'm wondering if any of you guys have encountered a similar problem, and found a solution to it.
The reason that your TextChanged event handler is not invoked in initial assignment of the text is that it is attached after the first text has been assigned (the designer seems to do things in this order by default). I would do like this:
TextChanged calls another method (UpdateGraph)
UpdateGraph collects necessary data and updates the graph
Call UpdateGraph as the last thing done when loading the form
That will make sure that the graph is updated with the initial values. It is important that this call happens after the call to InitializeComponent.
It is fairly common practice in "setters" to ignore trivial changes, for example:
public int Foo {
get {return foo;}
set {
if(foo != value) {
foo = value;
OnFooChanged();
}
}
}
If Text is behaving like this, and you are relying on all updates causing an event, then it may not work as you want. I would probably try to find another way to do what you want; perhaps using an intermediate object that passes the values through.
You could create your own control that inherits from that control and create your own Text property that will fire an event when assigned a new value.