Properties are 'reset' with two forms? - c#

I'm using MainWindow and Settings. MainWindow is the startup window from which I can open Settings. I'm trying to share some properties between both windows. Right now, I have the public properties declared in Settings:
public partial class Settings : Form
{
private string property1
public Settings()
{
InitializeComponent();
this.changeSettings();
}
public string property1
{
get { return property1; }
set { property1 = value; }
}
public void changeSettings()
{
textbox.Text = property1;
}
}
I can create an instance of Settings in MainWindow and change the properties from there:
public partial class Mainwindow : Form
{
private Settings settings;
public MainWindow()
{
InitializeComponent();
settings = new Settings();
this.changeSettings();
}
private void changeSettings()
{
settings.property1 = "value";
textbox.Text = settings.property1;
}
private void openSettings_Click(object sender, EventArgs e)
{
settings.ShowDialog();
}
}
Say, I want to change the contents of the textboxes in both forms. For MainWindow this works, i.e. I can store the value in the property and access it again. However, I open up Settings and try to change its textbox, the property is empty!
What could explain this?

You never called changeSettings() after setting the property.
You should probably get rid of that method and update the textbox directly in the setter.

The flaw is in Settings.property1, it doesn't update the text box that displays its value. A simple solution is:
public string property1
{
get { return textBox1.Text; }
set { textBox1.Text = value; }
}
You'll also need to update your MainWindow's text box after displaying the dialog:
private void openSettings_Click(object sender, EventArgs e)
{
settings.property1 = textbox.Text;
if (settings.ShowDialog() == DialogResult.OK) {
textbox.Text = settings.property1;
}
}

Related

Reload Windows Forms variables without reloading form layout

