Change text of Button from another form class in C# - c#

I want to modify something in Mission Planner and I want to change button from another class/form in C# in this function :
public void CloseAllConnections()
{
myButton1.Text = "Disconnecting all";
...
}
function that is located in :
namespace MissionPlanner
{
public partial class MainV2 : Form
{
...
}
...
}
the idea is that everything works perfectly when i am focused on that menu, but sometimes i get a error
i even made a function like this
public MyButton GetMyButton1 { get { return myButton1; } }
and also created new instance
var myObject = new MainV2(true);
myObject.myButton1.Text = "Disconnecting all";
nothing works ...
i don't even know where is the function called from, because is clear that is not called from MainV2 class ...
An exception of type 'System.NullReferenceException' occurred in MissionPlanner.exe but was not handled in user code
Any ideas? Thank you.

It appears that your click event form object is called (name) myButton1, and that you are calling the following to change it: myobject.myButton1.Text = "Disconnecting all". Try using myButton1.Text = "Disconnecting all" instead.

You need to grab an instance of the form where the button resides.
Do this by saving a static reference to the form in it's constructor:
namespace MissionPlanner
{
public partial class MainV2 : Form
{
public static MainV2 CurrentForm;
public MainV2()
{
CurrentForm = this;
InitializeComponent();
}
Then somewhere else in your code:
public void CloseAllConnections()
{
MainV2.CurrentForm.myButton1.Text = "Disconnecting all";
...
}

One thing that you could try is to pass the button from the form to the class that will be modifying the button.
public class Example
{
public Button MyButton1 { get; set; }
public Example(Button myButton1)
{
MyButton1 = myButton1;
}
public void CloseAllConnections()
{
MyButton1.Text = "Disconnecting all";
}
}
This should successfully set the button's text on MainV2.

Are you using any sort of multi-threading in your app? if so:
Make sure you either only change the button from the same thread it was created by,
or simply use the ControlInstance.Invoke() method to delegate the change.

Related

Call method in Form 1 to set text from user control

I found similar questions to this, but none of the answers solved my question - or perhaps I didn't understand the answers given to implement directly to my scenario.
I have started to learn Windows Forms and my question seems pretty basic.
I have a text box myTextBox in Form1 and created a method in Form1.cs to set the text.
public void SetText(string text)
{
myTextBox.Text = text;
}
I can call this from within Form1.cs and that works fine.
However I have created a user control and within that control I have a button and when I click the button I want to be able to call that SetText method, so I did Form1.SetText("example") but this gave an error for which adding 'static' to the SetText method resolved.
However, when I add static to SetText I can then no longer set the text within that method. I get the same error I had before adding static, only this time for the text box itself:
An object reference is required for the non-static field, method, or property 'Form1.myTextBox'
I don't suggest using SetText because it will be not compitable with other programs else.
Suggested Solutions:
TextBox Property:
Add in your user control TextBox Property and then use it.
Code sample:
In UserControl.cs
public TextBox TargetTextBox { get; set; }
public void SetText(string text)
{
TargetTextBox.Text = text;
}
And use new method that are avaliable in UserControl
Event:
Add event in the user control, and if this event fired in Form1, use SetText in code there.
Sample Code:
Create file called TextEventArgs and put this code:
public class TextEventArgs : EventArgs
{
public TextEventArgs(string text)
{
Text = text;
}
public string Text { get; set; }
}
Use this code in user control
public delegate void ShowTextEventHandler(object sender, TextEventArgs e);
public event ShowTextEventHandler ShowText;
// Use this method, and this method will fire 'ShowText' event
protected override OnShowText(TextEventArgs args)
{
TextEventHandler handler = ShowText;
handler?.Invoke(this, args);
}
Variable (Not suggested):
Go in Program.cs file and put replace it with this code:
using System.Windows.Forms;
public class Program
{
internal static readonly MainForm;
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompitableTextRenderer(false);
MainForm = new Form1();
Application.Run(MainForm);
}
}
And then you can use Program.MainForm.SetText("example").

How to change progress bar and textbox from another class

I've built an installer script for some software. I'm trying to make to such that my installation script (InstallationScript.cs) and Form GUI (Install.cs) are partitioned. However, when I try to update the form components from the InstallationScript class, it cannot resolve symbol, but yet can see methods like .Show(). I thought perhaps if I exposed a public reference to itself it would be able to see the instance of the form, but that doesn't seem to work either. Am I missing something here?
namespace Generic_Installer_Framework.gui {
public partial class Install : Form {
public static Install Self;
public Install() {
Self = this;
InitializeComponent();
}
public void InstallStep(int value, string message, string logMessage = "") {
Logger.Log(logMessage == "" ? message : logMessage);
installationProgressBar.Value = value;
installationRichTextBox.AppendText(message + "\n");
}
}
}
Other class:
namespace Generic_Installer_Framework{
class InstallationScript {
private readonly Form _installerForm = Install.Self;
public void Start() {
//This works
_installerForm.Show();
//This doesn't
_installerForm.InstallStep(0, "Starting...");
}
}
}
Thank you so much!
However, when I try to update the form components from the
InstallationScript class, it cannot resolve symbol, but yet can see
methods like .Show().
The problem is right here:
private readonly Form _installerForm = Install.Self;
You've declared "_installerForm" as the generic type of Form, which of course has no idea what you're talking about...
Change the type to Install, and all should be good:
private readonly Install _installerForm = Install.Self;
My guess that it can be because you run Start() method in a different Thread. You can try to pass this method inside a delegate :
public Action<int, string, string> InsStep = new Action<int, string, string>(InstallStep);
Try to call it in your InstallationScript class by installerForm.InsStep(0, "Starting...", "");
You can also benefit from using SynchronizationContext.Current property:
First you take it from your form :
SynchronizationContext sync = SynchronizationContext.Current;
Then you pass it to another Thread or whereever you want and use like:
sync.Post(delegate
{
// your updates here will be executed thread-safe
}, null);

Passing the form between classes and acces functions in the passed form

I am accesing another file by doing this:
public void startUpdateChecking()
{
UpdateHandler process = new UpdateHandler();
process.initialize(this);
}
The same class that 'startUpdateChecking' function is in I have this example functon aswell:
public void changeText(string Text)
{
label2.Text = Text;
}
Now in the UpdateHandler class I am doing this:
public Form form;
public void initialize(Form test)
{
Thread update = new Thread(checkForUpdates);
update.Start();
form = test;
edit();
}
public void edit() {
form.changeText("test");
}
But 'form' has no clue what changeText is for some reason, how would I make it so I can use functions from another class (Form2 class) WITHOUT the need for static function?
I tried doing:
Form2 form = new Form2();
And I could control and acces things from Form2, but this makes a new form instead of controlling the current one that is active (aka nothing visible happends using this).
Thanks in advance.
One way would be to use a delegate to pass the changeText method instead of passing the whole form. This should help separate the classes and I think would improve the design.
A quick way of doing this would use an action. Instead of passing in Form to initialize pass Action<Text>
The form side code would change to
public void startUpdateChecking()
{
UpdateHandler process = new UpdateHandler();
process.initialize((s) => {changeText(s);});
}
and the UpdateHandler side code would change to
public void initialize(Action<string> outputMethod)
{
Thread update = new Thread(checkForUpdates);
update.Start();
output= outputMethod;
edit();
}
public void edit() {
output("test");
}
Try to return a value from initialize and then pass that on to ChangeText.
like this:
public void startUpdateChecking()
{
UpdateHandler process = new UpdateHandler();
string Value1 = process.initialize(this);
ChangeText(Value1);
}
Initialize should then be a string, im not sure what the form is doing there, and what it has to do with the Thread update, thats something you probably know more about
public string initialize(string test)
{
Thread update = new Thread(checkForUpdates);
update.Start();
form = test;
return test;
}
Just don't try to call a function from out a class, best way is to return from a class and then call a function

How to save the value of the variable after closing the form

In WindowsForms I have an independent class Indicators.cs and a form Food. In the class I have a variable, which I'm changing in the form.
When I open the form, changing the variable, close the form and open it again (without closing the program), then the value of the variable is old. Why so?
Form:
namespace WF
{
public partial class Computer : Form
{
Indicators indicators = new Indicators();
public Computer()
{
if (indicators.isComputerAlreadyRunning == false)
indicators.isComputerAlreadyRunning = true;
}
}
}
Indicators.cs
namespace WF
{
class Indicators
{
public Indicators()
{
this.isComputerAlreadyRunning = false;
}
public bool isComputerAlreadyRunning;
}
}
Create a method in the form class that shows the form and returns a result. This is similar to the MessageBox.Show method. In the example below the FoodForm has a method called ShowForm. This method returns a custom class called FoodFormResult that has all the results needed from the form after it closes.
public FoodFormResult ShowForm()
{
return new FoodFormResult(
ShowDialog() == DialogResult.OK,
_indicators);
}
Every time the form class is created (ex. new FoodForm()), all the existing values in the form are lost.
Many ways to do this..You can create a delegate, save to form's resources, save to external file, save to settings/Appconfig file..So on..
And another but not much recommended for security reasons option is that : You can Create an internal or public static variable in main method of the application..Then when you need set to this variable..
And when you need to call that variable :
//Your main method example
static class Program
{
internal static bool AreYouOKAY = false;
// or public static bool as your needs
static void Main ()
{
........
}
/// And in your form
Program.AreYouOKAY = true;
// After your form closed.. from another form just call as above
if(Program.AreYouOKAY)
{
MessageBox.Show (" Yeah! I'm Ok!");
}

not able to set the visible property of button in one form from another form

I need to interact with controls on other forms. Trying to access the controls by using, for example, the following...
i am accessing Backupform control from form2
in backupform : I have defined like this....
public partial class BackupForm
{
public bool ControlIsVisible
{
get { return this.btnrestore.Visible; }
set {this.btnrestore.Visible = value; }
}
public BackupForm()
{
InitializeComponent();
cbbackupforms.SelectedIndex = 0;
// btnrestore.Enabled = false;
}
}
i made the btnrestore properties visible = true; and modifiers = private in designer of backupform
and in form2 i am accessing the btnrestore visible property
public partial class form2
{
private Forms.BackupForm backs;
public form2()
{
InitializeComponent();
backs = new Forms.BackupForm();
}
public void restore()
{
backs.ControlIsVisible = false;
}
}
but i am not able to visible false for the button , would any one pls suggest any solution for this.....
Many thanks in advance
You can supply a reference to the instance of the first form, and use that reference to set properties of objects on that form. When you cast the object to Form1, the properties will be accesible.
When are you calling your Restore() method? Also, if all the Restore() method does is set the button's visible property on the seperate form, why not encapsaluate that method within your BackupForm object and call it using backs.Restore()?

Categories

Resources