Access NSTextBox from another class - c#

I have my WinForm (Form1) and another class (Class1). Form1 has a textbox with the name of TextBox and I'm wanting to change the text inside TextBox within Class1. How can I do this? I've already checked everywhere and tried all the methods on Stackoverflow and other sources but they all seem to not be working.
EDIT:
I've tried making the TextBox public, but that didn't work.
Then I tried using the following code:
private readonly Form1 form;
public Class1(Form1 form) {
this.fom = form;
}
private void EditText() {
form.TextBox.Text = .... (TextBox seems to not be an object, even though it is)
}
Which also ended up not working.
Finally once I set the TextBox component modifiers to public inside the visual studio editor it gave me no errors until I ran the program in which it said:
Error 1 Inconsistent accessibility: field type 'NSTextBox' is less accessible than field 'OverloadBot_Panel.Form1.ConsoleTextBox' D:\Users\goff-laptop\Desktop\OverloadBotNet\OverloadBot_Panel\OverloadBot_Panel\Form1.Designer.cs 364 26 OverloadBot_Panel
I am using a Theme if that matters at all.

Basically, you need to do this the right way. Or at least a better way than exposing the control directly.
In order to keep tight encapsulation, as well as separation of concerns, you shouldn't be exposing your controls to the outside world anyways. Instead, define a method on your form class that sets the text box for you:
public void UpdateText(string text)
{
myTextBox.Text = text;
}
And in the caller:
private void DoStuff()
{
form.UpdateText("Test");
}
Now the caller doesn't need to know about the internal structure of the form. In fact, if you went through an interface instead, it wouldn't care if it was event talking to a form. The class on the other side would simply react to the "UpdateText" message in whatever way it needed to. This design is much better in addition to fixing your problem.

Related

C# How to get text from a textbox in a Form, called from a different class

Sorry if this is a simple question, I'm newish to c#. To simplify this, I have one form (this is in WinForms), let's say Form1 that has a textbox (A rich textbox that allows multiple lines). During runtime I need to be able to access that textbox and get everything the user has written and put that into a string. I can do that just fine (within the form), the problem I run into is getting that text from another class. Right now I have it set up so I have this method, within the form:
public int getWords()
{
int goals = 15;
string words = mainTextbox.Text;
int count = words.Split(' ').Length;
MessageBox.Show(count.ToString());
return count;
}
I tried to call the method from my class, let's call it Words, but the textbox text always came up as empty. It took me (a little too long) to realize that by creating a new instance of the form, I was basically resetting the textbox and that's why it came up as empty even though it wasn't.
I've looked through dozens of other questions like my own on StackOverflow but none of them really worked for me, nor did they explain how they worked. So my question is: How can I get the text from a textbox in Form1, to Class Words, during runtime. The simplest way possible, and the most dumbed-down explanation as possible, please and thank you!
Ok, let's say your mainform class is called MainForm and your other class is called OtherClass.
From MainForm:
OtherClass otherClass = new OtherClass(this); // the keyword this is MainForm
Now in OtherClass:
MainForm m_MainForm; //class level variable
public OtherClass(MainForm mainForm) //constructor
{
m_MainForm = mainForm; //Now m_MainForm is accessible from OtherClass
}
Now in MainForm, make the textbox public so it can be accessed from OtherClass.
You can call it's properties from OtherClass like:
string sTextBoxText = m_MainForm.MyTextBox.Text;

how "intercept" messagebox & modify its content, and back to normal flow?