Is there a way to reload a form variables?
string a = ""
public form1()
{
InitializeComponent();
}
private void form1_load(object sender, EventArgs e)
{
a = "Something";
textbox1.Text = a;
}
Is there a way to reset the value of "a" to empty and the text displayed on the textbox? I can create a function to set the value of "a" to empty and empty the textbox but as I have many variables, I want to avoid doing that as I might miss one that will cause a bug. I was wondering if there is a way to do that.
I don't want to reinitialize the form as its kinda slow to reload the form graphics again. Thanks for any help.
I would work like this:
public struct Snapshot
{
public string a;
public int? b;
}
private Snapshot _initial;
private void form1_Load(object sender, EventArgs e)
{
_initial = this.CreateSnapshot();
}
private Snapshot CreateSnapshot()
{
return new Snapshot()
{
a = textbox1.Text,
b = int.TryParse(textbox2.Text, out int x) ? (int?)x : null
}
}
private void button1_Click(object sender, EventArgs e)
{
this.RestoreSnapshot(_initial);
}
private void RestoreSnapshot(Snapshot snapshot)
{
textbox1.Text = snapshot.a;
textbox2.Text = snapshot.b.HasValue ? snapshot.b.Value.ToString() : "";
}
Your _initial Snapshot happens at form1_Load to save where the form was at at the beginning. You then just call this.RestoreSnapshot(_initial); whenever you want to revert your values.
The advantage of this kind of approach is that it allows you to make multiple snapshots and implement an "undo" function and, because you have separated your form from your data, it makes testing easier.
Have you considered using a wrapper around your properties, with change notification? You can then use data binding to make the value and the text boxes update together. See the following:
public partial class Form1 : Form
{
public NotifyProperty<string> A { get; } = new NotifyProperty<string>();
public NotifyProperty<double> B { get; } = new NotifyProperty<double>();
public void Reset()
{
A.Value = "Something";
B.Value = 3.14d;
}
public Form1()
{
InitializeComponent();
textBox1.DataBindings.Add("Text", A, "Value", true, DataSourceUpdateMode.OnPropertyChanged);
textBox2.DataBindings.Add("Text", B, "Value", true, DataSourceUpdateMode.OnPropertyChanged);
Reset();
}
private void simpleButton1_Click(object sender, EventArgs e)
{
Reset();
}
}
public class NotifyProperty<T> : INotifyPropertyChanged
{
private T _value;
public T Value
{
get => _value;
set
{
if (_value != null && _value.Equals(value)) return;
_value = value;
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("Value"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
When Reset() is called, both the values in A and B and textBox1 and textBox2 will be updated. Also, when you are obtaining the results from the form, you can use A and B (you don't need to use the textboxes, because when the user types text, A and B will be updated automatically).
First Form
public partial class FrmCasher : XtraForm
{
public static FrmCasher instanceC;
public SimpleLabelItem num;
public FrmCasher()
{
InitializeComponent();
num = lableTableID; // We want to change lableTableID's text value
instanceC = this;
}
}
Second Form
public partial class FrmHall : DevExpress.XtraEditors.XtraForm
{
private void FrmHall_FormClosing(object sender, FormClosingEventArgs e)
{
FrmCasher.instanceC.num.Text = "Our new String value...";
}
}

How to return to the calling method after calling a windows Form in c#?

I have a method, where I call a new Windows Form in Class A. And in the new Form, I use a Dropdown menu and store the selected Item from the Dropdown in a variable, called selectedItem.Now I have to access this selectedItem in Class A. I use the following code.
public class A
{
public method callingmethod()
{
ExceptionForm expform = new ExceptionForm();
expform.Show();
string newexp = expobj.selectedexception;
}
}
And my code in New Form,
public partial class ExceptionForm : Form
{
public string selectedexception = string.Empty;
private void btnExpSubmit_Click(object sender, EventArgs e)
{
selectedexception = this.comboBox1.GetItemText(this.comboBox1.SelectedItem);
this.Close();
return;
}
}
Now After clicking on Submit button, I get the correct value in selectedItem, But I could not pass it to Class A. How to retun to Class A?
If you are ok with posting ExceptionForm over parent form by disabling it, go for ShowDialog. But, if you do not wish to disable parent for and continue popping ExceptionForm as a new and independent window, try eventing back to parent form. Here I show an example on how to do so:
public partial class ExceptionForm : Form
{
public delegate void SelectValueDelegate(string option);
public event SelectValueDelegate ValueSelected;
private void btnExpSubmit_Click(object sender, EventArgs e)
{
this.Close();
if (this.ValueSelected!= null)
{
this.ValueSelected(this.comboBox1.GetItemText(this.comboBox1.SelectedItem));
}
return;
}
}
And in calling class:
public class A
{
public method callingmethod()
{
ExceptionForm expform = new ExceptionForm();
expform.ValueSelected += ExceptionForm_ValueSelected;
expform.Show();
}
private void ExceptionForm_ValueSelected(string option)
{
string newexp = option;
// Do whatever you wanted to do next!
}
}
Use ShowDialog() method.
expform.ShowDialog();
string newexp = expobj.selectedexception;

variable and textbox mapping in c# without using textbox changed event

I'm trying a code which changes the TextBox values when variable mapped with it changes accordingly without using TextBox changed event. I am not finding any clue to where to start please help me.
Here is the code:
public void varChange(TextBox text)
{
String name;
name="sachin";
text.Text = name;
MessageBox.Show("" + text.Text);
}
You can "extend" TextBox :
public class MeTextBox : TextBox
{
public override string Text
{
get
{
return base.Text;
}
set
{
//base.Text = value; // use it or not .. whatever
MyTextWasChanged();
}
}
void MyTextWasChanged()
{
String name;
name="sachin";
//text.Text = name;
base.Text = name;
MessageBox.Show("" + text.Text);
}
}
If that's not what you're looking for then give some more details and I'll update this answer.
You can use a BindingSource
public partial class Form1 : Form
{
private System.Windows.Forms.BindingSource form1BindingSource;
public string BindedProp { get; set; } //Variable or property binded with TextBox
public Form1()
{
InitializeComponent();
this.form1BindingSource = new System.Windows.Forms.BindingSource(new System.ComponentModel.Container());
this.form1BindingSource.DataSource = typeof(binding.Form1);
this.textBox.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.form1BindingSource, "BindedProp", true));
this.form1BindingSource.DataSource = this;
}
//add a button control to assing value code event click
private void btAssingValueProperty_Click(object sender, EventArgs e)
{
BindedProp = "Value assigned";
form1BindingSource.ResetBindings(false);
}
//add a other button control to show value code event click
private void btShowValueProperty_Click(object sender, EventArgs e)
{
MessageBox.Show(BindedProp);
}
}

Object loses data after initialization

I have these objects in my project:
SchedulerList
SchedulerListItem
SchedulerListItemDetails
each one is a win forms control, which are used in forms of my application. The SchedulerList holds SchedulerListItems and each item can have SchedulerListItemDetails.
my code goes as follows:
//creating my initial list form
FrmListTesting f = new FrmListTesting();
f.Show();
The form has only one button that has a hard-coded parameter for testing purposes, as well as a SchedulerList control taht will hold the list items.
When the button is clicked the form does the following:
private void button1_Click(object sender, EventArgs e)
{
var control = this.Controls[1] as SchedulerList;
var path = #"D:\Share\Countries.txt";
var sli = new SchedulerListItem(path);
control.AddItem(sli);
}
my SchedulerListItem constuctor goes as follows:
public SchedulerListItem(string path)
{
InitializeComponent();
this.Name = Path.GetFileNameWithoutExtension(path);
this.SourcePath = path;
this.DestinationPath = GetDestinationPath(path);
}
And the AddItem method is defined as:
public void AddItem(SchedulerListItem item)
{
this.flPanel.Controls.Add(item);
}
The add item method works as intended, displays all the data that was required and displays it in the UI. The list item has a button that brings up the details form as such:
//the form constructor
public FrmSchedulerItemDetails(SchedulerListItem item)
{
InitializeComponent();
this.detailsControl = new SchedulerListItemDetails(item, this);
}
//control constructor
public SchedulerListItemDetails(SchedulerListItem item, Form owner)
{
InitializeComponent();
this.SourcePath = item.SourcePath;
this.DestinationPath = item.DestinationPath;
this.OldFormat = item.OldFormat;
this.ExportToExcel = item.ExportToExcel;
this.owner = owner;
this.underlyingItem = item;
}
And now the problem. After the SchedulerListItemDetails constructor is called and the data "gets initialized", when i look at the data inside the object its set to default values. it seams that everything that I set after InitializeComponent(); gets ignored.
things that i have tried:
hard-coding the values to see if primitives get passed correctly
settings breakpoints on every InitializeComponent() method to see the stack trace associated with setting to default values
none of the methods show any results... I know that if i use a form directly instead of using a control within a from i can set the values the way i want to, but I'm very confused as to why this other method with controls doesn't work.
EDIT 1:
the code for SchedulerListItemDetails:
public partial class SchedulerListItemDetails : UserControl
{
public SchedulerListItemDetails(SchedulerListItem item, Form owner)
{
InitializeComponent();
this.SourcePath = item.SourcePath;
this.DestinationPath = item.DestinationPath;
this.OldFormat = item.OldFormat;
this.ExportToExcel = item.ExportToExcel;
this.owner = owner;
this.underlyingItem = item;
}
public SchedulerListItemDetails()
{
InitializeComponent();
}
private Form owner = null;
private SchedulerListItem underlyingItem;
public Boolean ExportToExcel
{
get
{
return this.cbxExcel.Checked;
}
set
{
this.cbxExcel.Checked = value;
}
}
public Boolean OldFormat
{
get
{
return this.cbxOldFormat.Checked;
}
set
{
this.cbxOldFormat.Checked = value;
}
}
public String DestinationPath
{
get
{
return this.tbxDestinationPath.Text;
}
set
{
this.tbxDestinationPath.Text = value;
}
}
public String SourcePath
{
get
{
return this.tbxSourcePath.Text;
}
set
{
this.tbxSourcePath.Text = value;
}
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.owner.Close();
}
private void btnSave_Click(object sender, EventArgs e)
{
underlyingItem.SourcePath = this.SourcePath;
underlyingItem.DestinationPath = this.DestinationPath;
underlyingItem.OldFormat = this.OldFormat;
underlyingItem.ExportToExcel = this.ExportToExcel;
btnCancel_Click(sender, e);
}
}
I'll make an answer, because it should help you to solve your problem.
You have default (parameterless) constructor, which may be called and if it is called, then your constructor with parameters is not called.
Proper design would be something like
public partial class SchedulerListItemDetails : UserControl
{
public SchedulerListItemDetails()
{
InitializeComponent();
}
public SchedulerListItemDetails(SchedulerListItem item, Form owner): this()
{
this.SourcePath = item.SourcePath;
...
}
}
Notice this(), this ensure what parameterless constructor is called before (and InitializeComponent() as well, no need to duplicate it in another constructor).
Back to your problem. In your case it's like this
public partial class SchedulerListItemDetails : UserControl
{
public SchedulerListItemDetails()
{
InitializeComponent();
}
public SchedulerListItemDetails(SchedulerListItem item, Form owner)
{
InitializeComponent();
this.SourcePath = item.SourcePath;
...
}
}
Only one constructor can be called. So if you put breakpoint in parameterless one and it's triggered, then you have problems. Because you create somewhere SchedulerListItemDetails without setting it's properties (they stay default).
More likely problem is that you create new instance of that object (either before or after constructing proper, if your code ever construct such object) and that instance is what you inspect later.
So after i got a quick course of how win forms work i figured out what the problem was.
my code that i thought was enough is:
public FrmSchedulerItemDetails(SchedulerListItem item)
{
InitializeComponent();
this.DetailsControl = new SchedulerListItemDetails(item, this);
}
public SchedulerListItemDetails DetailsControl
{
get
{
return this.detailsControl;
}
set
{
this.detailsControl = value;
}
}
the this.detailsControl is the control im trying to setup, but as i have learned the correct way of replacing a component for a new one is:
public FrmSchedulerItemDetails(SchedulerListItem item)
{
InitializeComponent();
this.DetailsControl = new SchedulerListItemDetails(item, this);
}
public SchedulerListItemDetails DetailsControl
{
get
{
return this.detailsControl;
}
set
{
this.Controls.Remove(this.detailsControl);
this.detailsControl = value;
this.Controls.Add(this.detailsControl);
}
}
Feel kinda silly now :).

DataBinding in winforms : Update even though I click "Cancel"

I have a problem with DataBinding in Winforms, Even though I click "Cancel" on the form, the objecte is updated.
I've set the property "DialogResult" of the Ok button to "OK", of the Cancel button to "Cancel", also, I've set the properties "AccesptButton" and "CancelButton" of the form to bnOk and bnCancel.
Here is my code :
Model :
private string code;
public string Code
{
get { return code; }
set { SetPropertyValue<string>("Code", ref code, value); }
}
private string libelle;
public string Libelle
{
get { return libelle; }
set { SetPropertyValue<string>("Libelle", ref libelle, value); }
}
UI :
public FamilleTiers CurrentFamilleTiers { get; set; }
private void FamilleTiersForm_Load(object sender, EventArgs e)
{
txCode.DataBindings.Add("Text", CurrentFamilleTiers, "Code");
txLibelle.DataBindings.Add("Text", CurrentFamilleTiers, "Libelle");
}
Edit function :
public static void EditFamilleTiers(FamilleTiers selectedFamilleTiers)
{
using (FamilleTiersForm form = new FamilleTiersForm() { CurrentFamilleTiers = selectedFamilleTiers, Text = selectedFamilleTiers.Libelle })
{
if (form.ShowDialog() == DialogResult.OK)
{
form.CurrentFamilleTiers.Save();
}
}
}
Thanks for your time
When you click cancel on a form data binding does not revert you need to keep a backup copy of the values and if they change replace the new values with the original values. .Net does not know what your wanting to do.

Categories