Simple Windows Forms data binding - c#

Let's say I have a String property in my form (and the form does not implement INotifyPropertyChanged). I've also created a BindingSource and set its DataSource to the form. Then I bind a textbox to the String property on my form (indirectly, using the BindingSource).
Question 1: When I change the value in the textbox at runtime, why don't I hit a breakpoint in the setter of the String property? I thought that binding the control to the String property would allow updates in this direction (GUI -> member data) to occur automatically
Question 2: How can I trigger updates in the other direction (member data -> GUI) to occur when something other than the GUI changes the String property? I don't want to implement the INotifyPropertyChanged interface and add NotifyPropertyChanged to the setter. I thought that by using the BindingSource's ResetBindings I could at least trigger this manually
public partial class Form1 : Form
{
private String m_blah;
public String Blah
{
get
{
return m_blah;
}
set
{
m_blah = value;
}
}
public Form1()
{
InitializeComponent();
textBox1.DataBindings.Add(new Binding("Text", bindingSource1, "Blah",true,DataSourceUpdateMode.OnValidation));
}
private void button1_Click(object sender, EventArgs e)
{
Blah = "Clicked!";
this.bindingSource1.ResetBindings(false); //expecting the GUI to update and say "Clicked!"
}
}

this.bindingSource1.DataSource = this;
I think you forget to assign data source.

Related

Trying to bind a combobox to an enum in C#

I have a class that contains a property that is an enum:
public RaTypes RaBucket1Type { get; set; }
My enum is:
public enum RaTypes
{
Red,
Yellow
}
I was able to bind a form's combobox data-source to the enum so that when I click on the drop-down, I see the enumerations:
cmbBucket1Type.DataSource = Enum.GetValues(typeof(RaTypes));
When I load the form, I would like to populate the combo-box with the existing value. I have tried the following:
cmbBucket1Type.DisplayMember = "TradeType";
cmbBucket1Type.ValueMember = "TradeEnumID";
cmbBucket1Type.SelectedValue = EditedAlgorithm.RaBucket1Type;
But this did not work.
Also, I'm not sure I have implemented the ValueChanged event handler correctly either:
EditedAlgorithm.RaBucket1Type = (RaTypes)((ComboBox)sender).SelectedItem;
Can someone help me understand:
How to set the combobox to current value, and
How to handle the event handler so I can set the property to whatever was selected?
Thanks
-Ed
UPDATES
I have tried
cmbBucket1Type.SelectedIndex = cmbBucket1Type.FindString(EditedAlgorithm.RaBucket1Type.ToString());
and
cmbBucket1Type.SelectedItem = EditedAlgorithm.RaBucket1Type;
Neither works.
I think you're using the terminology a little differently than normal, which makes it difficult to understand.
Normally, the terms Add, Populate, and Select are used to mean the following:
Add - Add an item to the existing set of items in the combo box.
Populate - Initialize the combo box with a set of items.
Select (Display) - Choose one among many items in the combo box as the selected item. Normally this item will be displayed in the combo box visible area.
Having cleared that up, I assume following is what you want to do.
Initially populate the ComboBox with a set of values. In your case, values of RaType Enum.
Create an instance of your class which contains the property mentioned. Since you didn't name that class I'll simply name it SomeClass.
Initialize the RaBucket1Type property of the said class instance with an enum value of your choice. I'll initialize it to Yellow.
Have the ComboBox select the said value at start up.
After Form_Load, at any given time, if the user changes the value of the ComboBox, have the change reflected in your class instance property.
For that, I would do something like this:
public partial class MainForm : Form
{
// Your class instance.
private SomeClass InstanceOfSomeClass = null;
public MainForm()
{
InitializeComponent();
// Initialize the RaBucket1Type property with Yellow.
InstanceOfSomeClass = new SomeClass(RaTypes.Yellow);
// Populating the ComboBox
comboBox1.DataSource = Enum.GetValues(typeof(RaTypes));
}
// At selected index changed event
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
// Get the selected value.
var selected = comboBox1.SelectedValue;
// Change the `RaBucket1Type` value of the class instance according to the user choice.
InstanceOfSomeClass.RaBucket1Type = (RaTypes)selected;
}
private void MainForm_Load(object sender, EventArgs e)
{
// At form load time, set the `SelectedItem` of the `ComboBox` to the value of `RaBucket1Type` of your class instance.
// Since we initialized it to `Yellow`, the `ComboBox` will show `Yellow` as the selected item at load time.
if (InstanceOfSomeClass != null)
{
comboBox1.SelectedItem = InstanceOfSomeClass.RaBucket1Type;
}
}
}
public enum RaTypes
{
Red,
Yellow
}
public class SomeClass
{
public RaTypes RaBucket1Type { get; set; }
public SomeClass(RaTypes raTypes) { RaBucket1Type = raTypes; }
}
Please do keep in mind this is a basic example to show you how to handle the situation and not a complete finished code. You'll need to do a bunch of error checks to make sure class instances and selected items are not null etc.
I FOUND MY ANSWER:
I had the SelectedIndexChanged event pointing to my event handler which means that when I "added" items to the ComboBox using:
comboBox1.DataSource = Enum.GetValues(typeof(RaTypes));
it was triggering the event handler, and resetting my class property. My event handler was this:
var selectedValue = cmbBucket1Type.SelectedValue;
So the simple solution was to:
Remove the hard-coded event handler from the Visual Studio GUI.
Add the following event handler in code AFTER I assign the DataSource
bucketType1.SelectedIndexChanged += BucketTypeChanged;
This worked.
THANK YOU ALL FOR HELPING!!
-Ed
You can set the selectedValue like this:
cmbBucket1Type.SelectedValue = EditedAlgorithm.RaBucket1Type;
And you can handle the selected value when the combo change like this:
private void cmbBucket1Type_SelectedValueChanged(object sender, EventArgs e)
{
var selectedValue = cmbBucket1Type.SelectedValue;
}