I have a bunch of messageboxes in an existing app, both simple informations to user and also questions.
I would like to "intercept" them (for sure not the correct IT wording), change automatically its content, and then normally display it to user.
The "OK" or other standard return should be returned/forwarded to the initial messagebox.
The modification function is a kind of translation, but for the purpose of demonstration, lets say that this special function does += " AAA" to the content and += " BBB" to the top header.
Note1: while searching, I have seen several custom message boxes, but
these are additional controls, mainly for changing the button captions
or style, not to "intercept". Please correct.
Note2: fully agree that a better & cleaner MVVM structure would have avoided the
trick needed above, but this big app started some time ago, with a
very small and different aim
As far as I know this isn't possible. You cannot have a reference to a MessageBox, so you cannot access it in any way once it is open.
According to the documentation:
You cannot create a new instance of the MessageBox class. To display a message box, call the static method MessageBox.Show.
This means that you cannot do like the following:
var box = new MessageBox([stuff]);
MS deliberately made the constructor or constructors of that class private (or protected), to make you use the factory method instead (MessageBox.Show();). Note that since they are explicitly defined, just not accessible, this means that no implicit constructor is generated either.
Doing this also won't work:
var box = MessageBox.Show([stuff]);
The Show method doesn't return a reference to the open box itself, but to the DialogResult object after it closes.
As for your situation, the only ways I can think of to solve your problem would be to either go through the program and change the strings, or create a new custom control and ditch the MessageBox entirely. You may be able to find another way, however "intercepting" the MessageBox instances isn't possible.
Assuming that the code uses System.Windows.MessageBox.Show calls using text and caption arguments, you can try defining a public static MessageBox class in a common namespace of your application providing a similar Show method that updates the arguments and calls the original MessageBox.Show method, e.g.:
public static class MessageBox
{
public static void Show(string text, string caption)
{
text += "AAA";
caption += "BBB";
System.Windows.MessageBox.Show(text, caption);
}
}
Note: this will only work if you are able to rebuild the solution from source code, as it requires adding a new source code file (the custom MessageBox class), and then rebuilding the solution.

Using a class to store gamedata, best practise?

Im using Visual C# 2010 express. Im working on a game, and have come accross a small, newbie problem. Thing is, i guess we're dealing with a best practise type situation, and none of the few beginner books i have really helped with it, so i hope you guys can.
So, i have two forms, one is a splashscreen/startup form and the other is the main game window. I made a class that contains all world data, and when in the first screen user clicks on "new game", a new instance of this class is generated and populated with data.
So far so good.
The newgame button, in addition to creating the world instance, opens up the main game window. The problem is, in the main game window, when i try to use attributes of the gameworld instance, it says that it doesnt exist in this context.
So, if i get it right, the created instance only exists within the first form class... is that correct?
So if i'd like to move that whole data, should i actually serialize and save the world class instance data, and load it in the second form? Or how should i approach this.
I understand it's a very newbie question, and i could propably hack it to work, but the thing is - i really feel like i have to understand everything im doing.
Thanks in advance!
You need to create a constructor on your game form that accepts an instance of your world class and assign it to a field of the same type - the field will be accessible to the game form methods.
World world;
// constructor
public GameForm (World world)
{
this.world = world;
}
// Can now use `world` in all `GameForm` methods
Instead of constructor injection (as I have shown in my example), you can use property injection, though I like the former better (tends to ensure proper initialization - though you may want to check for a null being passed in).
If there is a reference of the world data object in the splash screen, you can assign this to a public member in the main screen, or pass it to the main screen through a constructor.
so in the splash screen
FrmMain frmMain = new FrmMain();
frmMain.WorldData = this.WorldData;
if it is an instance member of the splash screen
or maybe something like
FrmMain frmMain = new FrmMain();
frmMain.WorldData = new WorldData();
or even
FrmMain frmMain = new FrmMain(this.WorldData);
or
FrmMain frmMain = new FrmMain(new WorldData());
with the FrmMain constructor as
public FrmMain(WorldData worldData)
{
this.m_WorldData = worldData;
}
Have a look at Passing Data Between Forms
Assuming you're using just windows forms, and not XNA or similar framework, where theres no winforms.
Startup form:
void StartButton_Click(object sender, EventArgs e)
{
GameWorld gw = new GameWorld();
// Initialize gw instance here
GameForm mainForm = new GameForm(gw);
mainForm.Show();
}
And add a constructor to the game form:
public class GameForm
{
private GameWorld _gw;
public GameForm()
{
InitializeComponent();
}
public GameForm(GameWorld gw) : this()
{
_gw = gw;
}
}
At that point you can use private variable _gw in the game form.
Also, i would suggest passing the GameWorld instance through the constructor, not the property as that value is crucial for the form. Generally properties might be better suited to provide a way to adjust some behavior, and any constructor parameter can be seen as mandatory for the object to work as it should.
You can also make default constructor (the one without parameters) private.
Depending on the size of the data and if the world object class is serializable, You might think about caching it. Then each form that needs the data can just get it from the cache whenever it is needed.

