C# Problem with Windows.Forms.NumericUpDown binding - c#

I have a NumericUpDown control, which is a part of a UserControl.
The UserControl has Value property:
[Browsable(true)]
public override double Value
{
get { return this.ControlValue; }
set
{
this.ControlValue = value;
InvokePropertyChanged(new PropertyChangedEventArgs("Value"));
}
}
I used DataBindings for the NumericUpDown:
NumericUpDown.DataBindings.Add(nameof(NumericUpDown.Value), this, nameof(UserControl.Value), false, DataSourceUpdateMode.OnPropertyChanged);
The Value property used to be Int32, but I had to change it to Double. And suddenly the binding stopped working.
I know for sure the Value property is changing, but the NumericUpDown's value doesn't.
Correction: it appears the Binding only fails to update NumericUpDown's value when the Value property is changed. Changing NumericUpDown's value DOES change the Value property.

So, the problem actually was not in the Binding or the NumericUpDown control, but rather in the "override" keyword. In this case, the binding was confused which property was changing - UserControl's Value or its base class. This was solved by using "new" instead of "override".
Still can't understand why I didn't have this problem earlier. This code is 4-5 months old and worked perfectly before I changed Value property type from Int32 to Double.

Related

How to make a DependencyProperty properly coerce a value's type for a binding

I've got an ItemsControl subclass that behaves like a Selector, but it can't be a subclass of Selector because the selected item isn't necessarily in the Items collection. So I'm stuck reimplementing a lot of Selector stuff.
My class has a SelectedValuePath property. If that property has a value, I create a binding so that when SelectedItem changes, the value of "SelectedItem." + SelectedValuePath gets assigned to SelectedValue. This works perfectly -- as long as the consumer binds my SelectedValue to a property of the same type as the value property on SelectedItem.
Here's the problem:
However, if the selected item has an int ID property that's being used as a value property, and SelectedValue is bound to a Nullable<int> SelectedID property on a view model, the binding fails to set the property on the view model except in the case where SelectedItem is null.
I've noticed that the WPF ComboBox class doesn't have this problem, so it must be solvable without requiring the consumer to provide a value converter. I've tried a CoerceValueCallback and that doesn't do anything for me. It doesn't know the target type. It has no information about the binding that's receiving the value.
What is ComboBox.SelectedValue doing that I'm not?
I'm reasonably familiar with IValueConverter and how value converters are added to bindings in XAML at the point where a control is used. I don't need help with that. I'm asking if anybody knows how any binding on ComboBox.SelectedValue converts int to int? without the consumer of the control adding a value converter to the binding.
As I should have expected, the problem wasn't where I expected. There was no type conversion issue.
It appears that the problem was internal to my class. I was updating SelectedValue with a binding.
Binding binding = new Binding("SelectedItem." + SelectedValuePath);
binding.Mode = BindingMode.OneWay;
binding.Source = this;
BindingOperations.SetBinding(this, MenuComboBox.SelectedValueProperty, binding);
This appears to have interfered with the consumer's two-way binding to SelectedValue.
I have a BindingTarget class which derives from DependencyObject. It exposes a single DependencyProperty called Value, and fires an event when Value changes. I already wrote it to forward values to the "read only" DependencyProperty SelectionBoxItem, where the setter is protected. So instead of creating a binding from "SelectedItem."+SelectedValuePath with SelectedValue as the target as above, I used a private BindingTarget instance as the target, and set SelectedValue in its ValueChanged handler. The consumer's binding now works as expected.
// The type argument to BindingTarget is the type of the property.
_selectedValueBindingTarget = new BindingTarget<Object>();
_selectedValueBindingTarget.ValueChanged += (s, e2) =>
{
SelectedValue = e2.NewValue;
};
Binding binding = new Binding("SelectedItem." + SelectedValuePath);
binding.Mode = BindingMode.OneWay;
binding.Source = this;
BindingOperations.SetBinding(_selectedValueBindingTarget,
BindingTarget<Object>.ValueProperty, binding);

Winforms derived combobox property two way binding

I created custom ComboBox control and want to bind custom property "ActiveValue" to a DataSet. I do it in the way:
cboMyComboBox.DataBindings.Add(New System.Windows.Forms.Binding("ActiveValue", Me.dstDetails, "Table.CBOVALUE", True, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged, ""))
...
Public Property ActiveValue As String
Get
Return _activeValue
End Get
Set(value As String)
If _activeValue <> value Then
_activeValue = value
Me.Text = _activeValue
End If
End Set
End Property
It retrieves value from DataSet, but it is unable to update. It doesn't matter what value I choose it simply is not updated. This property is simple text field. Tried to implement INotifyPropertyChanged on my derived ComboBox class, but it not helped. Could someone tell me where is the problem? Thanks
UPDATE:
found a bug in my class but Rex provided databinding write methods is also helpful, thanks for your time.
Not sure why as I cannot see your full implementation, but if you really want to force the databinding to write value back to object, try DataBinding.WriteValue(), so in your ComboBox class, do this at appropriate place (probably at some text changed event handler):
theDataBinding = Me.DataBindings(theIndex) ' you may find the binding by the bound field name
theDataBinding.WriteValue()

System.Windows.Forms.Binding and empty textboxes