Two-Way databinding dynamic object on winform controls

I want to databind a Dynamic object to a control in a winform app. So far I got it somewhat working, it does seems to databind "the first time", but then when I change the property value it does not take effect on the binded control, and that's the problem I can't overcome.
Here is the code, if you create a new winform app with a textbox and a button you can test it:
public partial class Form1 : Form
{
public dynamic ViewData { get; set; }
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
this.ViewData = new ExpandoObject();
this.ViewData.Test = "test1";
var bind = new Binding("Text", this.ViewData, null);
bind.Format += (o, c) => c.Value = this.ViewData.Test;
bind.Parse += (o, c) => this.ViewData.Test = c.Value;
textBox1.DataBindings.Add(bind);
this.ViewData.Test = "test2";
}
private void button1_Click(object sender, EventArgs e)
{
this.ViewData.Test = "test3";
}
}
For the record, if I change the control value, it'd reflected on the dynamic property, which is OK too.
For the sake of completeness, This post gave me this approach.
Simply, Binding cannot respond to your DataSource's property changes as it is not aware of the name of the property it needs to listen to, because the property name is not provided in Binding's constructor (3rd parameter) - by design.
To overcome this issue, basically, we need to listen to changes of DataSource and inform or force Binding to read value again. Fortunately, Binding class has a public method ReadValue, which forces Binding to read the value from DataSource again.
If you extend your code with the following line e.g. before binding is added to the DataBindings collection, that could solve the two-way bindings.
((INotifyPropertyChanged)this.ViewData).PropertyChanged += (sender2, e2) =>
{
if (e2.PropertyName == "Test")
{
bind.ReadValue();
}
};
At the end, all these workarounds can be encapsulated into a nice helper method to hide the details and make it reusable as much as possible.

How can we pass data from one opened form to another?

How can we pass data from one form to another opened form in winform?
In a windows application one form opens another form. When I am entering some data in parent form then that will reflect in another child form immediately.
How this will happen?
Depends how fancy you want to get.
Simplest approach is just to call methods directly.
Parent
_child = new ChildForm();
then, when you detect updates (TextChanged, SelectedIndexChanged etc.)
_child.UpdateData(someDataCollectedFromParent)
Child
public void UpdateData(MyObject data)
{
textBox1.Text = data.FirstName;
textBox2.Text = data.SecondName;
}
Other than that, you could build your message passing mechanism or look into the DataBinding infrastructure.
You can also use System.ComponentModel.INotifyPropertyChanged for MyObject.
public class MyObject : INotifyPropertyChanged
{
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private object _data1;
public object Data1
{
get{ return _data1;}
set
{
_data1=value;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Data1"));
}
}
}
then in your child form, assign a function to receive this event on account of updating new data(s), as the following code demonstrates:
myObject1.PropertyChanged += new PropertyChangedEventHandler(m_PropertyChanged);
and m_PropertyChanged:
public void m_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
// update your data here, you can cast sender to MyObject in order to access it
}
Regards,
S. Peyman Mortazavi

Accessing Form's Control from Custom Control

