c# - implementar - El control no actualiza inmediatamente la propiedad enlazada con INotifyPropertyChanged
inotifypropertychanged xamarin (2)
Tengo controles que no actualizan las propiedades respectivas de sus objetos enlazados hasta que se pierde el enfoque. Hay preguntas similares con respuestas aceptadas que hacen referencia a DataSourceUpdateMode.OnPropertyChange
se declara, lo que sí hago, pero el comportamiento persiste. Aquí hay una implementación de ejemplo. Intentaré ser cuidadoso, pero conciso. Se MyConfig
clase MyConfig
a través de una propiedad en una clase Singleton que llamo Configuration
.
[Serializable]
public class MyConfig : INotifyPropertyChanged
{
public enum MyEnum
{
Foo,
Bar
}
public MyConfig()
{
MyProperty = MyEnum.Foo;
}
private MyEnum _MyProperty;
public MyEnum MyProperty
{
get { return _MyProperty; }
set { if (value != _MyProperty) { _MyProperty = value; OnPropertyChanged("MyProperty"); } }
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (string.IsNullOrEmpty(propertyName))
throw new ArgumentNullException(propertyName);
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public partial class ConfigForm : Form
{
public ConfigForm()
{
InitializeComponent();
MyComboBox.Items.AddRange(Enum.GetNames(typeof(MyConfig.MyEnum)));
}
private void ConfigForm_Load(object sender, EventArgs e)
{
MyComboBox.DataSource = Enum.GetValues(typeof(MyConfig.MyEnum));
MyComboBox.DataBindings.Add("SelectedItem", Configuration.Instance.MyConfig, "MyProperty", false, DataSourceUpdateMode.OnPropertyChanged);
}
}
No estoy seguro, dada la breve implementación siguiente, lo que podría pasar por alto para garantizar cambios inmediatos de propiedad. Puedo cambiar, en este caso de Foo
a Bar
en el ComboBox, pero a menos que elimine el foco del ComboBox, nada cambia. ¿Alguien tiene alguna idea?
@Nicholas Piasecki merece crédito por guiarme hacia mi solución, así que, a menos que no pueda encontrar una solución basada en su respuesta, vote por su respuesta.
Había que hacer tres cambios principales para que esta solución funcionara en mi situación.
Estaba intentando acceder a la propiedad en el objeto vinculado a la propiedad SelectedValue de ComboBox. Por lo tanto, tuve que incluir el nombre de la propiedad "SelectedValue" en la cláusula linq where.
Si está configurando el enlace de datos a través del diseñador de formularios en Visual Studio, y simplemente establece a qué está vinculado SelectedValue o SelectedItem, el modo de actualización de la fuente de datos predeterminada es "OnValidation". Puede ver esto si va a la configuración "(Avanzada)" para el enlace de datos en el ComboBox. Por lo tanto, también debes incluir el modo de actualización de la fuente de datos si eso es lo que estás usando.
En mi caso, también tuve que provocar el evento OnSelectionChangeCommitted después de recorrer los enlaces y hacer las llamadas de Write / ReadValue. Desde que me suscribí al evento SelectionChangeCommitted del ComboBox en el formulario, al llamar a base.OnSelectionChangeCommitted antes de recorrer los enlaces y forzarlos a actualizar, la propiedad del objeto enlazado aún no estaba establecida.
Entonces, aquí está mi versión de la respuesta de @Nicholas Piasecki (también convertida a VB.NET):
'''''' <summary>
'''''' Raises the <see cref="E:System.Windows.Forms.ComboBox.SelectionChangeCommitted"/> event _after_ forcing any data bindings to be updated.
'''''' </summary>
'''''' <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
Protected Overrides Sub OnSelectionChangeCommitted(e As EventArgs)
Dim bindings As List(Of Binding) = ( _
From x In Me.DataBindings.Cast(Of Binding)()
Where (x.PropertyName = "SelectedItem" OrElse x.PropertyName = "SelectedValue" OrElse x.PropertyName = "SelectedIndex") AndAlso
(x.DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged OrElse x.DataSourceUpdateMode = DataSourceUpdateMode.OnValidation)
).ToList()
For Each b As Binding In bindings
'' Force the binding to update from the new SelectedItem
b.WriteValue()
'' Force the Textbox to update from the binding
b.ReadValue()
Next
MyBase.OnSelectionChangeCommitted(e)
End Sub
El WinForms ComboBox
es malo con respecto a OnPropertyChanged
. Aquí hay algo de código de un proyecto anterior que usé para que OnPropertyChanged
funcione de la manera que espero para la propiedad SelectedItem
. Esto funciona para mi instancia específica, pero a menudo me cuesta trabajo hacer que este escenario funcione. ¡Buena suerte!
/// <summary>
/// A modification of the standard <see cref="ComboBox"/> in which a data binding
/// on the SelectedItem property with the update mode set to DataSourceUpdateMode.OnPropertyChanged
/// actually updates when a selection is made in the combobox.
/// </summary>
public class BindableComboBox : ComboBox
{
/// <summary>
/// Raises the <see cref="E:System.Windows.Forms.ComboBox.SelectionChangeCommitted"/> event.
/// </summary>
/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
protected override void OnSelectionChangeCommitted(EventArgs e)
{
base.OnSelectionChangeCommitted(e);
var bindings = this.DataBindings
.Cast<Binding>()
.Where(x =>
x.PropertyName == "SelectedItem" &&
x.DataSourceUpdateMode == DataSourceUpdateMode.OnPropertyChanged);
foreach (var binding in bindings)
{
// Force the binding to update from the new SelectedItem
binding.WriteValue();
// Force the Textbox to update from the binding
binding.ReadValue();
}
}
}