How to show date from MonthCalendar to TextBox C# - c#

I have two forms, on one is month, on another is TextBox.
Problem is that I don't get displayed date on the TextBox after selecting it.
To be certain that I wrote working code, I did same thing just on one form, and it works fine.
Set MonthCalendar to public and same with the TextBox where date needs to be displayed.
Here is the code for Button and for the monthcalendar:
public void mcKalendar_DateChanged()
{
frmNovoVozilo fNv = new frmNovoVozilo();
fNv.txtDatKupovine.Text =
mcKalendar.SelectionRange.Start.ToShortDateString();
}
private void btnDatum_Click(object sender, EventArgs e)
{
frmKalendar fKalen = new frmKalendar();
fKalen.StartPosition = FormStartPosition.CenterScreen;
fKalen.Show();
}
Did try also DateSelected and it's giving me the same result, nothing.
Thanks upfornt.

One method to transfer the value to the previous form, is to use form closing event handlers and get/set methods to extract the value. For example:
form1 = new Form1();
form1.FormClosing += new FormClosingEventHandler(GetDateFromForm);
private void GetDateFromForm(object sender, FormClosingEventArgs e)
{
textbox1.Text = from1.GetDate;
}
then in your month calendar form, use
string date;
public string GetDate {get {return date;} set {date = value;}}
Public Form2()
{
date = monthCalendar1.SelectionStart.ToShortDateString();
}
once you close the calendar, the selected value will be transfered.
Another method is to send a reference to the form you want to apply the changes to in the constructor of the second form.
in your primary form (the one with the button) when you create the popup form, use the syntax Form2 calendarform = new Form2(this) and write a public method that does what you need to
public void SetText(string text)
{
textbox.Text = text;
}
In your second form (the one with the month calendar) you will be able to refer to the previous method. For example:
public partial class Form2 : Form
{
Form1 _owner;
public Form2(Form1 form)
{
InitializeComponent();
_owner = form;
}
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
{
_owner.SetText(monthCalendar1.SelectionEnd.ToShortDateString());
}
Because we are referencing the previous form in the second form, you are able to call all the public methods that will run on form1. So in this case you can call the SetText() method from form2, which will change the textbox to whatever we want - in your case the selected value of the monthcalendar.
Using the DateChanged method means that it will call said method in real time as you change the date.

Related

How to retain the value from an numericupdown after closing a form

I have the following question. I am using C# .NET, and I want to save a value in numericupdown box after I close my form. In my aplication I have in total 2 forms, so I want to save the value I enter in the second one, and after I open it again I want to see the last value. In my case the numericupdown value is empty after I open the second form again.
I was thinking about something like this:
namespace Project2
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
decimal a = numericUpDown1.Value;
label2.Text = "N: " + a;
}
}
}
But is still empty after I open it again.
You can create a class which provides set/get for a NumericUpDown control in this case using the following.
public sealed class Setting
{
private static readonly Lazy<Setting> Lazy =
new Lazy<Setting>(() => new Setting());
public static Setting Instance => Lazy.Value;
public decimal NumericUpDownValue { get; set; }
}
In the child form, OnShown set Value property to Settings.NumericUpDownValue then OnClosing remember the value.
public partial class ChildForm : Form
{
public ChildForm()
{
InitializeComponent();
Shown += (sender, args) =>
numericUpDown1.DataBindings.Add("Value", Setting.Instance,
nameof(Setting.NumericUpDownValue));
Closing += (sender, args) =>
Setting.Instance.NumericUpDownValue = numericUpDown1.Value;
}
}
The code above, specifically Settings class is known as the Singleton Pattern which you can learn more about in Implementing the Singleton Pattern in C#.
You can use static variable to store last updated value and with the reference of class name you can use it where ever you want.
From MSDN: Two common uses of static fields are to keep a count of the number of
objects that have been instantiated, or to store a value that must
be shared among all instances.
Like,
namespace Project2
{
public partial class Form2 : Form
{
public static decimal lastNumericUpDownValue = 0;
public Form2()
{
//For example: thiw will print lastest saved Numeric updown value.
//For the first time, it will print 0
Console.WriteLine(Form2.lastNumericUpDownValue);
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
//Assign value to lastNumericUpDownValue variable. Look at how it is used.
Form2.lastNumericUpDownValue = numericUpDown1.Value;
}
}
}

Navigating between user controls in same form

