This question already has an answer here:
How do I save an ArrayList to the application settings
(1 answer)
Closed 2 years ago.
I am writing a simple application - a kind of saper game in winforms in C#. My application already saves some information in application settings like the size or colour of buttons , but when i try to save an arraylist of my own structure I get a problem. The are no errors but the information is not saved for the next program execution.Ustawienia is a public static class including wyniki which is another form , and Properties.Settings.Default.scores is an ArrayList added in application settigs. I would be grateful if you have any idea what i am doing wrong and how to store the arraylist in app settings.
Here is the code:
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
if (Properties.Settings.Default.scores == null)
Properties.Settings.Default.scores = new System.Collections.ArrayList();
}
private void ok_click(object sender, EventArgs e)
{
Highscore higscore = new Highscore(Properties.Settings.Default.ktory, textBox1.Text, ustawienia.ile_wierszy, ustawienia.ile_kolumn, ustawienia.elapsed.Seconds);
Properties.Settings.Default.scores.Add( higscore);
Properties.Settings.Default.scores.Sort(new myComparer());
Properties.Settings.Default.ktory++;
Properties.Settings.Default.Save();
Highscore.show();
this.Close();
}
}
public class Highscore
{
public int nubmer;//w properties ktory=+1;
public string name;
int rows;
int columns;
public int time;
public Highscore(int _number, string _name, int _rows, int _columns, int _time)
{
number = _number;
name = _name;
rows = _rows;
columns = _columns;
time = _time;
}
public static void show()
{
ListView list = (ListView)ustawienia.wyniki.Controls.Find("listView1", true)[0];
list.Items.Clear();
foreach (Highscore e in Properties.Settings.Default.scores)
{
ListViewItem newItem = new ListViewItem(new[] { e.name, e.time.ToString(), e.rows.ToString()+"x"+e.columns.ToString() });
lista.Items.Add(newItem);
}
ustawienia.wyniki.Show();
}
}
public class myComparer:IComparer
{
int IComparer.Compare(Object x, Object y)
{
if (((Highscore)x).time < ((Highscore)y).time)
return 1;
else if (((Highscore)x).time > ((Highscore)y).time)
return -1;
else
{
return String.Compare(((Highscore)x).name,((Highscore)y).name);
}
}
}
}
In my experience, it was always a problem with trying to use the default Settings. For example, on Windows 8 the Default settings was saved in this folder pattern:
C:\Users\[username]\AppData\Local\[AssemblyName]\[AssemblyName].exe_Url_[random_string_of_characters]\1.0.0.0\user.config
However, in debug mode it would be .vhost.exe and then when testing locally it would be just .exe. Then if the version increased it would change the path again.
Eventually I gave up on trying to figure out which Settings file was being used, and trying to force it to save to a different (cleaner) folder. Instead, I switched to using a custom settings class and using XmlSerializer. It's not worth the headache.
Related
I'm creating a simple distance calculator. I have a window form with 2 combo boxes. The first combobox has the default place which is the Place1 and the second combobox has the value of Place1,Place2 and Place3.
Here's my code in my class.
public class classDistance
{
public string Places { get; set; }
public int DistanceKm { get; set; }
public static void Hours() {
List<string> Cities = new List<string>();
Cities.Add("Place1");
Cities.Add("Place2");
Cities.Add("Place3");
List<int> DestinationKm = new List<int>();
DestinationKm.Add(10); // Place1 = 10Km
DestinationKm.Add(20); // Place2 = 20Km
DestinationKm.Add(30); // Place3 = 30Km
return;
}
}
//Place1 has the speed of 80kmph.
And when the user click the button in the Form, it will calculate the Hours from the method class classDistance
// Inside my form
public Form1()
{
InitializeComponent();
}
classDistance classname = new classDistance();
private void button1_Click(object sender, EventArgs e)
{
if(comboBox1.Text == "Place1"){
// call the method on the classname if the user click the button and calculate the hours
}
}
How can I do that?
Thank you in advance!
As you made method Hours() static, you can simply call it by the class without creating any instance, like that:
private void button1_Click(object sender, EventArgs e)
{
ClassDistance.Hours();
}
But now your method just fills the lists, not calculates hours actually.
UPD:
I think it's better off using dictionary for storing and getting data in your case:
var citiesDistance = new Dictionary<string, int>
{
{"Place1", 10},
{"Place2", 20},
{"Place3", 30}
};
Then, you can get appropriate value by the place's name, e.g.:
var name = "Place2";
var length = citiesDistance[name];
And after that, you can calculate hours, needed to get to the place:
var speed = 80;
var hours = length/speed;
Hope, I've understood your question correctly)
At the moment you have a list of places and a list of distances which aren't really related to each other.
What I would do is create a new class which contains both the place name and distance, e.g.:
public class Destination
{
public string Name {get;set;}
public int DistanceKm {get;set;}
// ctor
public Destination(String name, int distanceKm)
{
Name = name;
DistanceKm = distanceKm;
}
public int getHours (int speed)
{
// do your calculation for the number of hours here
return hours;
}
}
You can then populate the destination with it's name and distance via the constructor, and use the getHours method to return the number of hours based on the speed you pass into it.
You could also create a List if you were handling multiple destinations
I am developing an application for training chess. The idea is to upload a file PGN Portable Game Notation ( no PNG is image format) , which is a file where the data of an item and also the moves are stored.
Each move can have zero , one or more variations . I declare a class to fill the tree and then to follow it.
Then the class that I created :
public class Movida
{
private int numeroMovida;
private string algebraicMove;
private int token;
private string comentario;
private List<Movida> variaciones = new List<Movida>();
public Movida(int numeroMovida, string algebraicMove, int token, string comentario, List<Movida> variaciones) {
this.numeroMovida = numeroMovida;
this.algebraicMove = algebraicMove;
this.token = token;
this.comentario = comentario;
this.variaciones = null;
}
public void agregarMovida(Movida movida) {
variaciones.Add(movida);
}
public List<Movida> obtenerVariaciones() {
return variaciones;
}
}
I think I need to make a function to enter fill the tree recursively , just to get moved back. Any help is appreciated.
I am using Visual Studio to create a Windows Forms C# project and am trying to set up an array of a type class, and have the entries in the array correspond to the constructor string for the class. I am using an array with an index of a variable, which increases each time that a new class instance is added to the array.
I am running into the problem of the index call is outside the bounds of the array. Additionally, I am not sure that my class variables are being set for each instance. Can anyone point me in the right direction? Below is my code:
public partial class MainMenu : Form
{
//int that will be used to alter the index of the array
public static int acctcount = 1;
//array of class Account
Account[] accounts = new Account[acctcount];
public MainMenu()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//check through each element of the array
for (int i = 0; i < accounts.Length; i++)
{
string stringToCheck = textBox1.Text;
foreach(Account x in accounts)
{
//check to see if entered name matches any element in the array
if (x.Name == stringToCheck)
{
//set variables in another form so that we are using the class variables for only that class
Variables1.selectedAccount = x.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = Account.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = Account.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
this.Hide();
acctMenu.Show();
}
else
{
/*insert new instance of Account
the index element should be 0, since acctcount is set to 1
and we are subtracting 1 from the acctcount
we are using the string from the textbox1.Text as the constructor
for the new instance*/
accounts [acctcount-1] = new Account(stringToCheck);
//increase the index of the array by 1
acctcount += 1;
}
}
}
}
}
class Account
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private static int acctNum = 0;
public static int AcctNumber
{
get
{
return acctNum;
}
set
{
acctNum = value;
}
}
//initialize the CheckBalance value to 100.00
private static decimal checkBalance = 100.00M;
public static decimal CheckBalance
{
get
{
return checkBalance;
}
set
{
checkBalance = value;
}
}
public Account(string Name)
{
this.Name = Name;
}
private static decimal saveBalance = 100.00M;
public static decimal SaveBalance
{
get
{
return saveBalance;
}
set
{
saveBalance = value;
}
}
}
The problem with the reported exception is [most likely] the line accounts[acctcount-1] as it will throw an IndexOutOfBounds exception when acctcount is >= 2 (eg. accounts[1]), as happens after the first button click and increment of acctcount. The array however, only has one element as it was created with accounts = new Account[acctcount]; - arrays in C# do not grow/resize.
The simplest and best immediate fix is to use a List (see Collections (C#)) instead of an array; Lists can grow dynamically. Then the code becomes:
// (remove the "acctcount" field as it is no longer useful)
List<Account> accounts = new List<Account>();
// ..
accounts.Add(new Account(stringToCheck));
As pointed out by Trevor, remove the static modifier in the Accounts class; otherwise the member data will be incorrectly shared (ie. each account will have the same balances!) and "overwrite" each other. If the use of static is an attempt to "pass back" the data from the form see How to return a value from a Form in C#? for a more viable solution. The same use of a public property can be used to pass an (Account) object into a form.
The exception is thrown when the button is clicked more than once.
You created an array of size 1, the second time you click the button and it tries to add an element at index 2, the index is already out of bounds.
Arrays do not grow in size as you add new items.
As pointed out, you should use a collection, like List<T>
If you wanted to keep using arrays, everytime you add a new item, you need to create a new array of bigger size, copy the elements of the old array to the new array, and reference the old array to the new array. You can also create an array of a bigger size and only create a new array when it's full. Which is basically what the .Net collections already implement.
As always, it all depends on what your needs and requirements are.
This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 7 years ago.
I cannot figure out why I am getting this error. I am setting an instance to the object I am trying to create. Any help would be really appreciated. I will post my form code and then the class code below that. The application runs fine, it just gives me that null reference error when I click on btnAdd.
public partial class frmProperties : Form
{
Agent curAgent;
PropertyCollection pc;
int currRecord;
public frmProperties()
{
InitializeComponent();
}
public frmProperties(Agent ac, PropertyCollection pcPassed)
{
InitializeComponent();
curAgent = ac;
pc = pcPassed;
}
//check if there is a property in the list
private void frmProperties_Load(object sender, EventArgs e)
{
if (curAgent.AgentPropertyList.Count > 0)
ShowAll();
}
private void btnNext_Click(object sender, EventArgs e)
{
if (currRecord < curAgent.AgentPropertyList.Count - 1)
{
currRecord++;
ShowAll();
}
else MessageBox.Show("No more properties to view");
}
void ShowAll()
{
txtId.Text = curAgent.AgentPropertyList[currRecord].ToString();
Property p = pc.FindProperty(curAgent.AgentPropertyList[currRecord]);
}
private void btnShowPrev_Click(object sender, EventArgs e)
{
if (currRecord > 0)
{
currRecord--;
ShowAll();
}
else MessageBox.Show("No more properties to view");
}
private void btnAdd_Click(object sender, EventArgs e)
{
pc.AddProperty(Convert.ToInt32(txtId.Text), txtAddress.Text, Convert.ToInt32(txtBedrooms.Text), txtType.Text, Convert.ToInt32(txtSqFt.Text), Convert.ToDouble(txtPrice.Text), txtAgent.Text);
}
private void btnExit_Click(object sender, EventArgs e)
{
this.Close();
}
}
Here is the code to the class that the add function was created in:
public class PropertyCollection
{
// list of properties
List<Property> propertyList = new List<Property>();
public List<Property> PropertyList
{
get { return propertyList; }
set { propertyList = value; }
}
public void AddProperty(int id, string address, int bedrooms, string type, int sqft, double price,string agent)
{
Property p = new Property(id,address,bedrooms,type,sqft,price,agent);
propertyList.Add(p);
}
public void RemoveProperty(int id)
{
Property rem = new Property(id);
propertyList.Remove(rem);
}
//loop through and find equivalent
public Property FindProperty(int id)
{
Property find = new Property(id);
for (int i = 0; i < propertyList.Count; i++)
if (propertyList[i].Equals(find))
return propertyList[i];
return null;
}
//Count property and INDEXER
public int Count
{
get { return propertyList.Count; }
}
public Property this[int i]
{
get { return propertyList[i]; }
set { propertyList[i] = value; }
}
}
Your default constructor isn't initialising pc; You could change it to the following:
public frmProperties()
{
InitializeComponent();
pc = new PropertyCollection(/* any params here */);
}
I am posting this as I am more or less peaved at the 5 upticks to check the breakpoint as it showed the commentor did not read the question.
Posted stated receiving System.NullReferenceException {“Object reference not set to an instance of an object.”} when clicking on the btnAdd_Click method
So we look at this method and it shows we are only accessing 1 variable named pc. The error tells us we have an object that has not been initialized. So we look to see if the variable is define, sure is. now we look to see whereit is initialized so lets look at the constructors.
//this constructor does not initialize any variables, just the form
public frmProperties()
{
InitializeComponent();
}
//this constructor initializes the variables but does not check for null
public frmProperties(Agent ac, PropertyCollection pcPassed)
{
InitializeComponent();
curAgent = ac;
pc = pcPassed;
}
so we have two issues that could result in the proceeding exception.
1) the default constructor is being called therefor pc is never initialized
2) the second constructor is being called and pcPassed has a value of null.
so to fix this we could remove the first constructor requiring that the arguments be passed in in order to start the form then we just need to check for null on the variables. Or leave the default constructor and call the correct one passing in default values or nulls, I suggest nulls that way all processing is done in the constructor with args. So the fix would be
//default constructor calling the correct constructor with params.
public frmProperties() :this(null,null) { }
public frmProperties(Agent ac, PropertyCollection pcPassed)
{
InitializeComponent();
if(ac != null) //check for null values
curAgent = ac;
else
curAgent = new Agent();
if(pcPassed != null)//check for null values
pc= pcPassed;
else
pc = new PropertyCollection();
}
so in short you dont need the breakpoint as you already know that the object was not initialized as that is what the exception was telling you.
Ok so I'm just making a mock MVC app to get a handle on how things work
my model has some string in it (and more, but don't care at the moment)
my GUI has a bunch of radiobuttons and here is what I do
private class radioButtonEvent : Model.EventHandling.XObjectEvent{
private List<RadioButton> myList;
public radioButtonEvent() { }
public override void execute(){
foreach (RadioButton a in myList){
if (a.Text == ((Model.InfoTree)myObj).Info){
a.Checked = true;
((TabControl)a.Parent.Parent).SelectTab(a.Parent.Name);
}
}
}
public void setRadioList(List<RadioButton> a){
myList = a;
}
}
I create one of these and add a list of all my radiobuttons then make it listen to a certain string, like so:
radioButtonEvent locationEvent = new radioButtonEvent();
List<RadioButton> radioList = new List<RadioButton>();
radioList.Add(Location_Logged_Arena_radioButton);
radioList.Add(Location_Logged_Market_radioButton);
radioList.Add(Location_Logged_Mute_radioButton);
radioList.Add(Location_Logged_Town_radioButton);
radioList.Add(Location_Logged_Vault_radioButton);
radioList.Add(Location_Logging_Home_radioButton);
radioList.Add(Location_Logging_Select_radioButton);
locationEvent.setRadioList(radioList);
myModel.InformationTree.addInfoEvent(locationEvent);
one thing I should point out is that in XObjectEvent there is a method that gets inherited that handles the setting of myobj
now the two ways I've currently thought of going about having listenable strings are these:
Way 1:
private ListenableString lstring = new ListenableString();
public string Info{
get
{ return lstring.Text;}
set
{ lstring.Text = value;}
}
public void addInfoEvent(XEvent ev){
lstring.addEvent(ev);
}
and this uses the following
class ListenableString
{
public ListenableString() { }
private string me = "";
private List<XEvent> Events = new List<XEvent>();
public void addEvent(XEvent ev){
Events.Add(ev);
}
public string Text{
get
{ return me;}
set{
me = value;
foreach (EventHandling.XObjectEvent x in Events){
x.setObject(this);
x.execute();
}
}
}
}
Way 2:
private List<XEvent> infoEvents = new List<XEvent>();
public void addInfoEvent(XEvent ev)
{
infoEvents.Add(ev);
}
private string _Info = "";
public string Info
{
get
{
return _Info;
}
set
{
_Info = value;
foreach (EventHandling.XObjectEvent x in infoEvents)
{
x.setObject(this);
x.execute();
}
}
}
Way 3
got a better way? :)
Ye Olde New Answer
Here are some Stack Overflow questions that deal with implementing MVC in a Windows Form Application:
Implementing MVC with Windows Forms.
How would you implement MVC in a Windows Form Application?
Ye Olde Olde Answer
Use ASP.NET MVC 1.0.