The point is to notify the user using the memo when a packet is received/sent in a TCP Client.
The old code was extra dumb,I used a Timer that used to add text in the memo since the Timer has access to the form members,lol.
The old code:
//Memo.Text += txt + "\n";
I played with it today,this is what I've done
In Form1's class
public string TextValue
{
get
{
return Memo.Text;
}
set
{
this.Memo.Text += value + "\n";
}
}
I call the code like that:
Form1 myForm = new Form1();
myForm.TextValue = "test asdasd";
The memo modifiers are private,but that's not the problem.
The problem is that no text is displayed on the memo when i call the code.
By typing this:
Form1 myForm = new Form1();
you create a new instance of your form (Form1), but instead I guess you should use existing instance which most likely has been initialized already.
One of the ways to do it:
var form = Form.ActiveForm as Form1;
if (form != null)
{
form.TextValue = "test asdasd";
}
Though this is not very good design. Try to use custom events instead.
Maybe you should consider publishing an event in your tcpclient. Then your form will be able to listen to this event and display proper information.
Assuming Memo inherits from Control and assuming you set it with the proper modifier, the problem you may be going through is that you're likely trying to set the text from a worker thread (the one that's used to run the TCP client). If that's the case, then you need to check the InvokeRequired field of your control and if true invoke a delegate that will set the text for you.
Below is a short and easy C# snippet.
private void SetTextOnMemo(string txt){
if(Memo.InvokeRequired){
Memo.Invoke(SetTextOnMemo, txt);
}
else{
Memo.Text = txt;
}
}
Related
I'm trying to pass a variable from one form to another form textbox. The 'variable' is a result of a calculation based on the user inputs.
Below is the code for the parent form(RuleInsertForm) where I'm calling the subform(Helpformula) to get the user inputs.
public partial class RuleInsertForm : Form
{
public string helpformulainputs;
}
private void RuleInsertForm_Load(object sender,EventArgs e)
{
if (helpformulainputs=="")
{
textBox_Inputs.Text = "";
}
else
{
textBox_Inputs.Text = helpformulainputs;
}
}
Below is the code for the subform(Helpformula) where i'm passing the result variable(formulainputs) to the parent form(RuleInsertForm).
public partial class HelpFormula : Form
{
public string formulainputs = string.Empty;
private void button_generateformula_Click(objectsender, EventArgs e)
{
using (RuleInsertForm insertform = new RuleInsertForm())
{
insertform.helpformulainputs = formulainputs;
this.Close();
insertform.Show();
}
}
}
Problem:
The values are getting passed to the text box but in the UI its not getting dispalyed.
so far I tried to push data back to parent form and then tried to display the data in the textbox where I failed.(I dont know where it went wrong suggest me if I can resolve the below one)
Now I need an alternative method to this for eg: instead of pushing the data back to parent form i need to make the variable available for all the forms trying to use the subform(formulainputs)
How can I acheive this process ? any suggestions are much appreciated.
The problem seems to be that insertForm.Show() does not block the execution of your button handler. Show opens the insertform as non-modal.
So after insertform is opened, the execution is continued in button_generateformula_Click and when you exit the using block, the insertform is disposed and therefore closed.
To solve this you may call insertForm.ShowDialog() instead.
For different ways of communicating between Forms look here or simply type communicate between forms into the SO search box.
I have the following snippet of code that allows me to pull the properties from an object in my list and assign them to variables in other forms. However, I need to be able to pull the data from my variables in the other form and use those to set the properties of the given object.
My class Account is used to populate my list accounts. On my next form AccountMenu I have a class Variables1 that contains accessible variables that are used throughout the rest of my forms to keep track of the checking balance and saving balance. When logging off from the AccountMenu, I want to be able to pass the values from Variables1 to the account that was initially used.
I know how to pass variables from one form to another, but I'm not really sure how to update the form automatically, without a button, on the original form. Thus, the solution that I see is that I have a button on my AccountMenu form that "logs" the user out, via this.close(); Additionally, I guessed that under that button, I need to have some code that assigns the variables as properties to the object. I'm just not sure how I can access the set properties of the object, since it is dynamically called with the code below.
Can someone help me figure out what I need to do? Below is some of the relevant code so that you can see how I have things set up. I am just not sure how to access "matches" from the other form in order to update that specific object properties. Thank you, anyone, who can help!
//variable that will be used to check textbox1.Text
string stringToCheck;
//array of class Account
List<Account> accounts = new List<Account>();
public MainMenu()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//set value to user's input
stringToCheck = textBox1.Text;
//set a var that only returns a value if the .Name already exists
var matches = accounts.FirstOrDefault(p => p.Name == stringToCheck);
//check through each element of the array
if (matches == null)
{
accounts.Add(new Account(stringToCheck));
textBox1.Text = "";
label3.Visible = true;
}
else if (matches != null)
{
//set variables in another form. not sure if these are working
Variables1.selectedAccount = matches.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = matches.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = matches.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
this.Hide();
acctMenu.Show();
}
}
As per my understanding I think what you required is kind of trigger on your parent form that needs to be called from your child application.
If that is what you required than you can go with defining an event on your AccountMenu form. and register this event from your Accounts form.
Than simply raise this event from your AccountMenu subform.
Deletegates and Events are really works like magic :)
Let me show you some code how to do this.
Code required in AccountMenu window:
public delegate void PassDataToAccounts(string result);
public event PassDataToAccounts OnPassDataToAccount;
protected override void OnClosing(System.ComponentModel.CancelEventArgs e)
{
if (OnPassDataToAccount != null)
OnPassDataToAccount("result");
base.OnClosing(e);
}
Code required in Accounts window button1_Click event where the AccountMenu will open:
//set variables in another form. not sure if these are working
Variables1.selectedAccount = matches.Name;
//is this calling the CheckBalance of the instance?
Variables1.selectedCheckBalance = matches.CheckBalance;
//same thing?
Variables1.selectedSaveBalance = matches.SaveBalance;
//switch to form
AccountMenu acctMenu = new AccountMenu();
acctMenu..OnPassDataToAccount += childwindow_OnPassDataToAccount;
this.Hide();
acctMenu.Show();
}
void childwindow_OnPassDataToAccount(string result)
{
if (result == "result")
{
// Processing required on your parent window can be caried out here
//Variables1 can be processed directly here.
}
}
I seem to be have a great deal of trouble with a simple issue. Yes I'm new to c# but I try to learn what I can without jumping to post a question. In this case I just think I'm not asking the right question.
No code samples will help here because I'm talking about the basics ( implementation ). I have not really coded anything yet, just use the visual builder to create my windows forms and menus.
The issue I'm having is when I select a menu item (call it: set paths ) I want that list view on my main form to load from the path selected when I hit ok on form2. So I did a simple find folder dialog and I have my new path stored on form2 in a text box. When I hit ok on that form2 I want my listview form1 to populate. I know how to do all of this but I can not for the life of me access form1 from form2 or vice versa.
I tried making a call back function but I get that non-static variable cannot be referenced... error because my form1 is static, so I can't create any non static methods. I looked in to EventArgs but that just seems like an over kill for such a common request.
So what is the general way to do this?
Robert's answer is correct as far as accessing members on another form. However, in general you should be storing the state of your application (call it the "model") separately from the state of your user interface (call it the "view"). This becomes very important as your application grows beyond one or two interactions. There are several philosophies or patterns about how to tie the two together (Google "model-view-controller" (MVC) and "model-view-viewmodel" (MVVM) for example), and if you really want to do this correctly I would recommend learning about those. My preference is for the MVVM approach, and you can do it fairly easily with Windows Forms even though it was designed with WPF applications in mind.
In .NET, the basic piece of code you should use to implement the connection between your viewmodel and your view is an interface called INotifyPropertyChanged. You create a class that implements this interface and sends notifications whenever a property changes, so for example for your path property you would create this class:
class ViewModel : INotifyPropertyChanged
{
private string path;
public string Path
{
get { return path; }
set {
if (value != path)
{
path = value;
NotifyPropertyChanged();
}
}
}
// This event gets triggered whenever a property changes.
public event PropertyChangedEventHandler PropertyChanged;
// This will cause the event to actually be triggered. It automatically determines the name of the property that triggered it using the [CallerMemberName] attribute - just a bit of .NET 4.5 sweetness. :)
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
It may seem like a lot of work, but now in your form1 you can create a new "ViewModel" instance, subscribe to the event, and then pass the instance to form2. form2 then simply updates the Path property on the viewmodel instance whenever the user selects a different path.
So, Form1 needs this code near the top:
private ViewModel viewmodel = new ViewModel();
And this goes in the Form1 constructor:
viewmodel.PropertyChanged += new EventHandler(OnPathChanged);
And when you create/show form2:
var form2 = new Form2(viewmodel); // Note, the viewmodel instance is being passed to the form2 constructor
form2.Show();
The form2 constructor then stores its own reference to the "viewmodel" instance, and sets the Path property whenever the path is changed by the user.
private ViewModel viewmodel;
public Form2(ViewModel viewmodel)
{
this.viewmodel = viewmodel;
... // Other stuff to set up your controls etc. goes here
}
private void PathChanged(object sender, EventArgs e) // This may be named differently in your code; it's the event handler that gets called when the path changes
{
// This will automatically notify the event handler in Form1! It's super-elegant and flexible.
this.viewmodel.Path = txtPath.Text; // Assuming you have a textbox called txtPath
}
And finally the event handler in Form1:
private void OnPathChanged(object sender, EventArgs e)
{
var newPath = viewmodel.Path; // Get the updated path back from the viewmodel
//TODO: Whatever you want to do when the path changes.
}
Here's a link to a really good MVVM intro using Windows Forms, it uses two forms like you have in your example. MVVM (Model-View-ViewModel) Pattern For Windows Form Applications, using C#
If you need to access something on another form, just hold a reference to it from your first form, like this:
form2 = new Form2();
form2.Show();
form2.WhateverYouWantToAccess
That said, if you just want to get a file path from the user, you want to use the OpenFileDialog class.
private void button1_Click(object sender, System.EventArgs e)
{
Stream myStream = null;
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.InitialDirectory = "c:\\" ;
openFileDialog1.Filter = "txt files (*.txt)|*.txt|All files (*.*)|*.*" ;
openFileDialog1.FilterIndex = 2 ;
openFileDialog1.RestoreDirectory = true ;
if(openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
if ((myStream = openFileDialog1.OpenFile()) != null)
{
using (myStream)
{
// Insert code to read the stream here.
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: Could not read file from disk. Original error: " + ex.Message);
}
}
}
I have two forms in my project, one is with button and second one is with two textboxes.
When I am clicking the first form button, I want to fill textbox in another.
code:
secondForm secondForm = new secondForm();
secondForm.MdiParent = this.MdiParent;
secondForm.fillForm("String");
if (formShown != true)
{
secondForm.Show();
formShown = true;
}
else
{
Application.OpenForms[secondForm.Name].Focus();
}
and
public void fillForm(string text)
{
if (String.IsNullOrEmpty(priceText1.Text))
{
priceText1.Text = text;
}
else
{
priceText2.Text = text;
}
}
looks simple, but when i am clicking button second time, its not detecting text in second form text box and entering data in textbox1 instead of textbox2, why?
The problem is that when you click the button a second time you're creating a second instance of the form, and then just not showing it (you're focusing the first instance instead). You should refactor the program so that you don't do that.
private secondform secondform = null;
private void Foo()
{
if(secondForm == null)
{
secondForm = new secondForm();
secondForm.MdiParent = this.MdiParent;
secondForm.Show();
}
secondForm.fillForm("String");
secondForm.Focus();
}
So a new instance is only created if we don't already have one, we fill the data every time, and then focus the form.
P.S. there's nothing wrong with focusing the form the first time, so I just left it after the end of the if. If there was something that should only happen when it's not the first time we could add an else to the if and put the code there.
P.S.S. secondForm isn't following standard naming conventions for the name of a class. Class names should start with an upper case letter, i.e. SecondForm. Among other issues, this removes the ambiguity about whether secondForm is refering to the type, or the instance of the type.
P.S.S.S. It may not be needed functionality in your case, but we may need to properly handle the case where the child form is closed and then the button is clicked again. The easiest way of handling this is to clear out the secondForm instance field when the form is closed (letting a new one be created when the button is next clicked, if that ever happens). Closures make this really easy, we just add this line right before secondForm.Show();:
secondform.FormClosed += (s, arg) => secondform = null;
When using a basic form application in C# I am having trouble accessing the variabels within it.
So with in the form class I have
public partial class pingerform : Form
{
..
..
private System.Windows.Forms.TextBox textBox2;
public string textBox2Text
{
get { return textBox2.Text; }
set { textBox2.Text = value; }
}
And then in the main application I have
Application.Run(new pingerform());
...
...
pingerform.textBox2Text.text() = str;
but I am told that there is no object reference.
Error 1
An object reference is required for the non-static field,
method, or property
'pingerform.textBox2Text.get' C:\Users\aaron.street\Documents\Visual
Studio 11\Projects\PingDrop\PingDrop\Program.cs 54 21 PingDrop
So I thought I would make the pinger form class static but it wont let me do this?
Error 1
Cannot create an instance of the static class
'PingDrop.pingerform' C:\Users\aaron.street\Documents\Visual Studio
11\Projects\PingDrop\PingDrop\Program.cs 21 29 PingDrop
How can I access the forms properties with out creating a specific instance of the form,
I have a background thread running that I want to update a text filed with in the form at regular intervals?
Cheers
Aaron
You have no choice but to create new instance and either pass it as parameter to the thread, or store it as member of your main Program class.
Example for the second option:
private static pingerform myPingerform = null;
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
myPingerform = new pingerform();
Thread thread = new Thread(new ThreadStart(UpdateTextBox));
thread.Start();
Application.Run(myPingerform);
}
private static void UpdateTextBox()
{
while (true)
{
myPingerform.textBox2.Text = DateTime.Now.Ticks.ToString();
Thread.Sleep(1000);
}
}
And don't forget to change the textbox to be public.
Note: this is simple working solution to the simple case of one background thread accessing the textbox. If you have more threads accessing it, this will break. For best practice methods that require some more work, please read this.
You cannot access properties of an instance without creating that instance, it is nonsense (or VB which is the same). And you have already created the instance which you then passed to Application.Run(). And anyway you cannot do anything with your form after Application.Run() because it returns only when app exits. If you want to do anything with the form you need to do that in some other places. And of course you cannot make the form class static because you need to create instances.
If you need to do something with a form in another thread, you need to pass the form instance to the thread when you create it. Note though that direct messing with GUI elements from non-GUI threads is a bad idea, you should use Control.BeginInvoke().
Please try this:
pingerform myForm = new pingerform();
Application.Run(myForm);
myForm.textBox2Text = "this is text";