How to use the same info across multiple forms - c#

I am working on my first C# program and have run into a brick wall. I want to be able to set and get variables throughout diferent forms in the same application.
I created a class called "data" which contains the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Application1
{
public class data
{
public string SearchAirport
{
get
{
return searchairport;
}
set
{
searchairport = value;
}
}
}
}
What do I need to put into my forms to be able to use this class??
Right now all I have is:
data.SearchAirport = commandAirport;
string working = data.SearchAirport;
I know I have to add something else to keep from getting the:
"Error 11 An object reference is required for the non-static field, method, or property 'Sector_Datastore_2._0.data.SearchAirport.get'..."
error

Well, you need to declare searchairport:
public class data
{
private string searchairport;
public string SearchAirport
{
get
{
return searchairport;
}
set
{
searchairport = value;
}
}
}
alternatively, you could let C# do that automatically by using the following code:
public class data
{
public string SearchAirport
{
get;
set;
}
}

You are accessing searchAirport statically, and the method itself is not static.
You can either add the static keyword to the SearchAirport method signature or create a data object and then call SearchAirport on that object.

I'd suggest a Service Locator pattern, but I'm afraid it's way too complicated for what the Question-poster wants to achieve.
Just in case it may be useful later on: Service Locator pattern

data d = new data();
....before those lines

Related

Keep getting the CS0122 Error and do not understand how to fix it

I have this code, and the 'lblPatientVital1-4', 'lblBedNumber' and 'lblPatientName' bits of code keep giving me the CS0122 error. Saying it is inaccessible due to its protection level. I have looked around the internet made the source files not read only but still have no luck.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace HospitalMonitor
{
public class Controller
{
public CentralModule centralStationBedsideDetails;
public string module1Name, module2Name, module3Name, module4Name, bedName, patientName;
public CentralModule CentralStationBedsideDetails
{
get { return centralStationBedsideDetails; }
set { centralStationBedsideDetails = value; }
}
public void SetSelectedModules(string module1, string module2, string module3, string module4, string bednumber, string pName)
{
module1Name = module1;
module2Name = module2;
module3Name = module3;
module4Name = module4;
bedName = bednumber;
patientName = pName;
SetCentralStationBedsideDetails();
}
public void SetCentralStationBedsideDetails()
{
centralStationBedsideDetails.lblPatientVital1.Text = module1Name;
centralStationBedsideDetails.lblPatientVital2.Text = module2Name;
centralStationBedsideDetails.lblPatientVital3.Text = module3Name;
centralStationBedsideDetails.lblPatientVital4.Text = module4Name;
centralStationBedsideDetails.lblBedNumber.Text = bedName;
centralStationBedsideDetails.lblPatientName.Text = patientName;
}
}
}
If you look at the line
centralStationBedsideDetails.lblPatientVital1.Text = module1Name;
the error message is telling you that
lblPatientVital1
is a property or field of centralStationBedsideDetails that is declared as (mostly likely) private (and certainly not public). This is common in WinForms forms.
You can either modify that property to make it public (or internal, if this code is in the same assembly), or you can provide an additional wrapper property or method that sets/gets the value of that internal property/field and is visible to your code (public, or internal and in the same assembly).
You're not showing the code for it, but presumably the implementation for CentralModule has members (either properties or class-level variables) by those names. The error is telling you that you're trying to access them as though they are public, but they are not public.
They may be protected, internal, or private perhaps. But they are not public. And therefore your code can't directly access them on that object.
You can make them public, or you can make public members (properties or methods) which provide the functionality you're looking for. Perhaps something like this:
public Label PatientVital1
{
get { return lblPatientVital1; }
}
which you could use as:
centralStationBedsideDetails.PatientVital1.Text = module1Name;
Or, to de-couple consuming code from UI technologies, you can just expose a method:
public void SetPatientVital1Text(string text)
{
lblPatientVital1.Text = text;
}
which you could use as:
centralStationBedsideDetails.SetPatientVital1Text(module1Name);

