I am trying to use a method inside class, from another class.
namespace Crystal.Utilities
{
public class Logging
{
public static void Log()
{
//dostuff
Crystal.MainForm.general_log_add_item("Hello World");
}
}
}
namespace Crystal
{
public partial class MainForm : Form
{
public void general_log_add_item(string msg)
{
listBox1.Items.Add(msg);
}
}
}
I want to be able to call Crystal.Utilities.Logging.Log() from anywhere, and that to be able to call Crystal.MainForm.general_log_add_item() . But It doesn't let me, because if I put it as public, then I can't see it, if it's static then It can't interact with my listbox.
This is a wrong approach. Your class should not call into the UI, as the UI could change. The class should not know nor care about the UI. Instead, the class could expose an event that the form could subscribe to, and update based upon the information contained within the event's arguments.
Here's a hastily thrown together example.
class Program
{
static void Main()
{
Logger.OnLogging += Logger_OnLogging;
Logger.Log();
Logger.OnLogging -= Logger_OnLogging;
}
static void Logger_OnLogging(LoggingEventArgs e)
{
Trace.WriteLine(e.Message);
}
}
public class Logger
{
public delegate void LoggingEventHandler(LoggingEventArgs e);
public static event LoggingEventHandler OnLogging;
public static void Log()
{
// do stuff
RaiseLoggingEvent("Data logged");
}
protected static void RaiseLoggingEvent(string message)
{
if (OnLogging != null)
OnLogging(new LoggingEventArgs(message));
}
}
public class LoggingEventArgs : EventArgs
{
public LoggingEventArgs(string message)
{
this.Message = message;
}
public string Message { get; private set; }
}
Instead of implementing it as a static method, try implementing as a singleton. It's a common trick to make an instance global in scope, and restrict to one instance, without making everything static (and thus unable to be used as an instance).
You have to understand that the window is not static, there is one instance of him, thats why the method cant be static,
you can use
Application.Windows to reach this instance and call the add method.
or you can register the window in his constructor on another class that will mediate the Logging and the window.
If you don't understand tell me and I'll try to be more clear
When you declare a method as "static" you're saying that it's not dependent upon a specific instance of the class it's in.
For example if you have a class named "chair" and you want to count how many chairs there are, you'll do that with a static field, and a static method to return that field's value.
The count of all chairs is not related to a specific chair.
In your case you want to add a static method to add an item to a specific instance of a Form. That's impossible and doesn't make sense.
If you want to add an item to a listBox, it must be through a public method.
So basically what I'm saying is - rethink what you're trying to do, there's a good explanation as to why you're not succeeding in doing that.
Related
I have two classes that I'd like to keep in separate files.
namespace GridSystem
{
public class Grid
{
public void AddItem(GridItem item)
{
item.InformAddedToGrid();
}
}
}
namespace GridSystem
{
public class GridItem
{
public void InformAddedToGrid()
{
Debug.Log("I've been added to the grid");
}
}
}
How do I ensure no other classes are allowed to call InformAddedToGrid?
I'm trying to emulate Actionscript namespaces, which can be used on a method, in place of public, private, internal, etc. It doesn't exactly protect the method, but forces an extra step of including the namespace before the method can be accessed. Is there an alternative approach to this in C#?
If GridItem itself can be hidden from the outside world as well I would consider putting GridItem inside Grid as a nested class. That way it won't be visible outside of the class
http://www.codeproject.com/Articles/20628/A-Tutorial-on-Nested-Classes-in-C
Not that you should do this, you should do what TGH suggests, have a public interface for GridItem, and have gridItem nested in Grid (then have a factory method on Grid to create Items and use partial Grid class to have them in separate files).
Because there isn't a way of having friend methods ( you can do friend classes through InternalsVisibleToAttribute )
You COULD do this ( but don't... )
public partial class Grid
{
public void AddItem(GridItem item)
{
item.InformAddedToGrid();
}
}
public class GridItem
{
public void InformAddedToGrid()
{
if (new StackTrace().GetFrame(1).GetMethod().DeclaringType !=
typeof(Grid)) throw new Exception("Tantrum!");
Console.WriteLine("Grid called in...");
}
}
then
var g = new Grid();
g.AddItem(new GridItem()); // works
new GridItem().InformAddedToGrid(); // throws a tantrum...
A really ugly answer would be to make it private and use reflection.
Another ugly answer would be to make it throw an exception if the caller is wrong.
Both of these are much slower to execute than a normal call also.
I don't think there's a good answer. C# doesn't have friends.
IMHO the answer is simple: access modifiers are just there to remind the programmer of the intent of how public/private a class should be. Through reflection you can lift those barriers.
The usage you make of a class is all in your hands: if your class is meant to only be used in one place, make it so. If anything, if a class has a special way of being used, document it - put it in the XML comments.
That said, in this specific example I'd believe since the GridItem doesn't add itself to the grid, it's not its job to notify about it (what if "I've not been added to the grid"?). I think InformAddedToGrid belongs somewhere in your Grid class as a private method, where there's a concept of adding an item... assuming that's what AddItem(GridItem) really does.
You can do it as TGH suggested, with nested classes, except the other way around. Nest Grid within GridItem and make InformAddedToGrid private. Here I use a nested base class so the public API can remain the same. Note that no one outside of your assembly can inherit from GridBase because the constructor is internal.
public class GridItem
{
public class GridBase
{
internal GridBase() { }
public void AddItem(GridItem item)
{
item.InformAddedToGrid();
}
}
private void InformAddedToGrid()
{
Debug.Log("I've been added to the grid");
}
}
public class Grid : GridItem.GridBase { }
Another option is to have GridItem explicitly implement an internal interface. This way no one outside of your assembly can use the interface by name and therefore cannot call InformAddedToGrid.
public class Grid
{
public void AddItem(GridItem item)
{
((IGridInformer)item).InformAddedToGrid();
}
}
public class GridItem : IGridInformer
{
void IGridInformer.InformAddedToGrid()
{
Debug.Log("I've been added to the grid");
}
}
internal interface IGridInformer
{
void InformAddedToGrid();
}
I have a method in my Mainwindow, i want to call this method in an other usercontrol.
I dont use a static method because my MainWindow is not Static, and I can't make it static.
So I figured out to use this, but I dont know what comes behind the AS and I dont know if I can put a method is VAR?
I also can't make another MainWindow instance because that gives me a Stackoverflow exception.
How can I solve this?
var myMethode= mainWindow.FindName("MyMethode") as (should be a methode);
if (myMethode!= null)
{
//My code
}
You can define a static method on a class that is not static.
For example:
static void Main()
{
Foo foo = new Foo();
Foo.DoSomething();
foo.DoSomethingElse();
}
public class Foo
{
public static void DoSomething()
{
Console.WriteLine("DoSomething");
}
public void DoSomethingElse()
{
Console.WriteLine("DoSomethingElse");
}
}
But wouldn't it be a better solution to pass the MainWindow as a parameter into the User Control? So the user controls knows to which window it belongs and can access a function on it? (even better to declare an interface for this and pas the interface around).
This would look like:
public interface IWindow
{
string SomeWindowActivity();
}
public class MyUserControl
{
public IWindow Window { get; set; }
public void SomeActionOnUserControl()
{
string data = Window.SomeWindowActivity();
}
}
public class MainWindow : IWindow
{
MyUserControl MyUserControl { get; set; }
public MainWindow()
{
// Link the UserControl to the Window it's one. This can be done trough the
// constructor or a property
MyUserControl.Window = this;
}
public string SomeWindowActivity()
{
// Some code...
return "result";
}
}
Try this
((MyMainWindow)Application.Current.MainWindow).Method()
You don't need to make MainWindow singleton in your case, you have access to it from Application.Current singleton
Application.Current.MainWindow
Hope this helps
Short unswer: you can't. You want to call a instance method, you need to have an instance.
The fact that MainWindow is not static does not prevent you from defining static methods in it, as long as those methods do not use other instance members, so if it a helper method, you can define it static and call from other place, it might a good idea to refactor it out of MainWindow class then.
If it's a nonstatic method, you claim you don't want to create second instance of MainWindow, why not call it on first instance then, by passing it to your control?
Also, if creating another instance of MainWindow gives you stackoverflow, maybe it's because you just did some recurrent call with this method, and it can be fixed?
I am writing a class library(API) in C#. The class is non-static and contains several public events. Is it possible to trigger those events from a static method in a separate class?
For example...
class nonStaticDLLCLASS
{
public event Event1;
public CallStaticMethod()
{
StaticTestClass.GoStaticMethod();
}
}
class StaticTestClass
{
public static GoStaticMethod()
{
// Here I want to fire Event1 in the nonStaticDLLCLASS
// I know the following line is not correct but can I do something like that?
(nonStaticDLLCLASS)StaticTestClass.ObjectThatCalledMe.Event1();
}
}
I know you typically have to create an instance of the non-static class in order to access it's methods but in this case an instance has already been created, just not by the class that is trying to access it.
No, instance members can only be invoked/accessed on a valid instance of the type.
In order for this to work you must pass an instance of nonStaticDLLCLASS to StaticTestClass.GoStaticMethod and use that instance reference to invoke/access the non-static members.
In your example above how do you specify which instance of the type you are accessing? The static method has no knowdlege of any instance so how does it know which one to use or if there are any loaded in memory at all?
Consider this example:
using System;
class Dog
{
public String Name { get; set; }
}
class Example
{
static void Main()
{
Dog rex = new Dog { Name="Rex" };
Dog fluffy = new Dog { Name="Fluffy" };
}
static void sayHiToDog()
{
// In this static method how can I specify which dog instance
// I mean to access without a valid instance? It is impossible since
// the static method knows nothing about the instances that have been
// created in the static method above.
}
static void sayHiToDog(Dog dog)
{
// Now this method would work since I now have an instance of the
// Dog type that I can say hi to.
Console.WriteLine("Hello, " + dog.Name);
}
}
Instance methods can only be called on instances. In your example, the instance is calling the static method. Can you give the static method a parameter allowing the instance to pass in a reference to itself? Something like this:
class nonStaticDLLCLASS
{
public event Event1;
public CallStaticMethod()
{
StaticTestClass.GoStaticMethod(this);
}
}
class StaticTestClass
{
public static GoStaticMethod(nonStaticDLLCLASS instance)
{
// Here I want to fire Event1 in the nonStaticDLLCLASS
// I know the following line is not correct but can I do something like that?
instance.Event1();
}
}
I think you need to clarify your question to specify why you can't do something like this, or why the instance can't raise its own event.
I have an application in C# .NET which has a MainForm and a few classes.
One of these classes receives incoming data messages from a network. I need to get these message's text appended into a multi-line textbox on the MainForm.
I can send the message to a method in the MainForm by making the method static, but then the static method cannot access the MainForm's controls.
TheIncomingDataClass.cs
namespace TheApplicationName
{
class TheIncomingDataClass
{
public void IncomingMessage(IncomingMessageType message)
{
TheApplicationName.MainForm.ReceiveMSG(message);
}
MainForm.cs
public static void ReceiveMSG(string message)
{
txtDisplayMessages.AppendText(message); //This line causes compile error
}
The compile error:
An object reference is required for the nonstatic field, method, or
property 'TheApplicationName.MainForm.txtDisplayMessages'
A static method doesn't have access to members like txtDisplayMessages because it is not a part of that instance. I suggest you do some reading on the concepts of static methods and whatnot, because that is a fairly language agnostic concept. That method would best be served by removing the static modifier, because it doesn't need to be static - it appears that it would need to be called by that particular instance of that object.
To continue the way you've been doing it, your "TheIncomingDataClass" should have a reference to the MainForm object with which it should interface. When you create an instance of this class (presumably from an instance method of MainForm), you will need to pass in a reference to this MainForm object.
class TheIncomingDataClass{
MainForm form;
public TheIncomingDataClass(MainForm form){
this.form = form;
}
}
class MainForm : Form{
MainForm(){
new TheIncomingDataClass(this);
}
}
However, as suggested by Bugs, you probably would be better off making this an event on TheIncomingDataClass and subscribing to it from MainForm.
class IncomingMessageEventArgs : EventArgs{
IncomingMessageType message;
public IncomingMessageType Message{get{return message;}}
public IncomingMessageEventArgs(IncomingMessageType message){
this.message = message;
}
}
class TheIncomingDataClass{
public event EventHandler<IncomingMessageEventArgs> MessageReceived;
protected virtual void OnMessageReceived(IncomingMessageEventArgs e){
if(MessageReceived != null)
MessageReceived(this, e);
}
public void IncomingMessage(IncomingMessageType message){
OnMessageReceived(new IncomingMessageEventArgs(message));
}
}
class MainForm : Form{
MainForm(){
new TheIncomingDataClass().MessageReceived +=
(s, e)=>txtDisplayMessages.AppendText(e.Message.ToString());
}
}
Its possible to pass in a reference to the current form like this:
public static void ReceiveMSG(string message, MainForm mainform)
{
mainform.txtDisplayMessages.AppendText(message);
}
Although as suggested an event is probably a better way of doing it.
raise an event from class which the form can subscribe to.
Just remove the static modifier, you don't need it for your purposes. Read about statics here.
You can solve this problem by removing the static keyword.
When you see "static", think: without an instance of this type.
When you call a non-static method, you must explicitly use some instance. The method can access that instance using the "this" keyword.
When you call a static method, there is no instance - you have abandoned the boundaries of OO and are now in a structural or functional programming context. If you want an instance of something, you need to bring it in as a parameter.
I think you might be taking the wrong approach on this. It sounds like you are trying to push messages to a client from an external process. There are ways to do this, but it will get complicated. My suggestion would be to have the client poll whatever process has the data periodically - maybe every 10 seconds depending on your needs. This is going to be a heck of a lot easier than pushing from server to client.
Ok here goes.
Static methods can access only static members. Your ReceiveMSG method is static. txtDisplayMessages is not and hence you cant access it.
Why does your method need to be static? Needless to say, if you remove the static keyword that will fix your problem.
Just make ReceiveMSG part of a class, create an instance of the class and then call the method on the instance.
I think you should post the kind the solution you are expecting.
Seeing as you are new to C# I will keep this as simple as possible. You should have a Program.cs file that has a single method Main (this would have been generated by Visual Studio). You will need to make it look like the following:
class Program
{
public static readonly MainForm MainForm;
static void Main()
{
Application.EnableVisualStyles();
MainForm = new MainForm(); // These two lines
Application.Run(MainForm); // are the important ones.
}
}
Now in your incoming message you will have a way to access that form.
public void IncomingMessage(IncomingMessageType message)
{
Program.MainForm.RecieveMSG(message);
}
That method in the form would then be a instance (not static) method. E.g.
public void RecieveMSG(IncomingMessageType message) // NB: No static
{
txtDisplayMessages.Text = message.Text; // Or whatever.
}
There are better ways to do it - but as a beginner I think this would be the best approach.
The difference between static and instance (instance is when you don't say static) is huge. To get to an instance method, field or property (which are collectively called members in C#) you need to have the containing instance. So:
Person p = new Person(); // You now have an instance.
p.Name = "Fred"; // You are using an instance property.
Static are the opposite, they are the same anywhere in your application (more technically within the same AppDomain - but if you are a beginner you won't need to worry about that for a while). You don't need an instance to get to them (props to codewidgets "Static methods can access only static members"). For example:
// Where Planet is a class and People is a static property.
// Somewhat confusingly the Add method is an instance - best left for the student :).
Planet.People.Add(new Person("Fred"));
Hopefully that gives you a good indication of what static and instance is and where to use them. The most important thing though is to try and avoid static members as best as you can - they can cause maintenance nightmares.
Microsoft has a whole write-up on the important concepts in regard to this.
private void FormMain_Load(object sender, EventArgs e)
{
TheIncomingDataClass.SetupControl(textBox1);
}
public class TheIncomingDataClass
{
public static TextBox textbox = new TextBox();
public static void SetupControl(TextBox txt)
{
textbox = txt;
}
public void IncomingMessage(string message)
{
textbox.Text = message;
}
}
How can I make a textbox in my winforms application that accepts new lines of text from anywhere in the application?
I have a main form that contains a textbox. I'd like to directly add text to the box from a method in another class.
Update
I tried this in my main form:
public void Output(String value)
{
if (txtOutput.Text.Length > 0)
{
txtOutput.AppendText(Environment.NewLine);
}
txtOutput.AppendText(value);
}
But I can't call Output from the other class. I'm new to C#, so perhaps I'm missing something obvious.
Regards, Miel.
PS Yes, I know this is bad design, but for now this seems to be the best way to do what I want. The textbox would function like a console.
You'll need to expose the Text property of the TextBox as a string property on your form. For example...
public string TextBoxText
{
get { return textBoxName.Text; }
set { textBoxName.Text = value; }
}
Edit
After reading the question edit, your problem is that you need a reference to a specific instance of the form whereever you're trying to execute that code. You can either pass around a reference (which is the better option), or you could use some smelly code and have a static property that refers to one instance of your form. Something like...
public partial class MyForm : Form
{
private static MyForm instance;
public static MyForm Instance
{
get { return instance; }
}
public MyForm() : base()
{
InitializeComponent();
// ....
instance = this;
}
}
Using this approach, you could call MyForm.Instance.Output("test");
In order to decouple a bit more you could inverse the control a bit:
// interface for exposing append method
public interface IAppend
{
void AppendText(string text);
}
// some class that can use the IAppend interface
public class SomeOtherClass
{
private IAppend _appendTarget = null;
public SomeOtherClass(IAppend appendTarget)
{
_appendTarget = appendTarget;
}
private void AppendText(string text)
{
if (_appendTarget != null)
{
_appendTarget.AppendText(text);
}
}
public void MethodThatWillWantToAppendText()
{
// do some stuff
this.AppendText("I will add this.");
}
}
// implementation of IAppend in the form
void IAppend.AppendText(string text)
{
textBox1.AppendText(text);
}
It looks like your design is a little bit corrupted. You shouldn't let buisness logic mess with GUI controls. Why don't you try a return value and assigning it on the interface side?
This is a REALLY bad way of doing it, but just to make sure all the answers are out there...
In the VS designer, each form control has an item in the Properties window named Modifiers that defaults to Private. Changing this to one of the others settings, such as Internal or Public, will let you access it from outside the form.
I must stress that this is the worst way to do it.