I have specified a System.Windows.Forms.Binding for a textbox on my form. I have set the DataSourceNullValue property of the binding to 'DBNull.Value' and the NullValue property to 'string.Empty'. The DataSourceUpdateMode is set to 'OnValidation'. Everything works fine except one thing: when the textbox is bound to a datasource which has NULL set for the field the textbox is bound to and I enter the (empty) textbox and leave it (without changing anything), the datasource is updated from NULL to an empty string.
At MSDN - Binding.NullValue Property I have found, that the NullValue property is ignored for String-datatypes.
The desired behaviour is that the value in the datasource should stay NULL if the textbox is empty. How could I achieve this?

Combobox SelectedItem does not work

I have the code below
FooCB.DisplayMember = "FooNome";
FooCB.ValueMember = "Foo";
FooCB.DataSource = FooRepository.Instance.All();
FooCB.DataBindings.Add("SelectedItem", Bar, "Foo");
but when I display the form the SelectedItem is always the first.
What am I doing wrong?
I have been struggling a little with the behaviour of Winforms comboboxes and databinding recently and these are my observations (.Net4) when binding the ComboBox.DataSource to a list of items and also binding an object property to ComboBox.SelectedItem.
When binding a list of objects (in your case List<Foo>) to ComboBox.DataSource, the first object in the list is always shown in the combobox.
If you bind an object property to ComboBox.SelectedItem (in your case Bar.Foo) and that object property matches one of the combobox list objects then that object is displayed in the combobox. If the object property is null (Bar.Foo == null) or the object property is not in the combobox list then the first object is shown in the combobox.
Setting ComboBox.SelectedItem = null or ComboBox.SelectedIndex = -1 clears the displayed item on the combobox even though this seems to warn against it. And will set your bound object property to null.
If a user clears the combobox selection when using ComboBox.DropDownStyle == DropDown (with backspace) then the bound object property is set to null.
If you have implemented INotifyPropertyChanged on the object whose property is bound to Combobox.SelectedItem (Bar.Foo) and you programatically set the bound property to a value and that value appears in the combobox list then the changed value will be displayed. If you set the property to null or a value not in the list then the combobox displayed value will not change.
So what can you do about it? The only real issue I have is having no value displayed when my bound property is null so I have just been explicitly setting Combobox.SelectedItem = null as in point #3. You may be able to extend ComboBox and override the default behaviour but so far I have been content with an extra line of code here and there combined with using default values on non-nullable properties.
Probably you are missing some decleration. If you created the Combobox from the Tool Box, -I had the similar problem- you might want to add name of the Combobox's Name as a tag on XAML.
Other than that, if you created it dynamically by code, check if you are missing any decleration for class.
I can't tell from the OP's code whether I'm answering their question, but maybe this will help somebody reading this question. The ComboBox has four ways to set the current value:
SelectedIndex
SelectedItem
SelectedText
SelectedValue
You need to be consistent about what you're setting (and about which event handler you're using). You'll get an error if you set SelectedIndex to something dumb (less than -1 or longer than the list). However, you don't get errors setting the other three to something that doesn't exist for that type of selection.
Suppose you use a Dictionary (that's pseudo code) as a binding source and set DisplayMember = "Value" and ValueMember = "Key", the mapping would look like:
SelectedIndex - -1 to index of last item
SelectedItem - KeyValuePair<Key, Value>
SelectedText - Dictionary value
SelectedValue - Dictionary key
Supplying either value or key to SelectedItem will not generate an error, it will simply act like the OP has described. And that's why I thought this answer might help somebody.
I might also note that, if you're swapping out the contents of the ComboBox, it's not always safe to use SelectedIndex. Suppose the same basic kind of data is in the ComboBox, but selections are limited in some cases compared to others. Using SelectedIndex to persist a previous selection that was still valid in the new list of options is only going work if that previous selection held the exact same place in the list. You'd almost think this was the voice of very, very recent experience speaking...

Databinding issue with custom combobox

I've created a custom read only combobox that works for the most part. However when I download data from an external source, and set up data binding there is some very odd behaviour. Please look at the code below:
cboGender.DataSource = Animal.SpecificGenders;
cboGender.DataBindings.Clear();
cboGender.DataBindings.Add("text", animal, "Gender");
((ReadOnlyComboBox)cboGender).Readonly = true;
When the above line hits, it calls this property:
public bool Readonly
{
get
{
return readOnly;
}
set
{
textBox.Text = this.Text;
ShowControl();
readOnly = value;
}
}
Now, my issue is that when I set ReadOnly to false, this works fine. The 'this.Text' in the above setter shows the value that has been bound to it. However when I set the Reaonly to true, the 'this.Text' shows an empty string. This is the only difference I make. The this.Text refers to the standard Combobox Text property.
Does anybody have any ideas?
The base ComboBox has a DropDownStyle property that can be set to DropDownList which essentially makes the ComboBox read only. Maybe you could do that instead of implementing your own ReadOnly property.
If not, I suspect your problem exists in the ShowControl() method. Even though you're first setting the textBox.Text property, something in the ShowControl() method is preventing the control from updating. And, actually, setting another property from this Property doesn't seem quite right to me.
You're already using DataBinding, so setting the Text property should already be handled elsewhere.

Categories