Better understanding scope

I'm still very new to C#, but I thought I understood the concept of scope. I'm having a problem with a program and I would really appreciate some help.
The problem with the following code is that Line 35 fails with
"An object reference is required for the non-static field, method, or property".
You can see that object Mail is instantiated as part of the Program class and it seems like it should be globally accessible. But when I try to use Mail.Add in the InitMail() method, it doesn't recognize the Mail object.
If I move the instantiation and InitMail code into Main(), it works just fine (although I also have to remove public modifier on the instantiation). What am I not understanding here?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace TestApp1103
{
class Program
{
// Define an enum type named "Division" specifying all possible values:
public enum Division {PFR, PSE, PVF, PVM, PVS}
//Define a generic class named "MailList" and specify accessor methods:
public class MailList
{
public Division Div { get; set;}
public string[] SuccAddr { get; set; }
public string[] FailAddr { get; set; }
}
// Instantiate a MailList object named "Mail":
public List<MailList> Mail = new List<MailList>();
static void Main(string[] args)
{
// Populate the object "Mail":
InitMail();
}
static void InitMail()
{
Mail.Add( new MailList()
{
Div = Division.PFR,
SuccAddr = new string[2] { "addr1#contoso.com", "addr2#contoso.com" },
FailAddr = new string[2] { "addr3#contoso.com", "addr4#contoso.com" }
});
}
}
}
static void InitMail() {
Mail.Add( new MailList() {
// properties
});
}
This will try to add a new MailList object to Mail.
However when we look at Mail, we see this declaration:
public List<MailList> Mail = new List<MailList>();
Notice the absence of static which is present in InitMail().
This means that when the method InitMail() would be executed statically (Program.InitMail()), it would try to access the non-static variable Mail.
Thus the compiler complains.
Mail is an instance field - not a static one.
That means it belongs to instances of the class it is declared on - which there are none.
There are a couple of ways to go about fixing the issue:
Make the field static.
Instantiate Program and call InitMail on the variable.
You are trying to access the instance variable Mail from a static method.
This can not work as you need an object instance of your class Program to access the instance variable

Following the DRY principle in ASP.NET

I have just recently got involved in a classic ASP.NET project which contains lots of storing and reading values from the session and query strings. This could look something like the following:
Session["someKey"]=someValue;
And somewhere else in the code the value in the session is read. Clearly this violates the DRY principle since you'll have the literal string key spread out all over the code. One way to avoid this could be to store all keys as constants that could be referenced everywhere there is a need to read and write to the session. But I'm not sure that's the best way to do it. How would you recommend I best handle this so that I don't violate the DRY principle?
Create a separate public class where you can define your constants, e.g
public class SessionVars
{
public const string SOME_KEY = "someKey";
public const string SOME_OTHER_KEY = "someOtherKey";
}
and then anywhere in your code you can access session variables like this:
Session[SessionVars.SOME_KEY]=someValue;
This way you can get IntelliSence and other bells and whistles.
I think you're reading too much into DRY. I pertains more to things that could be wrapped up in a function. I.e. instead of repeating the same fives lines all over the place wrap those 5 lines in a function and call the function everywhere you need it.
What you have as an example is just setting a value in a dictionary (the session object in this case), and that is the simplest way to store and retrieve objects in it.
I can't remember for the life of me where I humbly re-purposed this code from, but it's pretty nice:
using System;
using System.Web;
namespace Project.Web.UI.Domain
{
public abstract class SessionBase<T> where T : class, new()
{
private static readonly Object _padlock = new Object();
private static string Key
{
get { return typeof(SessionBase<T>).FullName; }
}
public static T Current
{
get
{
var instance = HttpContext.Current.Session[Key] as T;
lock (SessionBase<T>._padlock)
{
if (instance == null)
{
HttpContext.Current.Session[Key]
= instance
= new T();
}
}
return instance;
}
}
public static void Clear()
{
var instance = HttpContext.Current.Session[Key] as T;
if (instance != null)
{
lock (SessionBase<T>._padlock)
{
HttpContext.Current.Session[Key] = null;
}
}
}
}
}
The idea behind it two fold. The type created should be the only type you need. It's basically a big strongly-typed wrapper. So you have some object you want to keep extending information in:
public class MyClass
{
public MyClass()
public string Blah1 { get; set; }
}
Then down the road you extend MyClass and you don't want to have to remember all the Key Values, store them in AppSettings or Const variables in Static Classes. You simply define what you want to store:
public class MyClassSession : SessionBase<MyClass>
{
}
And anywhere in your program you simply use the class.
// Any Asp.Net method (webforms or mvc)
public void SetValueMethod()
{
MyClassSesssion.Current.Blah1 = "asdf";
}
public string GetValueMethod()
{
return MyClassSession.Current.Blah1;
}
Optionally you could place the access to this session object in a base page and wrap it in a property:
class BasePage : Page
{
...
public string MySessionObject
{
get
{
if(Session["myKey"] == null)
return string.Empty;
return Session["myKey"].ToString();
}
set
{
Session["myKey"] = value;
}
}
...
}
Here you are repeating the myKey string but it is encapsulated into the property. If you want to go to the extreme of avoiding this, create a constant with the key and replace the string.

