here some beginners question after 2 hours of googling.
I have got a WindowsForm named GUI with an listbox item (it not have to be a listbox)
What I want to realize is having a box in the GUI an send from every classes in my project text to that box.
Example:
in Programm.cs I want simply write something like this GUI.WriteToLog("Hello World");
and it should appear in that box.
This GUI.WriteToLog should work in every class.
I tried to write a static function WriteToLog in the GUI class but if its static I cant use the listBox1 in that function.
public partial class GUI : Form
{
public void WriteToLog(string msg)
{
listBox1.Items.Add(msg);
}
}
Here the class that should access the box:
class FileManager
{
internal static void RenameFiles(string filePath)
{
GUI g = new GUI();
g.WriteToLog("Moving Files");
try {
File.Move(filePath, filePath + ".RDY");
}
catch (Exception e)
{
string message = e.ToString();
string caption = "Error";
MessageBox.Show(message, caption);
}
}
EDIT:
More Details what I want to do:
I have to access the ListBox from all of my classes, because it should inform about status. After some more google searches. I figured out that the best way to do this is to write an event ? I this right ? How du I do this ? Example what I want: GUI with the ListBox ... I'm in class "FileManager" Function "RenameFile" there I want write one line to the ListBox "Hey, I'm renaming files now" or I'm in Class "Communicator" in Function "SendEmail" so I want to add a line to the ListBox "Hey dude, I'm sending a fabilous email" ...
When you call the method RenameFiles you create a new instance of the class called GUI. So you're not using the same form.
You can fix your code by using dependency injection when creating your GUI class so that the FileManager has access without needing to create a new class.
By adding something like this to the FileManager and calling the setter on creation of your GUI.
private GUI gui;
public void SetGUI(GUI g)
{
this.gui = g;
}
A solution is use singleton pattern below an example:
public partial class GUI
{
private static GUI _instance;
public static GUI Instance
{
get { return _instance ?? (_instance = new GUI()); }
}
public void WriteToLog(string msg)
{
//[your code]...
}
}
class FileManager
{
internal static void RenameFiles(string filePath)
{
GUI.Instance.WriteToLog("Moving Files");
// [other code]...
}
}
Related
I'd like to add a WinForm into my Console App:
namespace ExchangeNativeDemo.Window
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
}
}
}
I would like to pass textbox1 value to Program.cs, like:
var emailaddress = textbox1.value
In program.cs:
using ExchangeNativeDemo.Window;
namespace ExchangeNativeDemo
{
class Program
{
static void Main(string[] args)
{
But I got the error:
is inaccessible due to its protection level
What I missed?
When you add a TextBox (or other control) to a WinForm using Visual Studio, the control is defaulted to protected scope, meaning that the only code that can access it is the code in the WinForm itself or classes that derive from it.
There are two common options:
Just change the TextBox from protected to public. This breaks encapsulation a bit so this isn't my favorite.
Write a custom property that exposes the textbox's Text property, e.g.
class Form1
{
//.....Other stuff....
public string Text1Value
{
get { return this.textbox1.Text; }
}
}
Since you know that it is supposed to be the email address, and you want to at least try to be a little encapsulated, you might actually want to name it EmailAddressEntered or something similar.
public string EmailAddressEntered
{
get { return this.textbox1.Text; }
}
Then in your main program, create an instance of the form, display it, then read the property.
void Main()
{
//....do other stuff....
var form = new Form1();
form.ShowDialog();
var emailaddress = form.EmailAddressEntered;
}
Also note, a TextBox does not have a Value. The contents are stored in the Text property instead.
Also also note, your main function should contain a call to Application.Run or you'll find that Form1 doesn't work very well.
You need to make textbox1 public,
or add property to `Form1 that will expose its value:
public string Textbox1Text
{
get { return textbox1.Text; }
}
I believe you need to declare your var as public otherwise it is automatically private. Try and let me know.
I have been looking around and found some answers with the same question as me, however i did try the code and it didn't work in my case.
I tried to do the same thing as this. My aim is to enable many different forms to use a class to do something.
Here are the part of simplified version of my class:
public class test
{
somedll g = new somedll();
somedll h = new somedll();
public void Stop(int module)
{
string command = "STOP";
if (module == 1)
{
this.WriteCommand(1, command);
}
else if (module == 2)
{
this.WriteCommand(2, command);
}
}
private void WriteCommand(int module, string command)
{
try
{
if (module == 1)
{
g.write(command + '\r');
}
else if (module == 2)
{
h.write(command + '\r');
}
}
catch (Exception)
{
if (module == 1)
{
gconnected = false;
}
else if (module == 2)
{
hconnected = false;
}
MessageBox.Show("<Write failed> Please connect.");
}
}
As my problems is i am unable to use static to make my class to be able to shared by all forms, as static is more efficient in just sharing variable/data.
edit*: I dont actually need static, i just need to make this class accessible from all other forms, without declaring new instances, i mentioned static because i did tried to used it and it cant compile.
The problem with not creating multiple instances is due to i need the data to be centralized. As declaring multiple instances cause all forms to get independent data.
edit*: My aim is to use this class that i show above with other forms without creating new instances from each forms. For example, in each form1, form2, form3 and form4, i will need to access 'stop', and then stop will in turn call 'writecommand' to finally send out the command. So, due to there is some calling in the method, static is unable to use(in my field of knowledge in c# only
Is there anyway to solve this? thanks
You can pass a single instance of your class to multiple forms (either through the constructor or via a property). However, you will probably need to make your class thread-safe by using locking.
A static instance of your non-static class would be another way for your forms to access a single instance, but this is not usually the best approach as it more tightly couples the class and the forms.
EDIT
To expand, a static instance of your non-static class Could look like this:
public class test
{
private static test singleInstance = new test();
public static test SingleInstance { get { return singleInstance; } }
somedll g = new somedll();
somedll h = new somedll();
public void Stop(int module)
{
// ...
}
private void WriteCommand(int module, string command)
{
// ...
}
}
Or it could be in another class altogether.
The other (possibly better) approach would be to create a new instance in the code that creates your forms, and to pass it to the forms' constructors, which could be edited to be something like this:
class MyForm : Form
{
private readonly test testInstance;
public MyForm(test testInstance)
{
this.testInstance = testInstance;
}
}
As I understand, you want to create an instance of your class, change it's value from one form and want the changed value of this instance to be reachable from other forms. You said you cannot use static for that, but I think you can. Have you tried using a static class like:
static class YourClass
{
private static string _yourVar= "";
public static string YourVar
{
get { return _yourVar; }
set { _yourVar = value; }
}
}
and change it like:
YourClass.YourVar = "your value"
I highly recommend reading this thread.
I've been struggling with this for a while... I have a programm written using the MVP pattern, I want to have a LogHandler class that must retrieve a string that corresponds to an ID provided in one of these methods, but it also needs to update the GUI, adding items to a listbox. So to simplyfy, imagine this:
if (name != "Peter")
{
Log.RegisterError(31, 4) //errorType, errorID
}
So in the Log class it would then get the string that matches the type and IDs provided and MessageBox it, but what if I want to add that string to a control on the form? I'm using views implemented by the forms to accomplish GUI updating, but since this is a static class I can't...
Also where should errors be checked and raised? Presenter? View? Model?
Thanks in advance
You could add callbacks in you Log class that other object could subscribe to.
Example:
In this example the Presenter can listen for an error code to be logged then receive the error string from the Log from the Model class
public class Logger
{
private static Dictionary<int, List<Action<string>>> _callbacks = new Dictionary<int,List<Action<string>>>();
public static void RegisterLoggerCallback(int errorType, Action<string> callback)
{
// Just using errortype in this exaple, but the key can be anything you want.
if (!_callbacks.ContainsKey(errorType))
{
_callbacks.Add(errorType, new List<Action<string>>());
}
_callbacks[errorType].Add(callback);
}
public static void RegisterLog(int errorType, int errorID)
{
// find error sring with codes
string error = "MyError";
// show messagebox
MessageBox.Show(error);
// tell listeners
if (_callbacks.ContainsKey(errorType))
{
_callbacks[errorType].ForEach(a => a(error));
}
}
}
public class Model
{
public Model()
{
}
public void DoSomething()
{
Logger.RegisterLog(1, 2);
}
}
public class Presenter
{
public Presenter()
{
Logger.RegisterLoggerCallback(1, AddToListbox);
}
private void AddToListbox(string error)
{
// add to listbox when errortype 1 is called somewhere
}
}
This is a very simple example but should give you an idea of a way to achive this.
I'm learning C# and what I need is to access control on a Form from other class (the same namespace).
I know there is a lot of posts on this topic here but didn't find complete solution 'for dumbs' so I write here what I figured out and please tell me - is this the correct way ?
Background: I have some 'debugging' form in my app and I need all other forms to be able to log their activity into this form. There is some ListBox control where all the logs from other forms are written. When I (or one of my tester-friends without Visual Studio) play around with app and something bad happens, I can look on that debug-form to see all detailed logs what happened just before that 'moment of error'.
My main form of the app (frmMain):
namespace myNamespace {
public partial class frmMain : Form {
private frmDebug debug; // frmDebug is declared in other class
// we will hold reference to frmDebug form in 'debug'
public frmMain() { // constructor of the main form 'frmMain'
InitializeComponent();
debug = new frmDebug(); // we create new instance of frmDebug immediately when
} // our main form is created (app started) and whole time
// of running this app we can access frmDebug from
// within frmMain through 'debug' variable
// clicking button 'btnLoggingTest', the log is written
// in the 'frmDebug' form even if it is closed (not visible)
private void btnLoggingTest_Click(object sender, EventArgs e) {
debug.Log("log this text for me please");
}
// Click handler of the button 'btnShowDebug' :
private void btnShowDebug_Click(object sender, EventArgs e) {
debug.ShowDialog(); // here we can show frmDebug (in 'modal' style)
} // just to see what log-information is written there
} // frmMain class
} // namespace
And here is the code of class frmDebug itself :
(there is only one Listbox placed on the form)
namespace myNamespace {
public partial class frmDebug : Form {
public frmDebug() {
InitializeComponent();
}
public void Log(string txt) { // this is the actual 'Log' function (or method)
this.listBox1.Items.Add(txt);
Application.DoEvents(); // if the logging takes place in some
} // computing-intensive 'loop' or function,
// (or in my case FTP login and upload process)
// 'DoEvents' ensures every log appears immediately
// after the 'Log()' was called. Otherwise all logs
// would appear together at once, as soon as the
// computing-intensive 'loop' is finished
} // class frmDebug
} // namespace
I have a strange feeling in my stomach I'm doing it all wrong so please tell me how to do it properly :) If it's OK, hope it helps somebody like me.
Thank you !
Your application has probably a class called "Program". There you will find the code
var mainForm = new frmMain();
Application.Run(frmMain);
Create a static property for the debugging form in this class
public static frmDebug DebuggingForm { get; private set; }
Change the startup code like this
DebuggingForm = new frmDebug();
var mainForm = new frmMain();
Application.Run(frmMain);
From other classes you can access this form like this
Program.DebuggingForm.Log("log this text for me please");
Program.DebuggingForm.Show();
I think you don't have to keep debugging form in memory. You can write logs to some object. E.g. static log:
public static Log
{
private static List<string> _messages = new List<string>();
public static Write(string message)
{
_messages.Add(message);
}
public static IEnumerable<string> Messages
{
get { return _messages; }
}
}
You can add log messages from every point of your application via
Log.Write("log this text for me please");
If you need to view those messages just create and show debug form:
private void btnShowDebug_Click(object sender, EventArgs e) {
using (frmDebug debug = new frmDebug())
debug.ShowDialog();
}
In debug form on load assign Log.Messages to your listbox.
A different approach would be to have an Event Sink that would act as a publish subscribe hub for your debug information, that way you don't get a dependency on the debug form all over the place, something like:
public class EventSink
{
private static readonly IList<Action<string>> _listeners = new List<Action<string>>();
public static void RegisterListener(Action<string> listener)
{
_listeners.Add(listener);
}
public static void RaiseEvent(string message)
{
foreach (var l in _listeners)
l(message);
}
}
in the constructor for your frmDebug you would do:
EventSink.RegisterListener(msg=>listBox1.Items.Add(msg));
and every time you need to add a message to the debug console you would do:
EventSink.RaiseEvent("this is a debug message");
This way you could then register new listeners to do different things, like send you an email when some specific event happens, etc. and you are not coupled with your debug form (decoupling is good:)
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.