What is the best practice for communicating forms?

When I need to pass some information from a form to another I usually do the following:
Form2 form = new Form2(this);
form.ShowDialog();
And inside Form2.cs, I use a constructor like:
private Form1 parent;
public Form2(Form1 form)
{
...
parent = form;
}
This way I can get a information from a textbox doing parent.textbox1.Text only if textbox1 is not a private member from Form1. Ok, a lot of time I need to get information about controls in Form1, should I make the setters and getters for each attribute of a control needed in Form2? For example: I need to know the values of Text, ReadOnly and Location. Should I make the setters and getters for each one of these attributes? Is the use of internal modifier a bad practice?
The correct way to do it is with delegates. They are really pretty simple but it takes awhile to get your head around them. Here is a great example of what I think you're looking for: http://samgaut.blogspot.com/2007/11/use-delegates-to-pass-data-between.html
Since I am not allowed to add comments to answers I'm going to add this.
The linked blog post from the accepted answer does not make sense to me (could just be my lack of thorough understanding of delegates).
If the next-in-line form frmDestination has a publicly accessible setter method (SetCustomerID(string strCustID)), then why do you need to pass that into a delegate when you can just pass customerID directly to the setter?
I noticed he mentioned that
Basically, the member variable that is set within the delegate method will be populated before the Form_Load event is executed. If you notice the delegate call is executed before the frmDestination.Show() call is made. This way, you have that variable available to execute in your Form_Load processing.
Would just calling dest.SetCustomerID(customerID) before dest.Show() not do the same thing?
Seeing as this is not a reusable framework from what I can tell, I wouldn't create wrapper properties around the control properties.
If there was something that needed to be flexible about this parent form then the proper course might be to use an interface that specifies the particular controls exist or a specific base form class.

what WPF method can I use to set some properties on a control's first display?