Using methods from another class in forms, C#

Thank you very much for the response. I have edited my post to show the QuoteMgr class. I use this mostly to read and save quotes to file; it is read back into an array of quotes called mylist. I can't figure out how to call QuoteMgr methods from within all of the four forms I have created. The only way I have found is to instantiate QuoteMgr from within one of the forms, but that won't work for the other three forms. The method I want to use in different forms is getRandomQuote() - haven't written the other methods yet.
My plan was to read data from a file, display the quote on the main form, and offer choice to add more quotes, edit one, or display another quote. A different form would be displayed, appropriate to the choice made.
At heart the problem is I don't fully grasp OOP. I understand the idea of having an abstract class to inherit methods from. If I do this, will the different forms be able to access my array of quotes ("mylist")? For data integrity, I think I only want one instance of my data floating around. In which case, I could have an abstract class with all of the quote manipulation methods, and use QuoteMgr only to read/write to file.
From the standpoint of learning the right way to program, is this the right design?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
namespace Quote
{
class QuoteMgr
{
Quotes myquote = new Quotes();
Quotes objectToSerialize = new Quotes();
Serializer serializer = new Serializer();
string myFile = "H:\\Dad\\Quotes\\quotes.quo";
public QuoteMgr()
{
}
static Random r = new Random();
public void getFile()
{
//fills myquote.mylist with quote strings from file
if (File.Exists(myFile))
{
objectToSerialize = serializer.DeSerializeObject(myFile);
myquote.myList = objectToSerialize.QuoteList;
//myquote.ShowQuotes();
}
else
{
FileInfo makeFile = new FileInfo(#myFile);
makeFile.Create();
}
}//end of get file
public void saveFile()
{
objectToSerialize.QuoteList = myquote.myList;
serializer.SerializeObject(myFile, objectToSerialize);
}
public string getRandomQuote()
{
int x = myquote.myList.Count-1;
return myquote.myList[r.Next(x)];
}
public void GUIop()
{
getFile();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 myMainScreen = new Form1();
//make all other forms invisible
myMainScreen.Visible = true;
changeQuoteDisplayed(myMainScreen);
Application.Run(myMainScreen);
saveFile();
}
public void changeQuoteDisplayed(Form1 theForm)
{
string s;
s = getRandomQuote();
theForm.lblDisplayQuote.Text = s;
}
}
}
It sounds like you should move the changeQuoteDisplayed method into your Form class...it doesn't make any sense to call a method in another class with your Form as an argument, only to have the other class modify the form you passed it. For one, you should not have public UI components inside your Form..if you must modify these from outside the form, make their data accessible through Properties.
If this is a method that all of your forms need to use, then perhaps you should allow them to inherit it through an abstract class, providing an abstract property as well that your child classes will use to implement set, making it update whatever UI component the child class needs updated on that method call. It could look something like this:
public abstract class QuoteBase
{
protected void changeQuoteDisplayed()
{
string s;
s = getRandomQuote();
LabelText = s;
// theForm.lblDisplayQuote.Text = s;
}
public abstract String LabelText
{
get; set;
}
}
public class EditQuote : QuoteBase
{
public override String LabelText
{
get { return lblDisplayQuote.Text; }
set { lblDisplayQuote.Text = value; }
}
}
Now all you need to do is implement the LabelText property in all of your Quote classes to update whatever label you want without needing to send an instance of your form to some other class to get an update.
Of course, this is just a wild guess..it's hard to tell what you should actually do without more information.

Property is null, even after being set in code

I've been trying to solve this for ages (3 days) now and I just cannot figure it out. I will try to explain the problem comprehensively because it is a bit more complex.
My school assignment is to create a simple text game using OOP in C# Visual Studio 2008 (should be built on a library the teacher provided for us). It should only use console. I have a decent experience with OOP from PHP and C++ but I still cannot figure this out.
80% of the text game is already working so I won't bore you with classes and stuff that already works and is not related to the problem. Ok let's get started:
Each command in the game (what you can type into the console and hit enter) is represented by a single class both extending an abstract class and an interface from the library I am supposed to built the game on. Bellow is a class Use which represents a command for using items (e.g. you type "use sword" into the console and the game will look for an item called sword and call its use method):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Game.Commands
{
class Use : TextGame.Commands.ACommand, TextGame.Commands.ICommand
{
private string name;
public new string Name
{
set { this.name = value; }
get { return this.name; }
}
private string description;
public new string Description
{
set { this.description = value; }
get { return this.description; }
}
private string parameters;
public new string Params
{
set { this.parameters = value; }
get { return this.parameters; }
}
public Use(string name, string description) : base(name, description)
{
this.name = name;
this.description = description;
}
private TextGame.Core.GameState gameState;
public TextGame.Core.GameState Execute(TextGame.Core.IGame game)
{
// This is just a test because it appears the problem is
// with the parameters property. There should be a command
// you have typed in the console but its always null
// Note that I have not yet coded the body of this method.
// I will do that once I solve the problem.
if (this.parameters == null)
{
Console.WriteLine("is null");
}
else
{
Console.WriteLine(this.parameters);
}
return this.gameState;
}
}
}
There are two other classes that are used. The Parser class and the Game class. There are a bit longer so I will only post snippets of relevant stuff from them. Parser class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; // ArrayList, Dictionary, Hashtable
using System.Text.RegularExpressions; // regex engine
using Game.Commands;
namespace Game
{
class Parser
{
private ArrayList commands = new ArrayList();
// All commands that are available in the game so far are
// initialized here in the constructor (and added to the arraylist)...
// skip to the other method this is not important
public Parser()
{
this.commands.Add(new North("^north", "Go north"));
this.commands.Add(new South("^south", "Go south"));
this.commands.Add(new East("^east", "Go east"));
this.commands.Add(new West("^west", "Go west"));
this.commands.Add(new Use("^use\\s\\w+", "Try to use the selected item"));
this.commands.Add(new Quit("^quit", "Quit the game"));
}
// This method takes as an argument a string representing
// a command you type in the console. It then searches the arraylist
// via the regex. If the command exists, it returns an the command object
// from the arraylist
// This works fine and returns right objects (tested)
public TextGame.Commands.ACommand GetCommand(string command)
{
TextGame.Commands.ACommand ret = null;
foreach (TextGame.Commands.ACommand c in this.commands)
{
Regex exp = new Regex(#c.Name, RegexOptions.IgnoreCase);
MatchCollection MatchList = exp.Matches(command);
if (MatchList.Count > 0)
{
ret = c;
}
}
return ret;
}
}
}
Now a snippet from the Game class where I'm using both above classes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TextGame.Core;
using System.Collections;
using Game.Items;
using Game.Commands;
namespace Game
{
class Game : TextGame.Core.IGame
{
public void Play()
{
// Here I read commands from the console in a loop and
// call the ProcessCommand() method. No problem here.
while (true)
{
string command = Console.ReadLine();
this.ProcessCommand(command);
}
}
// This is the IMPORTANT method so take a closer look
private TextGame.Core.GameState gameState;
public TextGame.Core.GameState ProcessCommand(string command)
{
Parser parser = new Parser();
TextGame.Commands.ACommand c = parser.GetCommand(command);
if (c != null)
{
// HERE I ADD THE COMMAND FROM THE CONSOLE TO THE C OBJECT
// I ADD IT VIA THE SETTER TO THE PARAMETERS PROPERTY
// OF THE COMMAND
c.Params = command;
// AND I CALL THE COMMAND'S EXECUTE() METHOD - SEE THE FIRST CLASS -
// USE - WHERE I TEST FOR THE PARAMS PROPERTY BUT IT IS STILL NULL
this.gameState = ((TextGame.Commands.ICommand)c).Execute(this);
}
}
}
}
I have added comments to the snippets to describe where is the problem. I hope I have explained it well.
Anyone has any ideas? I've been working on this projects for about 3 weeks now and most of the stuff went smoothly when 3 days ago I came across this problem and since then I've been trying to get my head around this problem.
Your problem is with the 'new' keyword. Here's where you're using it in the 'Use' class:
private string parameters;
public new string Params
{
set { this.parameters = value; }
get { return this.parameters; }
}
You're creating a different property that just happens to have the same name as a property on the type you are inheriting from. The 'new' keyword tells the compiler you meant to do that.
Basically, this means that if you do the following:
var x = new Use();
x.Params = "abcd";
((ACommand)x).Params = "wxyz";
Console.Writeline("direct: " + x.Params);
Console.Writeline("ACommand: " + ((ACommand)x).Params);
You'll get this output:
direct: abcd
ACommand: wxyz
You probably want to remove the definition of 'Params' entirely from Use and just inherit the one from ACommand. Probably from Name and Description as well, but you should be able to figure out from here if you want that or not.
Without seeing the code for the ACommand class... Try removing the "new" operator in the Params declaration of the Use class. When your setting the property c.Params = command; is actually setting the property of the base class, in the Execute method your checking this.parameters instead of base.Params.
// This is just a test because it appears the problem is
// with the parameters property. There should be a command
// you have typed in the console but its always null
// Note that I have not yet coded the body of this method.
// I will do that once I solve the problem.
This is caused by you declaring new on your properties. These should be override, or not included at all if you don't need to change the logic of ACommand.
When you reference as an ACommand:
TextGame.Commands.ACommand c = parser.GetCommand(command);
c.Params = command;
You will use either ACommand's Params, or your overrides (if you had defined one).
Your new Params shadow ACommand's Params, and are only accessible if your reference is a UseCommand.
Your problem is here:
private string parameters;
public new string Params
{
set { this.parameters = value; }
get { return this.parameters; }
}
In your code:
c.Params = command;
you are referencing the type TextGame.Commands.ACommand. Because you're hiding the Param property in your subclass, you're causing a non-polymorphic reference. Remove the definition above and rely on the base class definition of Param, and you'll be fine.
It's been a while since I ran into this problem, but if you open that up in Reflector I expect you will see that you are hiding the Use.Params property behind a callvirt explicitly bound to its base type there.... as the faster typists pointed out.

Categories

Resources