I want to access the list box and add the item into it for my Custom control which is dynamically created on run time. I want to add the Item when I press the button place in the custom control, but it does not work. I have use the following code to work:
private void button1_Click(object sender, EventArgs e)
{
Form1 frm = new Form1();
frm.ABC = "HI";
}
the 'ABC' is the Public string on the form ie:
public string ABC
{
set { listBox1.Items.Add (value); }
}
the above string works fine when I use it form the Button on the form and it adds the value in the lsitbox but whent I use it form the custom control's button the text of the 'value' changes but it does not add the item in list box.I have also try it on tabel but does not help. I change the Modifires of the ListBox1 from Private to Public but it does not works. The above function works well in the form but cannot work from the custom control.
Thanks.
Expose an event ("ItemAdded" or whatever) in the child form that your main form can handle. Pass the data to any event subscribers through an EventArgs derived object. Now your mainform can update the UI as it please with no tight coupling between the two classes. One class should not know about the UI layout of another, it's a bad habit to get into (one that everyone seems to suggest when this question crops up).
What I think you should use is
this.ParentForm
So in your case it should be:
public string ABC
{
set { this.ParentForm.listBox1.Items.Add (value); }
}
The easiest way would be to pass the form down into your custom control as a parameter in the constructor that way you could access it from the custom control.
EX:
public class CustomControl
{
private Form1 _form;
public CustomControl(Form1 form)
{
_form = form;
}
private void button1_Click(object sender, EventArgs e)
{
_form.ABC = "HI";
}
}

How to change text in a textbox on another form in Visual C#?

In Visual C# when I click a button, I want to load another form. But before that form loads, I want to fill the textboxes with some text. I tried to put some commands to do this before showing the form, but I get an error saying the textbox is inaccessible due to its protection level.
How can I set the textbox in a form before I show it?
private void button2_Click(object sender, EventArgs e)
{
fixgame changeCards = new fixgame();
changeCards.p1c1val.text = "3";
changeCards.Show();
}
When you create the new form in the button click event handler, you instantiate a new form object and then call its show method.
Once you have the form object you can also call any other methods or properties that are present on that class, including a property that sets the value of the textbox.
So, the code below adds a property to the Form2 class that sets your textbox (where textbox1 is the name of your textbox). I prefer this method method over making the TextBox itself visible by modifying its access modifier because it gives you better encapsulation, ensuring you have control over how the textbox is used.
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
public string TextBoxValue
{
get { return textBox1.Text;}
set { textBox1.Text = value;}
}
}
And in the button click event of the first form you can just have code like:
private void button1_Click(object sender, EventArgs e)
{
Form2 form2 = new Form2();
form2.TextBoxValue = "SomeValue";
form2.Show();
}
You can set "Modifiers" property of TextBox control to "Public"
Try this.. :)
Form1 f1 = (Form1)Application.OpenForms["Form1"];
TextBox tb = (TextBox)f1.Controls["TextBox1"];
tb.Text = "Value";
I know this was long time ago, but seems to be a pretty popular subject with many duplicate questions. Now I had a similar situation where I had a class that was called from other classes with many separate threads and I had to update one specific form from all these other threads. So creating a delegate event handler was the answer.
The solution that worked for me:
I created an event in the class I wanted to do the update on another form. (First of course I instantiated the form (called SubAsstToolTipWindow) in the class.)
Then I used this event (ToolTipShow) to create an event handler on the form I wanted to update the label on. Worked like a charm.
I used this description to devise my own code below in the class that does the update:
public static class SubAsstToolTip
{
private static SubAsstToolTipWindow ttip = new SubAsstToolTipWindow();
public delegate void ToolTipShowEventHandler();
public static event ToolTipShowEventHandler ToolTipShow;
public static void Show()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = true;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
public static void Hide()
{
// This is a static boolean that I set here but is accessible from the form.
Vars.MyToolTipIsOn = false;
if (ToolTipShow != null)
{
ToolTipShow();
}
}
}
Then the code in my form that was updated:
public partial class SubAsstToolTipWindow : Form
{
public SubAsstToolTipWindow()
{
InitializeComponent();
// Right after initializing create the event handler that
// traps the event in the class
SubAsstToolTip.ToolTipShow += SubAsstToolTip_ToolTipShow;
}
private void SubAsstToolTip_ToolTipShow()
{
if (Vars.MyToolTipIsOn) // This boolean is a static one that I set in the other class.
{
// Call other private method on the form or do whatever
ShowToolTip(Vars.MyToolTipText, Vars.MyToolTipX, Vars.MyToolTipY);
}
else
{
HideToolTip();
}
}
I hope this helps many of you still running into the same situation.
In the designer code-behind file simply change the declaration of the text box from the default:
private System.Windows.Forms.TextBox textBox1;
to:
protected System.Windows.Forms.TextBox textBox1;
The protected keyword is a member access modifier. A protected member is accessible from within the class in which it is declared, and from within any class derived from the class that declared this member (for more info, see this link).
I also had the same doubt, So I searched on internet and found a good way to pass variable values in between forms in C#, It is simple that I expected. It is nothing, but to assign a variable in the first Form and you can access that variable from any form. I have created a video tutorial on 'How to pass values to a form'
Go to the below link to see the Video Tutorial.
Passing Textbox Text to another form in Visual C#
private void button1_Click(object sender, EventArgs e)
{
Form2 frm = new Form2();
TextBox txt = (TextBox)frm.Controls.Find("p1c1val", true)[0];
txt.Text = "foo";
}

Categories

Resources