I can't find a specific problem that matches mine, which I think has to do with the fact that I am creating a subclass of EventArgs with one argument, a string. When I try to compile, it seems to tell me that ScanInfoEventArgs doesn't have one constructor, when it clearly does (clearly to me at least).
I've only included the bit of code that I think applies. It seems like such a simple thing that I am at a loss.
public partial class MainWindow : Window
{
Coffee coffeeOnHand;
SweetTea sweetTeaOnHand;
BlueberryMuffin blueberryMuffinOnHand;
public MainWindow()
{
InitializeComponent();
//The following reads the inventory from file, and assigns each inventory item to the Coffee, SweatTea
//and BlueberryMuffin objects in memory.
using (Stream input = File.OpenRead("inventory.dat"))
{
BinaryFormatter formatter = new BinaryFormatter();
coffeeOnHand = (Coffee)formatter.Deserialize(input);
sweetTeaOnHand = (SweetTea)formatter.Deserialize(input);
blueberryMuffinOnHand = (BlueberryMuffin)formatter.Deserialize(input);
}
//The following adds whatever information is loaded from the objects on file from above
//into the dropdown box in the menu.
SelectedItemDropdown.Items.Add(coffeeOnHand);
SelectedItemDropdown.Items.Add(sweetTeaOnHand);
SelectedItemDropdown.Items.Add(blueberryMuffinOnHand);
}
public class ScanInfoEventArgs : EventArgs
{
ScanInfoEventArgs(string scanType)
{
this.scanType = scanType;
}
public readonly string scanType;
}
public class Scan
{
//Delegate that subscribers must implement
public delegate void ScanHandler (object scan, ScanInfoEventArgs scanInfo);
//The event that will be published
public event ScanHandler onScan;
public void Run()
{
//The ScanInfoEventArgs object that will be passed to the subscriber.
ScanInfoEventArgs scanInformation = new ScanInfoEventArgs("scanType");
// Check to see if anyone is subscribed to this event.
if (onScan != null)
{
onScan(this, scanInformation);
}
}
}
You need to make your constructor public. All class members default to private, which means the outside world can't get at them.
Since the compiler didn't see a matching public constructor (as in, one the code could actually invoke), it threw the error you saw.
Correct code:
public ScanInfoEventArgs(string scanType)
{
this.scanType = scanType;
}
Note that internal would work as well if all code resides in the same assembly.
Related
I am brand new to C# (I apologise if my question is noobish - I'm teaching myself, so it's a bumpy process). I am trying to develop a winform and since some of the methods are pretty long, I am trying to keep it in a couple classes. This is what I'm kind of hoping to achieve:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1();
}
}
public class longCalculations
{
private void LongMethod1()
{
// Arbitrarily long code goes here
}
}
I'm doing this in an attempt to keep the formMainForm class tidy and be able to split any calculations into manageable chunks. However, I'm encountering problems with using form controls (e.g. check boxes, numeric up-down controls, etc.) in my non-form classes.
If I leave them as is (e.g. CheckBox1) I get a the name does not exist in the current context error. I searched around and I found that it's because that box is defined in a different class. However, if I change it to formMainForm.CheckBox1, the error is now an object reference is required for the non-static field, method or property. Again, I looked around and it appears that that is due to the form initialization method not being static.
If I change public formMainForm() to static formMainForm(), the error now moves to InitializeComponent(); and I do not know where to go from here. I also tried making an instantiation of the formMainForm() method, but that didn't do anything (the code I attempted to use is below. I found it somewhere on this site as an answer to a similar problem).
private void formLoader(object sender, EventArgs e)
{
shadowrunMainForm runForm = new shadowrunMainForm();
runForm.Show();
}
How can I use the formcontrol names in other classes?
P.S. It is my first post here - I am super sorry if I have missed this question already being asked somewhere. I did search, but I didn't find what I was looking for.
EDIT
It seems I hadn't made myself clear - this was just an example of code and my problem is with the second class, not the first one. I have now simplified the code to:
public partial class formMainForm : Form
{
public formMainForm()
{
InitializeComponent();
}
}
public class longCalculations
{
private void LongMethod1()
{
List<CheckBox> listOfBoxes = new List<CheckBox>();
listOfBoxes.Add(CheckBox1);
// The code displays an "object reference is required for the non-static field, method or property" error at this stage. Changing the "CheckBox1" to formMainForm.CheckBox1 doesn't help
// Arbitrarily long code goes here
}
}
LongMethod1 works perfectly fine when placed in the formMainForm partial class. Moving it to the other form makes it unable to take data from those checkboxes.
I believe this line longCalculations.LongMethod1(); is throwing error cause you are trying to access a instance method as if it's a static method and as well it's defined as private method which won't be accessible outside the class. You need to create an instance of longCalculations class before accessing any of it's member or method(s) and mark the method public like
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations ln = new longCalculations();
ln.LongMethod1();
}
public class longCalculations
{
public void LongMethod1()
{
// Arbitrarily long code goes here
}
}
(OR) If you really want it to be a static method then define accordingly with static modifier like
public class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
Now you can call it like the way you are trying
public static class longCalculations
{
public static void LongMethod1()
{
// Arbitrarily long code goes here
}
}
If you're going to make a call longCalculations.LongMethod1();, then you need to make your class static as such.
Or you leave it as not static method by calling
longCalculations lc = new longCalculations()
lc.LongMethod1();
As for accessing controls in separate classes, you can pass in the form and make the controls public which can be dangerous.
So on your Form.designer.cs, change any control you may have to public modifier. Then you would make a call like this...
private void UpDown1_ValueChanged(object sender, EventArgs e)
{
longCalculations.LongMethod1(this);
}
public void LongMethod1(Form1 form)
{
// Arbitrarily long code goes here
form.label1.Text = someString;
//more settings and whatnot
}
Or do something like this:
public class longCalculations
{
public string LongMethod1()
{
// Arbitrarily long code goes here
return myString;
}
}
longCalculations lc = new longCalculations()
string result = lc.LongMethod1();
this.label1.Text = result;
Ideally, your longCalculations class would not attempt to modify the form directly. Instead it would return an object that the form could use to update its controls.
If you need to access the form directly from the longCalculations class, first change the method to accept an instance of your form
public void LongMethod1(formMainForm myForm)
Then you can pass the form itself as a parameter
var calc = new longCalculations();
calc.LongMethod1(this);
In your other class, you need to have an instance of your formMainForm class:
var myForm = new formMainForm();
Then you can access its members like this:
myForm.CheckBox1.Checked = true;
I'm wondering as to why my private variable 'name' within my Events class won't change when I access the property from my Leisure class which inherits from Events. I need Leisure to use the properties to change it, and then in my form class, it should be able to read the value of 'name' from events. See below:
public partial class Form1 : Form //Main form class
{
private string eventType; //used for event type selection
private string formEventName; //used to store selected event name
private void itemSend_Click(object sender, EventArgs e)
{
//encapsulation
Events myEv = new Events();
string name=itemInput.Text;
myEv.myEvent(eventType, name);
formEventName = myEv.myName;
txtOutput.Text = "Event name is " + formEventName + "\r\n";
}
class Events:Form1
{
private string name; //private variable for event name
public string myName //used to change property value depending on what eveny type/ event name
{
get { return name; }
set { name = value; }
}
public void myEvent(string eventType, string eventName) //variable recieved from main form class
{
if (eventType == "Leisure")
{
Leisure myLes = new Leisure();
myLes.eventNames(eventName);
}
else
{
//test for other event types
}
}
class Leisure:Events
{
public void eventNames(string eventName)
{
//when adding new items add one with a capital and one without
myEventNames.Add("music");
myEventNames.Add("Music");
if (myEventNames.Contains(eventName))
{
myName = eventName;
}
else
{
MessageBox.Show("item not found, please try again"); //error message
}
}
}
It seems wrong that Events inherits from Form1.
When you say new Events(), you get a new object, unrelated to the existing form, and any changes you make to it have no effect on the existing form. That happens again when you say new Leisure().
The myName property you are using changes the name private field of myLes instance and not the name private field of myEv instance created in the ItemSend_Click.
In an Object Oriented Language when you create an instance of a class, that instance has a copy of every non-static private/public variable declared in the class. So when you write
Leisure myLes = new Leisure();
you are creating an instance of Leisure class, but this instance, while inherithing from Events has a different set of internal variables and not the same variables of the current Event instance (myEv).
Looking at your code I suggest to create a third class called
public class EventFactory
{
public Event CreateEvent(string eventType, string eventName)
{
switch(enventType)
{
case "Leisure":
Leisure myLes = new Leisure();
myLes.eventNames(eventName);
return myLes;
// case Add other specialized events here:
// break;
default:
return null;
}
}
}
change your Events class removing the inheritance from Form1 (not needed as far as I can tell) and the method myEvent
now your ItemSend_Click could be written in this way
private void itemSend_Click(object sender, EventArgs e)
{
Events myEv = new EventFactory().CreateEvent(eventType, itemInput.Text);
formEventName = myEv.myName;
txtOutput.Text = "Event name is " + formEventName + "\r\n";
}
this works because Leisure derives from Events and you could treat every Leisure instance as an Event instance.
You just change myName of the myLes (Leisure) variable in your myEv field, thats why myEv.myName is still empty.
So the problem that you're having is just a small symptom of major fundamental problems in your code that will only continue to manifest themselves as you continue.
I've re-written what you have into something that's more in line with what is more traditionally seen for what you're trying to do. It's not perfect, and I've tried to keep things fairly simple so as to not throw too much at you at once.
public partial class Form1 : Form //Main form class
{
private TextBox itemInput;
private TextBox txtOutput;
private string eventType; //used for event type selection
private string formEventName; //used to store selected event name
private void itemSend_Click(object sender, EventArgs e)
{
string name = itemInput.Text;
try
{
Event myEvent = Event.Create(eventType, name);
txtOutput.Text = "Event name is " + myEvent.Name + "\r\n";
}
catch (ArgumentException ex)//if the event name isn't valid
{
MessageBox.Show(ex.Message);
}
}
}
public abstract class Event
{
public string Name { get; private set; }
public Event(string eventName)
{
Name = eventName;
}
public static Event Create(string eventType, string eventName)
{
if (eventType == "Leisure")
{
Leisure myLes = new Leisure(eventName);
return myLes;
}
// else if { ... } test for other event types
else
{
return null;
}
}
}
public class Leisure : Event
{
private static List<string> myEventNames =
new List<string>() { "music", "Music" };
public Leisure(string eventName)
: base(eventName)
{
if (!myEventNames.Contains(eventName))
{
throw new ArgumentException("Not a valid Leisure event name");
}
}
}
So, let's go over some of the changes. First off, Event doesn't inherit from Form1. It should not do so. An event is not conceptually a type of form at all, let alone that particular type of form. An Event should have no knowledge of any form, in any way, not just inheritance. It's just some other class that Form1 will use, but it could just as easily be used by any other type of class, form or otherwise.
In addition to making Event not inherit from Form, I've made it abstract. It doesn't have any abstract methods, it's just that you shouldn't ever be creating just an plain Event, you should only ever actually create some specific type of event. Being a common base class, it's easiest to prevent accidental creation and to help improve readability by making it abstract.
I've also made Event immutable. Rather than allowing name to be changed at any time, creating an event without giving it a name, and then changing it later, I have configured it such that you need to provide the name and type before creating the event, and then there's no way of changing it once it's created. The Name is set in the constructor, and I have added a static Create method which is where the logic can go for choosing the proper subtype of Event and actually creating it. This is a simple version of the "Factory Pattern". Note that normally I wouldn't pass the type in as a string. I would make it something like an Enum, so that it's easier to tell what the valid options are.
Now onto Leisure. Logically, Leisure really is an Event and should inherit from it. Your problems were steming from the fact that you created an instance of Event, and also an instance of Leisure, and assumed that they shared the same variables. They don't, but that confusion should go away now that you can't ever have an instance of Event.
When a Leisure is created it uses the base class constructor to set Name, since it doesn't have access to set the property itself.
From what I can see myEventNames is just a list of valid names, and it doesn't appear to change between different types of Leisure instances, so it makes sense for it to be static, which means it's shared between all instances and is only created once.
I also moved the MessageBox call out of the Leisure type's constructor. Instead I'm throwing an exception. The main idea here is that you shouldn't mix your UI code with your business code. Event and Leisure are both business objects and shouldn't know anything about what, if any, UI exists. You should be able to use them from a console app, an ASP application, etc. On top of that, since what we're trying to say is that this is an invalid name and the type shouldn't exist, the end result of throwing an Excpetion in the constructor is that the object never becomes "valid". We don't allow the creation of an object that shouldn't exist, as opposed to allowing them to continue using the object anyway.
That exception is caught with the try/catch block in Form1, where it shows the appropriate MessageBox based on the failure to create the event.
I have a class which is inherited from context bound object. Class has attribute on some properties. When some property is changed, PostProcess(IMessage msg, IMessage msgReturn) raise an event and from the event again a new property with same attribute is fired. Second change should also call PostProcess, but it is not happening. Probably because, the object where second property is changed is not original .net object but MarshalByRefObject / ContextBoundObject / Proxy Object. My query is how to cast the proxy to original object. I tried casting and SynchonizationAttribute, but it does not help. Just to let you know the events are executing in Async manner so it does not block code execution, and both proxy and original object exist in same app domain.
I tried with two object, one holding reference of second, and when property of first is changed, it try to change property of second, but it did not invoke PostProcess.
Basically I need to make a tree where various objects are depending on property of other objects. And when any one property is changed, it should trigger its watcher, and this could spread like a chain untill no watcher is found. I am trying it with ContextBoundObject.
Sample:
public class PowerSwitch : ObjectBase
{
[Watchable]
public bool IsOn { get; set; }
public bool IsWorking { get; set; }
}
public class Bulb : ObjectBase
{
public Color Color { get; set; }
[Watchable]
public bool IsOn { get; set; }
protected override void Update(object sender, PropertyChangeEventArgs e)
{
((Bulb)this).IsOn = !((Bulb)this).IsOn;
//<-- b1.update should be called after this, but it is not
}
}
[Watchable]
public class ObjectBase : ContextBoundObject
{
public virtual void Watch(ObjectBase watch, string propertyName)
{
watch.Watcher.Add(this, propertyName);
}
protected virtual void Update(object sender,
PropertyChangeEventArgs e) { }
public Dictionary<ObjectBase, string> Watcher
= new Dictionary<ObjectBase, string>();
internal void NotifyWatcher(
PropertyChangeEventArgs propertyChangeEventArgs)
{
Watcher.Where(sk => sk.Value == propertyChangeEventArgs.Name)
.ToList()
.ForEach((item) =>
{
item.Key.Update(this, propertyChangeEventArgs);
});
}
}
Main method
PowerSwitch s1 = new PowerSwitch();
Bulb b1 = new Bulb();
b1.Watch(s1, "IsOn");
s1.IsOn = true; //<-- b1.update is called after this
Please suggest alternate or better way to implement what I want to achieve.
It looks like you're very close to the observer pattern, where Observers subscribe to status notifications on a Subject.
In that pattern, b1.IsOn = true would contain code that cycles through the Observers and notifies them of changes. I guess if you wanted to observe a lot of properties on one object, you could encapsulate the notification code. Then b1.IsOn could just have a single line that says something like:
this.SendNotification("IsOn", Value);
This seems a lot like what you're doing... If you read up on the pattern you might end up feeling a little more confident, and maybe you could make a few changes to standardize your code.
By the way, there is something built into .Net for this -- IObservable(T). I haven't used this, but it looks strong.
He everybody,
I'm trying to setup a project management class.
In order to see if somthing in the data changed i want to implement events on the lower level of the programming structure. I have some Classes extending the ProjectComponent Class. The base class has an event and event throwing methode, which the childcomponents can use.
Now I have a couple of custom list (nameley eList) in the project object.
Because all the child component have a common parent, ProjectComponent, i would like my custom list object (eList) to subscribe to the event when an object is added and unsubscribe when removed.
However when trying to prog this, i received the following error:
'ProjectComponent' does not contain a
definition for 'itemChanged' and no
extension method 'itemChanged'
accepting a first argument of type
'ProjectComponent'
Which is kind of wierd seeing as the class clearly has that public field.
Here is a the code:
public class ProjectComponent
{
public event ItemChanged itemChanged;
public void throwItemChangedEvent(ItemChangedEventArgs Arguments)
{
if (itemChanged != null)
itemChanged(new Object(), Arguments);
}
}
public class eList<ProjectComponent> : IList<ProjectComponent>
{
List<ProjectComponent> internalList = new List<ProjectComponent>();
public override void Add(ProjectComponent Item)
{
this.internalList.Add(Item);
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
}
private void ItemChanged_Handler(object sender, ItemChangedEventArgs eventArgs)
{
//do stuff here
}
}
An example how it would be called is:
public eList<ChildClass> Children = new eList<ChildClass>();
The idea is that when an object in the list is edited the list object recieve an object like so:
Children.childstring = "anything";
At the moment the field inside the Children object is changed an event could be recieved.
My question is simply what am i doing wrong, why cant i suscribe to the ProjectComponent event inside the eList class?
Or does anyone know a better way to achive the same results?
Thanks in Advance,
Harry
Edit: Definition of ItemChanged delagate:
public delegate void ItemChanged(object sender, ItemChangedEventArgs eventArgs);
public class ItemChangedEventArgs : EventArgs
{
private String p_CallStack;
public String CallStack
{
get { return this.p_CallStack; }
set { this.p_CallStack = value; }
}
public ItemChangedEventArgs()
{
p_CallStack = "";
}
public ItemChangedEventArgs(String StackStart)
{
p_CallStack = StackStart;
}
}
you have 2 errors:
1.
in generic class definition you must use variables not existing classes:
public class eList<ProjectComponent>: ...
--> public class eList<T>: ...
in your case you want to do:
public class eList : IList<ProjectComponent>
2.
Item.itemChanged += new Item.itemChanged(ItemChanged_Handler);
new Item.itemChanged has no meaning, you have to use the underlying delegate type of your event:
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
N.B:
your code does not respect at all design guidelines for c#
More informations here:Naming Guidelines
Shouldn't it be
Item.itemChanged += new ItemChanged(ItemChanged_Handler);
I would like to pass the reference of a variable into a class, use it and then get it out later.
Something like this:
// Create the comment Screen
string newCommentText = "";
commentsScreen = new CommentEntry(this, ref newCommentText);
commentScreen.ShowDialog();
...
_dataLayer.SaveOffComment(newCommentText);
And then in the comment class:
public partial class CommentEntry : Form
{
public CommentEntry(Control pControl, ref string commentResult)
{
InitializeComponent();
control = pControl;
// ***** Need a way for this to store the reference not the value. *****
_commentResult = commentResult;
}
private string _commentResult;
private void CommentEntry_Closing(object sender, CancelEventArgs e)
{
_commentResult = tbCommentText.Text.Trim();
}
}
Is there someway that newCommentText can have the value set in _commentResult in the closing method?
NOTE: Clearly it would be easy to just set a variable in my class and access it after the ShowDialog. This example is only a an approximation of my real issue and accessing any variables in the class after ShowDialog is done is not possible.
This will never work with a String as they are immutable and the variable will change to point to a new instance.
You have two basic options. The first is to simply have a getter for the result so it can be accessed when it is needed later. The other option is to have the owner pass in a delegate method that can be called passing in the resulting value. The owner would then receive the value when the CommentEntry is closing.
You generally can't directly store a 'reference to a reference' in C#, but you could do something like this:
public interface ICommented
{
string Comment { get; set; }
}
public class MyClass : ICommented
{
public string Comment { get; set; }
}
public partial class CommentEntry : Form
{
public CommentEntry(Control pControl, ICommented commented)
{
InitializeComponent();
control = pControl;
// ***** Need a way for this to store the reference not the value. *****
_commented = commented;
}
private ICommented _commented;
private void CommentEntry_Closing(object sender, CancelEventArgs e)
{
_commented.Comment = tbCommentText.Text.Trim();
}
}
So now your form can edit the comment of any class that has said it knows how to be commented upon.
As Dan Bryant pointed out, you cannot do that directly. One option is to wrap the reference into a class, but that requires writing a lot of boilerplate code. A simpler option is to use delegate and lambda functions (in C# 3.0) or anonymous delegates (C# 2.0):
string newCommentText = "";
// Using lambda that sets the value of (captured) variable
commentsScreen = new CommentEntry(this, newValue => {
newCommentText = newValue });
commentScreen.ShowDialog();
_dataLayer.SaveOffComment(newCommentText);
A modified version of the CommentEntry form would look like this:
public partial class CommentEntry : Form {
public CommentEntry(Control pControl, Action<string> reportResult) {
InitializeComponent();
control = pControl;
// Store the delegate in a local field (no problem here)
_reportResult = reportResult;
}
private Action<string> _reportResult;
private void CommentEntry_Closing(object sender, CancelEventArgs e) {
// Invoke the delegate to notify the caller about the value
_reportResult(tbCommentText.Text.Trim());
}
}
Make newComment property of CommentEntry class.
Here, try out what this guy is doing.
http://www.c-sharpcorner.com/UploadFile/gregory_popek/WritingUnsafeCode11102005040251AM/WritingUnsafeCode.aspx