I need to store my app window's size/position and state when the user closes the app and set them back when the user thereafter opens the app.
I did this easily using registry keys (is this even the best way to do?), but I'm wondering where I actually should put the code to set those properties.
I need to set them when the window first "appears" I think. But I have several methods that could be used in this case, namely:
Window.Show()
Window.Activate()
Window.ApplyTemplate()
Window.Arrange()
Window.ArrangeCore()
Window.ArrangeOverride()
Window.BeginInit()
Window.EndInit()
Window.Measure()
Window.MeasureCore()
Window.MeasureOverride()
Window.OnApplyTemplate()
Window.OnInitialized()
Window.OnRender()
Window.UpdateLayout()
I'm aware that most of them just are a bad idea (UpdateLayout() will be called waaaaaaay too often for instance). Idealy I'm looking for a method that will only be called once in the window's life so that I don't have to add a flag checking if this is the method's first call.
so which one would be the best in this case? and why?
side question: I put the code to save the values in Window.Close() (I'm overriding the method in my MyWindow class), But I could as well have put it in Window.OnClosing() or Window.OnClosed(). Does this make any difference in my case?
side question (bis): I also have to save a datagrid's column order, where should I put both "saving" and "loading" code in this case?
Ok, it seems to me you are treating WPF like you would an old-school WinForms application. You no longer need to monitor form events to retrieve information from the Forms Properties. A majority of WPF Control properties are something known as a Dependency Property.
Amonst some of the clever things dependency properties introduce is Data Binding.
If you then consider writing the application with an MVVM Architecture you will quickly be able to work the following out yourself... =)
In the View*1, you can create either Dependency Properties, or standard properties and implement INotifyPropertyChanged, which hold the Size/Layout/Position/etc. Then bind the form's properties (in xaml or code) to the View's Properties. You can then implement any functionality you like for storing/retrieving the defaults and have automatic updates when the form is changed by simply adapting the Get/Set of the properties in the view.
As a quick example on the Windows' Title:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="{Binding Path=DisplayName}"
WindowStartupLocation="CenterScreen" >
<Grid>...</Grid>
</Window>
An example implementation of the view:
public class SampleView : System.ComponentModel.INotifyPropertyChanged
{
public event PropertyChangedEventHandler System.ComponentModel.INotifyPropertyChanged.PropertyChanged;
public delegate void PropertyChangedEventHandler(object sender, System.ComponentModel.PropertyChangedEventArgs e);
private string _Title;
public string Title {
get {
if (_Title == null) {
_Title = My.Settings.MainWindowTitle;
}
return _Title;
}
set {
_Title = value;
if (!(_Title == My.Settings.MainWindowTitle)) {
if (PropertyChanged != null) {
PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs("Title"));
}
My.Settings.MainWindowTitle = Title;
My.Settings.Save();
}
}
}
}
EDIT: Regarding how best to store user preferences, I wouldn't recommend the registry though, it's far from unheard of. The registry nowadays is packed full of settings that, in my opinion, the registry wasn't really designed for. Consider using application settings set to a user scope. That will handle most of the subleties of where and how the data is stored/retrieved and provide a nice type safe interface for you.
*1 I personally prefer to try and bind everything to the ViewModel and have almost totally dumb Views; though I do know there are plenty of valid cases for the Views having code. I wouldn't say the Size/Layout/etc is really a Business Logic Concern and isn't something I've concerned myself with up to now, so this should probably be handled in the View itself.
EDIT 2 - A quick example of User/Application scope settings:
Here is a quick picture of the settings I added to the project:
The following code attempts to use both the application and user scoped settings.
NB: Application Scope Settings are ReadOnly at runtime
public class SettingsExample
{
private Form1 frmMain = new Form1();
public void Main()
{
frmMain.BackColor = My.Settings.DefaultBackColour;
}
public void UserLoggedIn()
{
frmMain.BackColor = My.Settings.UserBackcolour;
}
public void UpdateUserBackcolour(System.Drawing.Color newColour)
{
My.Settings.UserBackcolour = newColour;
My.Settings.Save();
}
public void UpdateDefaultBackcolour(System.Drawing.Color newColour)
{
My.Settings.DefaultBackColour = newColour;
// Compiler Error
// This property is read only because it is an application setting
// Only user settings can be changed at runtime
}
}
First off, you forgot about
Loaded event - occurs when the element
is laid out, rendered, and ready for
interaction. (Inherited from
FrameworkElement.)
There is no one simple answer. Scenario may vary whether it'a child "dialog-like" window (then I would just set the size a line before Show() ), a new instance of the same window or a new instance of the app.
I will argue that UpdateLayout() is a bad idea. Actually, it's a very good idea. For example:
private bool m_onStart = true;
public MainWindow()
{
InitializeComponent();
this.LayoutUpdated += new EventHandler(MainWindow_LayoutUpdated);
}
void MainWindow_LayoutUpdated(object sender, EventArgs e)
{
if (m_onStart)
{
m_onStart = false;
Dispatcher.BeginInvoke(() =>
{
//Start App
}
);
}
}
Even if it's called a thousand time per second (which is very unlikely) you won't even notice it and won't hurt the performance.
All in all, you can make a helper method that saves user preference and second the reads it. Since the task is view related and using MVVM and binding is an overkill for this, set the size in Loaded event (do it when all ctors, initialization and visual tree is done).
My Choice: I finally ended up putting the code to load the values from the registry in window.Show().
the reason I did this is because of 2 things:
I store the state of the window, (minimized/maximized) and the way WPF does it, I need to first set the width/height, then the maximized state (if needed), otherwise it messes up the layout. And if I don't set the width/height first, I loose them when I de-maximize the window thereafter. So I have to do things in this order precisely: Width + height and them state. (Also, this is necessary when working with multiple screens, otherwise you loose the screen you were working on). This means that some of the methods above are impractical (the "measure" ones for instance)
adding to this, if I put my code in most of the methods above-mentioned, I'll get a bad looking effect on first display: the window will first appear with its height and width set, in the middle of the screen, and then after a small delay, the window gets maximized.
putting the code in window.Show() managed to solve those 2 issues. I might have had the same result with one or more of the other methods, but I simply got fed-up with trying different configurations and ended up using the first one that gave me entire satisfaction.

Categories

Resources