How can I click a Button in one form and update text in a TextBox in another form?
If you're attempting to use WinForms, you can implement a custom event in your "child" form. You could have that event fire when the button in your "child" form was clicked.
Your "parent" form would then listen for the event and handle it's own TextBox update.
public class ChildForm : Form
{
public delegate SomeEventHandler(object sender, EventArgs e);
public event SomeEventHandler SomeEvent;
// Your code here
}
public class ParentForm : Form
{
ChildForm child = new ChildForm();
child.SomeEvent += new EventHandler(this.HandleSomeEvent);
public void HandleSomeEvent(object sender, EventArgs e)
{
this.someTextBox.Text = "Whatever Text You Want...";
}
}
Roughly; the one form must have a reference to some underlying object holding the text; this object should fire an event on the update of the text; the TextBox in another form should have a delegate subscribing to that event, which will discover that the underlying text has changed; once the TextBox delegate has been informed, the TextBox should query the underlying object for the new value of the text, and update the TextBox with the new text.
Assuming WinForms;
If the textbox is bound to a property of an object, you would implement the INotifyPropertyChanged interface on the object, and notify about the value of the string being changed.
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string title;
public string Title {
get { return title; }
set {
if(value != title)
{
this.title = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("Title"));
}
}
}
With the above, if you bind to the Title property - the update will go through 'automatically' to all forms/textboxes that bind to the object. I would recommend this above sending specific events, as this is the common way of notifying binding of updates to object properties.
Related
I am trying to set a ConstantLine for a DevExpress SplineChart that is created in the Form1 from Form2 and also set a numericalupdown.value placed in the Form2 for a textBox.text that is placed in the Form1, whilst both Form1 and Form2 are Open and running.
I am using from accessors {get;set;} to get and set values of DevExpressChart as i have written down in my codes.
I can get the values, but i can't set any value without using Form1.ShowDialog().
I have also used Form1.Update(); andForm1.Refresh(); but the mentioned code only run successfully with the use of Form1.Show(); or Form1.ShowDialog();
However, i want them to execute while both forms are running Form2 as a child of Form1 an seeing the changes in the Form1
Code
//Code Snippet in the Form2:
//NumericalUpDown-ValueChanged Event: In Form2
private void numUpDnShkgTimeRstcConfig_ValueChanged(object sender, EventArgs e)
{
Form1 frm1 = new Form1();
if (chkBxShakingTimeRestCteLineConfig.Checked == true)
{
XYDiagram diagram = (XYDiagram)Frm1.SplineChart.Diagram;
diagram.AxisX.ConstantLines.Add(new ConstantLine("Shaking Time", Convert.ToString(numUpDnShkgTimeRstcConfig.Value)));
Frm1.TxtBx = Convert.ToString(numUpDnShkgTimeRstcConfig.Value);
}
}
//Code Snippet in the Form1
//Pass Objects And Parameter.
public DevExpress.XtraCharts.ChartControl SplineChart
{
get {return SplineChrt1Form1; }
set { SplineChrt1MainFrm = value; }
}
public string TxtBx
{
get { return txtBxSmplWt1Form1.Text; }
set { txtBxSmplWt1Form1.Text = value; }
}
...
The way I understood your problem was that:
You are displaying a Chart in Form1.
From Form1, you want to show a second form (Form2) that allows you to change or specify values for the Chart in Form1.
You want to get the updated values from Form2 in to Form1.
The best way to setup this sort of notification and updating of a parent form from a child form is to use Events. Events enable a child form to notify its parent without actually knowing anything about the parent.
Step 1 - Create an EventArgs class. This class will be used to hold the information you want to pass from Form2 to Form1.
Generally speaking, I find it is better to have the properties as Read Only and only set them in the constructor for this sort of event.
// I wasn't sure what the parameters were called or their type,
// so I just used an int and string to demonstrate the functionality
public class ChartValuesChangedEventArgs : EventArgs
{
public ChartValuesChangedEventArgs (int value1, string value2)
{
Value1 = value1;
Value2 = value2;
}
public int Value1 { get; private set; }
public string Value2 { get; private set; }
}
Step 2 - Declare the event that will be raised from Form2. This is what will notify the Parent (Form1) that the values have changed and what the values are.
public event EventHandler<ChartValuesChangedEventArgs> ValuesChanged;
Step 3 - Raise the Event. This is where you notify the Parent that the values have changed.
For this example, I am raising the event on a Button Click. You can just as easily put the content of this function in your own numUpDnShkgTimeRstcConfig_ValueChanged function.
private void button1_Click(object sender, EventArgs e)
{
ChartValuesChangedEventArgs chartValuesChangedEventArgs = new
ChartValuesChangedEventArgs(numUpDnShkgTimeRstcConfig.Value,
txtBxSmplWt1Form1.Text);
OnValuesChanged(chartValuesChangedEventArgs);
}
protected virtual void OnValuesChanged(ChartValuesChangedEventArgs e)
{
EventHandler<ChartValuesChangedEventArgs> handler = ValuesChanged;
if (handler != null)
{
handler(this, e);
}
}
Step 4 - Handle the event. This is where you update your chart with the new/updated values from Form2
private void ShowForm2Button_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.ValuesChanged += form2_ValuesChanged;
form2.Show();
}
void form2_ValuesChanged(object sender, ChartValuesChangedEventArgs e)
{
// Update the chart values here
Debug.Print(e.Value1.ToString());
Debug.Print(e.Value2);
}
Using c# and winforms with .NET 4.5 I would like to link the Checked property of a menu item with the Visible property of a form.
Changing any of these two attribute would change the other one to keep them synchronized.
Is there an easy and elegant solution to do that ?
Something like this example with a checkbox and a button:
Wire up to the CheckedChanged event
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
var checkBox = sender as CheckBox;
button1.Visible = !checkBox.Checked;
}
Edit:
Ok, i misunderstood.
Although the solution of 'farid' is a clean solution with separation of concerns using viewmodel and model it also adds more complexity to your application.
If you don't want to use this mvvm pattern and put the logic in the code behind you can implement the INotifyPropertyChanged interface to the form that has the visible property (or add a custom event), add a new Visible property that sets the base.visible property (inherited by the Form from the Control class) and raise the PropertyChanged event. in the form that contains the menu item you can wire up to the event and perform the necessary logic to set the checked state or do some other action.
Here is an example:
Form1 code behind:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.Load += new System.EventHandler(this.Form1_Load);
}
private Form2 _frm2;
private void Form1_Load(object sender, EventArgs e)
{
_frm2 = new Form2();
_frm2.MdiParent = this;
_frm2.PropertyChanged += _frm2_PropertyChanged;
_frm2.Show();
}
void _frm2_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Visible")
{
showToolStripMenuItem.Checked = _frm2.Visible;
}
}
private void showToolStripMenuItem_CheckedChanged(object sender, EventArgs e)
{
var menuItem = sender as ToolStripMenuItem;
if (_frm2 != null)
_frm2.Visible = menuItem.Checked;
}
}
Form2 code behind:
public partial class Form2 : Form, INotifyPropertyChanged
{
public Form2()
{
InitializeComponent();
}
public event PropertyChangedEventHandler PropertyChanged;
public new bool Visible
{
get
{
return base.Visible;
}
set
{
base.Visible = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
}
private void hideButton_Click(object sender, EventArgs e)
{
Visible = false;
}
}
You can use Windows Forms Data Bindings.
Every windows forms control has a DataBindings property that can be used to bind a property in given data source to one of controls properties.
You can structure your code like example below:
This example shows binding from a ViewModel object to a control property. In your specific case you can bind a ViewModel property to two control property.
public partial class StackOverflowForm : Form
{
public ViewModel Model { get; set; }
public Dictionary<string, Control> BindableControls { get; set; }
public StackOverflowForm()
{
Model = new ViewModel();
Model.PropertyChanged += Model_PropertyChanged;
BindableControls = new Dictionary<string, Control>();
Model.Visible = false;
InitializeComponent();
RegisterBinding(boundButton, "Visible", Model, "Visible");
}
void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
foreach (var item in BindableControls)
{
NotifyChange(item.Value, e.PropertyName);
}
}
private void NotifyChange(Control control, string propertyName)
{
button1.DataBindings[propertyName].ReadValue();
}
private void RegisterBinding(Control control, string controlPropertyName, ViewModel _model, string modelPropertyName)
{
control.DataBindings.Add(controlPropertyName, _model, modelPropertyName, true, DataSourceUpdateMode.OnPropertyChanged);
BindableControls[control.Name] = control;
}
private void SetPropertyButton_Click(object sender, EventArgs e)
{
Model.Visible = true;
}
}
public class ViewModel : INotifyPropertyChanged
{
private bool _IsVisible;
public bool Visible
{
get
{
return _IsVisible;
}
set
{
_IsVisible = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Visible"));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
I have defined a ViewModel object in the form that is used as binding data source for controls. (that have a Visible property)
private void RegisterBinding(Control control, string controlPropertyName, ViewModel _model, string modelPropertyName)
{
control.DataBindings.Add(controlPropertyName, _model, modelPropertyName, true, DataSourceUpdateMode.OnPropertyChanged);
BindableControls[control.Name] = control;
}
Use RegisterBinding method to register simple binding (parameters are simple enough).
'ViewModel' class implements INotifyPropertyChanged interface in System.ComponentModel. This interface adds a PropertyChanged event to call when any property in ViewModel changes.
In form's constructor I added event listener to PropertyChanged event of ViewModel in listener I forced the binding to read new value for each of controls that a binding registered for it. This portion of code refresh's the bound control and changes the visible state of button.
NOTE: In order to answer simplicity I assumed that properties in ViewModel that bound to a control's property has SAME name with destination property in form control. (Mode.Visible and boundButton.Visible). If you want to implement property name mapping for source and destination properties you can use a Dictionary or something to achieve this functionality.
My problem is more complex than you think!!
Let me explain first.
I have form say "Form1". It has one grid view that contains details of Items.
On the same form i have a button "Search". If i click on Search button another form opens say "SearchForm"
"SerchForm" has one textbox and button("Search").
Now i write the name of item in textbox of "SearchForm" and click on "Search", matching item should be shown in the grid view of "Form1".
Is it possible in windows form?? How??
Thanks in advance
If you want to know a call method in parent form, then using delegate and event.
SearchForm
: Make event and call it when 'Search' button is clicked.
// Make delegate and event
public delegate void DisplayData(string aMessage);
public event DisplayData ShowData;
private void btnSearch_Click(object sender, EventArgs e)
{
// Call event
ShowData(txtMessage.Text);
}
Form1
: Make method which you want to use and link it to event.
SearchForm searchForm = new SearchForm();
private void Form1_Load(object sender, EventArgs e)
{
// Add event
searchForm.ShowData += new SearchForm.DisplayData(Search);
}
private void Search(string aMessage)
{
// Input gridview add code here
}
Use a property in the SearchForm and retrieve it from the Form1
SearchForm :
public int GetSelectedItem { get; set; }
set the value of this property after you click the search button in SearchForm
Form1:
SearchForm searchForm = new SearchForm();
searchForm.ShowDialog();
int _selectedItem = searchForm.GetSelectedItem;
I have a User control with a list box.
This User control located on my window.
how can I detect and get selected item from list box in user control?
I previously tried this but when i select an item from list box e.OriginalSource return TextBlock type.
private void searchdialog_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
//This return TextBlock type
var conrol= e.OriginalSource;
//I Want something like this
if (e.OriginalSource is ListBoxItem)
{
ListBoxItem Selected = e.OriginalSource as ListBoxItem;
//Do somting
}
}
Or there is any better way that I detect list box SelectionChanged in From My form?
I think the best soution would be to declare an event on your user control, that is fired whenever the SelectedValueChanged event is fired on the listbox.
public class MyUserControl : UserControl
{
public event EventHandler MyListBoxSelectedValueChanged;
public object MyListBoxSelectedValue
{
get { return MyListBox.SelectedValue; }
}
public MyUserControl()
{
MyListBox.SelectedValueChanged += MyListBox_SelectedValueChanged;
}
private void MyListBox_SelectedValueChanged(object sender, EventArgs eventArgs)
{
EventHandler handler = MyListBoxSelectedValueChanged;
if(handler != null)
handler(sender, eventArgs);
}
}
In your window, you listen to the event and use the exposed property in the user control.
public class MyForm : Form
{
public MyForm()
{
MyUserControl.MyListBoxSelectedValueChanged += MyUserControl_MyListBoxSelectedValueChanged;
}
private void MyUserControl_MyListBoxSelectedValueChanged(object sender, EventArgs eventArgs)
{
object selected = MyUserControl.MyListBoxSelectedValue;
}
}
there are a few ways to handle this:
Implement the SelectionChanged event in your usercontrol, and raise a custom event that you handle in your window:
//in your usercontrol
private void OnListBoxSelectionChanged(object s, EventArgs e){
if (e.AddedItems != null && e.AddedItems.Any() && NewItemSelectedEvent != null){
NewItemsSelectedEvent(this, new CustomEventArgs(e.AddedItems[0]))
}
}
//in your window
myUserControl.NewItemsSelected += (s,e) => HandleOnNewItemSelected();
If you use binding or any form of MVVM, you can use a DependencyProperty to bind the selected item to an object in your viewmodel
//in your usercontrol:
public static readonly DependencyProperty CurrentItemProperty =
DependencyProperty.Register("CurrentItem", typeof(MyListBoxItemObject),
typeof(MyUserControl), new PropertyMetadata(default(MyListBoxItemObject)));
public LiveTextBox CurrentItem
{
get { return (MyListBoxItemObject)GetValue(CurrentItemProperty ); }
set { SetValue(CurrentItemProperty , value); }
}
//in your window xaml
<MyUserControl CurrentItem={Binding MyCurrentItem} ... />
I have a form1.cs and in that form I have a panel1, in the load event of the form1.cs I am adding a control to the panel1. Now my issue is, I have a control called Numbers.cs, I need to add another control to that panel1 but from this control in a button event. How can I do this?
public partial class Number : UserControl
{
public Number()
{
InitializeComponent();
}
private void btnAcceptWelcome_Click(object sender, EventArgs e)
{
//HERE I NEED TO PASS A CONTROL TO THE PANEL1 IN FORM1.CS
//NOT SURE HOW TO DO THIS.
}
}
MORE INFO
So basically I have a folder called UserControls and in that folder I have
Numbers.cs
Letters.cs
Welcome.cs
All of them user controls, then i have a form
Form1.cs
Form1.cs instantiates Welcome and it is added to a Panel1 on the Form1.cs on form load. Then Welcome.cs has a button, when I click this button I need to swap to Numbers.cs. But I dont know how to do this from Welcome.cs
Another way would be to use a Custom Event raised by Numbers and handled by Form1 to pass the control and add it to your Panel's Control Collection.
This is an example of an Custom Event added to UserControl1
Form1
public partial class Form1 : Form
{
UserControl2 mySecondControl = new UserControl2();
public Form1()
{
InitializeComponent();
userControl11.AddControl+=new EventHandler(SwapControls);
}
private void SwapControls(object sender, EventArgs e)
{
panel1.Controls.Remove(userControl11);
userControl11.AddControl -= new EventHandler(SwapControls);
panel1.Controls.Add(mySecondControl);
}
}
UserControl
public partial class UserControl1 : UserControl
{
public event EventHandler AddControl;
public UserControl1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
this.AddControl(this, new EventArgs());
}
}
Note:
Untested code
Assuming Form1 has (or can get) a reference to Number
Add an event handler to Number:
public partial class Number : UserControl
{
// event handler Form1 will subscribe to
public EventHandler<EventArgs> OnWelcomeAccepted = (o, e) => { };
public Number()
{
InitializeComponent();
}
private void btnAcceptWelcome_Click(object sender, EventArgs e)
{
// raise the event
OnWelcomeAccepted(sender, e);
}
}
...Form1 will have a subscription after InitializeComponent(); note the additional subscription to ControlAdded:
public partial class Form1 : Form {
public Form1()
{
InitializeComponent();
this.ControlAdded += Control_Added;
// subscribe to the event and provide the implementation
Number.OnWelcomAccepted += (o, e) => { Controls.Add(GetControl( )); }
}
private void Control_Added(object sender, System.Windows.Forms.ControlEventArgs e)
{
// process size and placement and show
}
}
No other control should be adding anything directly to Form1. Let Form1 control it's children.
One way is to have a reference to panel1 within numbers since both of them are created within form1 you can pass one as an argument to the other's constructor.
It's not very clear from your description but you can just pass the control you want in the constructor or a property. Since in C# objects are always by reference you will be action on the same control in the Button event. You can always write your own event and have the panel register for it. A more complete code sample would be great.
I'm still a little unsure of what you're doing exactly but that's OK. I think the most flexible approach is to create your own custom event. Outside of any class create a delegate:
public delegate void WelcomeClick(object sender, EventArgs e);
Inside Welcome you need to create the event handler, it can be either static or part of the instance:
public event WelcomeClick OnClick;
Inside the Button Click event in welcome you can just call that event with the same parameters:
if (OnClick != null)
OnClick(sender, e);