I have a windows form that allows different user controls to show and be hidden by different button.
I would like this user controls to communicate directly with each other and change values etc.
For example usercontrol1 below
User will fill form, then when they click Proceed, usercontrol1 should close and usercontrol2 should now be visible with user information picked and displayed as follows
So far I have the code below
private void btnProceed_Click(object sender, EventArgs e)
{
string name = tbName.ToString();
string email = tbEmail.ToString();
string phone = tbPhone.ToString();
string color = tbColor.ToString();
this.Hide();
UserControl2 u2 = new UserControl2();
MainForm f1 = new MainForm();
f1.panelMain.Controls.Add(u2);
f1.listView1.Items.Add(new ListViewItem(new[]{
name,
email,
phone,
color}));
}
It does not work. Only the usercontol1 is hidden and I'm left with a blank.
What I'm I doing wrong?
(Using visual studio 13 and c# language)
You are adding the new usercontrol to a new instance of MainForm. You can't see it because this new instance is never shown. To avoid this problem in the simplest possible way you pass the instance of the current MainForm to the UserControl constructor, keep that instance stored in a global variable of the UserControl and use that instance when you need to switch the two usercontrols.
In MainForm.cs (when you create the first usercontrol)
UserControl1 uc = new UserControl1(this);
.....
In UserControl1.cs
public class UserControl1
{
MainForm _current;
public UserControl1(MainForm f)
{
InitializeComponent();
_current = f;
}
private void btnProceed_Click(object sender, EventArgs e)
{
.....
UserControl2 u2 = new UserControl2();
_current.panelMain.Controls.Add(u2);
u2.listView1.Items.Add(new ListViewItem(new[]{
name,
email,
phone,
color}));
}
}
This will be problematic to correctly handle for other tasks. I would recommend to redesign your application to let the MainForm decide which usercontrol to show when needed.
In this approach you use events to get informed in MainForm.cs when the user clicks the UserControl1, so you get this in MainForm.cs
UserControl1 uc = new UserControl1();
uc.UserClick += UserAdded;
.....
where UserAdded is a method of MainForm that received the info about the new user though the class UserInfoArgs
public void UserAdded(UserControl1 sender, UserInfoArgs args)
{
sender.Hide();
UserControl2 u2 = new UserControl2();
this.panelMain.Controls.Add(u2);
u2.listView1.Items.Add(new ListViewItem(new[]{
args.name,
args.email,
args.phone,
args.color}));
}
And in UserControl1 you add the delegate, the event and raise the event when you need to communicate to MainForm the info about your new user.
public class UserControl1
{
public delegate void onClick(UserControl1 sender, UserInfoArgs args);
public event onClick UserClick;
....
private void btnProceed_Click(object sender, EventArgs e)
{
UserInfoArgs args = new UserInfoArgs()
{
name = tbName.Text,
email = tbEmail.Text,
phone = tbPhone.Text,
color = tbColor.Text
};
if(UserClick != null)
UserClick(this, args);
}
public class UserInfoArgs
{
public string name {get;set;}
public string email {get;set;}
public string phone {get;set;}
public string color {get;set;}
}
I think using backgroundworker control for this actually works for your case .
private void btnProceed_Click(object sender, EventArgs e)
{
string name = tbName.ToString();
string email = tbEmail.ToString();
string phone = tbPhone.ToString();
string color = tbColor.ToString();
string a = " "+name+" "+email+" "+phone+" "+color;
backgroundWorker1.RunWorkAsync(a);//passing the variables to the backgroundWorker
}
And then in backgroundWorker_doWork(),you can populate the data you're getting as you like .
You are overcomplicating things. You can just layer the two controls on your UI on the same position, and set the second control's Visible property to False.
Make the first user control expose an event for the button's click (or just expose the button so you can access its Click event), so that you can detect that mouse click from the main form. Then, when the listener for that button is called; the main form can get the data out of the first control, use it to initialize the second control, and then hide the first one and show the second one.

Adding XML node on the basis of TextBox entry inside WPF Form

Suppose i have created a WPF form having one text box. i am calling that form inside another wpf window's gridpanel and after entering value inside the textbox, i am clicking on submit button. After button click, i need to get that value and save it in string form inside my current class. My logic is something like this.
For getting the from inside my current window:-
void SelectedClick(object sender, RoutedPropertyChangedEventArgs<object> e)
{
selectedItem.ContextMenu = VcontextMenu;
VcontextMenu.Items.Add(VmenuItem1);
VmenuItem1.Click += AddValidation;
details();
}
void AddValidation(object sender, RoutedEventArgs e)
{
ValidationForm obj = new ValidationForm();
ProcessGrid.Content = obj.VForm;
}
Now i want to store the value of my textbox inside a string. For that i have used following code:-
public void details()
{
ValidationForm obj = new ValidationForm();
string str = obj.s.ToString();
}
My ValidationForm Code:-
public partial class ValidationForm : UserControl
{
public string s { get; set; }
public ValidationForm()
{
InitializeComponent();
}
public void XSave_Click(object sender, RoutedEventArgs e)
{
s = TextValidationName.Text;
}
}
but instead of opening the form, the control is going to obj.s.ToString() and showing error as "Object reference not set to an instance of an object." Please help. Thanks.
The issue is caused since the string s in your ValidationForm class is not assigned. It is probably caused since the XSave_Click() method is not being called.
Ensure that you properly assign the value to s before you try to get value from it.

Different parents for new Winform with a single constructor

Im running into a bit of an issue regarding Children and parents.
I have 2 forms which have the same dropdown menus, both of which have the ability to add additional options to them. When the "(add new)" option is selected in any of the combo boxes my third form is loaded which enables the addition of a new option.
This is the code for that third window (as it stands)
public partial class taskNewDropdownEntry : Form
{
taskWindow _owner;
applianceWindow _owner2;
int windowType;
int manufacturer_id;
sqlMod data = new sqlMod();
public int setManufacturerID {get { return manufacturer_id; } set { manufacturer_id = value; } }
public taskNewDropdownEntry(taskWindow owner, int type)
{
InitializeComponent();
this._owner = owner;
this.windowType = type;
}
public taskNewDropdownEntry(applianceWindow owner, int type)
{
InitializeComponent();
this._owner2 = owner;
this.windowType = type;
}
private void taskNewDropdownEntry_Load(object sender, EventArgs e)
{
if (windowType == 1)
{
instructionLabel.Text = "Input the new appliance type below";
}
else if (windowType == 2)
{
instructionLabel.Text = "Input the new manufacturer below";
}
else if (windowType == 3)
{
instructionLabel.Text = "Input the new model below";
}
}
private void btnOK_Click(object sender, EventArgs e)
{
if (windowType == 1)
{
data.insertApplianceType(textField.Text);
_owner.refreshTypeCombo();
}
else if (windowType == 2)
{
data.insertManufacturerSimple(textField.Text);
_owner.refreshManuCombo();
}
else if (windowType == 3)
{
data.insertModelSimple(manufacturer_id, textField.Text);
_owner.refreshModelCombo();
}
this.Close();
}
private void btnCancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
Now, my issue is that the 2 forms that call this third form are different - thus my only thought of how to solve this would be to duplicate some of the code and modify the methods (you can see the second constructor already added).
Instead of having multiple constructors, and duplicated methods (in this class, or in a seperate one) is there a way whereby I can use the same constructor but different owners depending on the form that calls it?
You have too much implementation in your child form. The way I would tackle this is to
Add a property to your child form:
public string InstructionLabel { get; set; }
This allows your parent forms to individually set the label text when instantiating the form, and also set up an event handler for when the form is closing. So your parent form would have code something like
var newItemForm = new taskNewDropdownEntry();
newItemForm.InstructionLabel = "Input the new appliance type below";
newItemForm.FormClosing += new FormClosingEventHandler(ChildFormClosing);
Then somewhere early in your child form's life cycle (FormLoading event) set
instructionLabel.Text = InstructionLabel;
Then also add a property in the child form for
public string NewItem { get; set; }
your child form should set this public property in the btnOK_Click event
private void btnOK_Click(object sender, EventArgs e)
{
this.NewItem =textField.Text;
}
Then your parent form listens for a FormClosing event, and when it hits that event it takes the NewItem text, adds it to the relevant combo and refreshes it. So in the parent form, the handler looks like
private void ChildFormClosing(object sender, FormClosingEventArgs e)
{
sqlMod data = new sqlMod();
data.insertApplianceType(textField.Text);
refreshTypeCombo();
}
Pretty hard to understand the question but code speaks for all.
There are 2 options, worse (because keeping the parent reference is not a good practice first of all):
create an interface that both classes taskWindow and applianceWindow (where is the naming convention for god's sake!) implement, ex
intrerface IRefreshable {
void refreshManuCombo();
}
then constructor and your poperty can have type of IRefreshable
IRefreshable _owner;
public taskNewDropdownEntry(IRefreshable owner, int type)
{
InitializeComponent();
this._owner = owner;
}
better option, use child form events like Closed to implement refreshing logic in parent. You just need to register event handler before showing the form and voila. Check examples here:
https://msdn.microsoft.com/en-us/library/system.windows.forms.form.closed(v=vs.110).aspx
You can also implement your own public form event for more custom usage (ex. DataChanged, ResultGenerated).

Pass variable between forms when clicking button

I have two Forms. One with where all the main code is being executed. And the other form is displayed when clicking a menu item by using this method:
Form2 videoSettings = new Form2();
private void videoToolStripMenuItem_Click(object sender, EventArgs e)
{
videoSettings.Show();
}
The form which is then opened containsfields where the user gets to set some settings for the application.
Then when clicking the "save" button I want this variable: public int deviceIndex;
to be fetched from the original Form.
So I'm wondering if I can add any event or something in Form1 which detects when the save button is clicked in videoSettings (Form2)?
I would do it a different way. I'd separate the code between the UI handling and the business logic layers. So your scenario would run in such a way:
The first form issues an event notifying that the button with certain semantics has been activated. The data needed for the processing is included into the event's data.
The business logic listens to this event, and decides to issue a command on the second form. It calls an appropriate method on the form's class, passing the needed information as a parameter (and maybe preprocessing the parameter if needed).
The second form receives the command from the business logic and updates the view.
This way the problem doesn't arise at all.
Example: (I'm not the winforms expert, beware it can be totally wrong from the POV of best winforms practices.)
Part 1 (first form):
class ProcessingActivatedEventArgs : EventArgs
{
public ProcessingActivatedEventArgs(int data) { MoreData = data; }
public int MoreData { get; protected set; }
}
class Form1 : Form
{
private int currentData;
public event EventHandler<ProcessingActivatedEventArgs> ProcessingActivated;
void OnButtonClick(object sender, EventArgs args)
{
// ...
if (ProcessingActivated != null)
ProcessingActivated(new ProcessingActivatedEventArgs(currentData));
}
}
Part 2: (business logic)
class Controller
{
Form1 f1;
Form2 f2;
void StartFirstForm()
{
f1 = new Form1();
f1.ProcessingActivated += OnProcessingActivated;
f1.Show();
}
void OnProcessingActivated(object sender, ProcessingActivatedEventArgs args)
{
int data = args.MoreData;
f1.DisableProcessingRequests();
model.ProcessingFinished += OnProcessingFinished;
model.StartProcessing(data);
if (data > 0)
f2.DisplayDataProcessing(0, data);
else if (data < 0)
f2.DisplayDataProcessing(data, 0);
else
throw new SomeCoolException("impossible data");
}
}
Part 3: (second form)
class Form2 : Form
{
public void DisplayDataProcessing(int lower, int upper)
{
// ... update the UI
}
}
Note that this implementation ties the Controller and forms tighter than it could be done. In WPF, the decoupling is achieved by using the appropriate DataContext (but I don't know how to do it properly in WinForms).
Let me suggest another way, something between the simplest ShowDialog() and the elaborated way of separation between business logic and interface.
I wish to create a new event in Form2. I call this event SettingsSaved
In Form2 add as global declaration
public delegate void SettingsSavedEventHandler(object sender, SettingsSavedEventArgs e);
public event SettingsSavedEventHandler SettingsSaved;
and in the cmdSave_Click event
if(SettingsSaved != null)
{
SettingsSavedEventArgs ss = new SettingsSavedEventArgs() { DeviceIndex = deviceIndex};
SettingsSaved(this, ss);
}
the skeleton for the class SettingsSavedEventArgs
public class SettingsSavedEventArgs: EventArgs
{
public int DeviceIndex {get; set;}
// Other settings could be added here
}
now in the code calling the Form2 we can subscribe to the event and get notified when the user clicks on the Form2 Save button
Form2 videoSettings = new Form2();
videoSettings.SettingsSaved += new SettingsSavedEventHandler(SavedHandler);
videoSettings.Show();
....
private void SavedHandler(object sender, SettingsSavedEventArgs ss)
{
int deviceIndex = ss.DeviceIndex;
}
Observer Pattern
There are many suggestions, but I'd like to add my two cents.
You could use form2.ShowDialog(); which will stop the execution of your form1 thread until the form2 is closed. Which means you can just do this from form1:
Form2 videoSettings = new Form2();
//show options
videoSettings.ShowDialog();
//at this point, the user has either clicked save, cancel, or closed the form
//(because the form is closed, obviously :) )
int device = videoSettings.deviceIndex;
If you cant have it locking up your form like that, here is another way using an event in Form2:
Form2 : Form
{
public event EventHandler Saved;
OnSaveButtonClicked(...)
{
if(Saved != null) Saved(this, new EventArgs());
}
}
and then from Form1:
Form2 frm = new Form2();
frm.Saved += (s, e) =>
{
//saved button clicked, retrieve value.
//also could be handled as a method, or really any way.
};
frm.Show();
Maybe you could try to have your second form to implement INotifyPropertyChanged interface. Then when you click on Save, you Raise the PropertyChanged event, and you capture it in the first form.
You can pass information something like this
private Form1 mainForm = null;
public Form2(Form callingForm)
{
mainForm = callingForm as Form1;
InitializeComponent();
}
Then, you can access the Form1 property from Form2 like this:
//Call this in Save button click event
this.mainForm.deviceIndex;

Categories