form databind data c# wpf xaml binding

c# - databind - OneWayToSource Binding parece estar roto en.NET 4.0



data binding c# (6)

¿Es este el comportamiento deseado para OneWayToSource Binding en .NET 4.0?

Sí. Esto se hace para que el desarrollador pueda cambiar el valor proporcionado sin convertidores torpes.

¿Cuál fue el problema con la forma en que funcionó en 3.5?

No hay problema. La forma en que funcionaba en 3.5 no permitía corregir los valores proporcionados.

¿En qué escenarios es mejor este nuevo comportamiento?

Cuando necesita corregir los valores proporcionados. Si no lo necesita, entonces solo debe escribir getter and setter de la propiedad correcta.

public string TextProperty { get; set; }

Sin embargo, como puedo ver, el cambio de UpdateSourceTrigger a "PropertyChanged" evita que se vuelvan a leer los valores (para que pueda dejar la antigua declaración de propiedad):

<StackPanel> <TextBox Text="{Binding TextProperty, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}"/> <Button/> </StackPanel> private string m_textProperty; public string TextProperty { get { return "Should not be used in OneWayToSource Binding"; } set { m_textProperty = value; } }

OneWayToSource Binding parece estar roto en .NET 4.0

Tengo esta simple pieza de Xaml

<StackPanel> <TextBox Text="{Binding TextProperty, Mode=OneWayToSource}"/> <Button/> </StackPanel>

Y mi código detrás se ve así

public MainWindow() { InitializeComponent(); this.DataContext = this; } private string m_textProperty; public string TextProperty { get { return "Should not be used in OneWayToSource Binding"; } set { m_textProperty = value; } }

En .NET 3.5 esto funciona como se puede hacer excepto. Ponga un poco de texto en el TextBox texto, presione la tecla Tab para que pierda el foco, y TextProperty actualiza con el texto ingresado en el TextBox

En .NET 4.0 , si escribo un texto en el TextBox texto y luego presiono la tecla Tab para que pierda el foco, TextBox vuelve al valor de TextProperty (lo que significa "No se debe usar en el enlace OneWayToSource" ). ¿Es esta relectura prevista para un OneWayToSource en .NET 4.0? Solo quiero que TextBox introduzca su valor en TextProperty y no al revés.

Actualizar
Agregar un Bounty a esta pregunta ya que esto se ha convertido en un inconveniente mayor en mi proyecto y me gustaría saber el motivo por el que esto ha cambiado. Parece que se llama a get después de que el enlace ha actualizado la fuente. ¿Es este el comportamiento deseado para OneWayToSource Binding en .NET 4.0?

En caso afirmativo

  • ¿Cuál fue el problema con la forma en que funcionó en 3.5?
  • ¿En qué escenarios es mejor este nuevo comportamiento?

¿O se trata de un error que esperamos solucionar en una versión futura?


El blog de Karl Shifflett y la respuesta de @ Simpzon ya explican por qué agregaron esta función y por qué no es un problema para las propiedades que siempre obtienen lo que se estableció. En su propio código, siempre utiliza una propiedad intermedia que tiene la semántica adecuada para el enlace y utiliza una propiedad interna que tiene la semántica que desea. Llamaría a la propiedad intermedia una propiedad de "bloqueo" porque bloquea el getter para que no llegue a su propiedad interna.

Pero en el caso de que no tenga acceso al código fuente de la entidad en la que está configurando la propiedad y quiere el comportamiento anterior, puede usar un convertidor.

Aquí hay un convertidor de bloqueo con estado:

public class BlockingConverter : IValueConverter { public object lastValue; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { return lastValue; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { lastValue = value; return value; } }

y puedes usarlo para tu ejemplo como este:

<Grid> <Grid.Resources> <local:BlockingConverter x:Key="blockingConverter" x:Shared="False"/> </Grid.Resources> <StackPanel> <TextBox Text="{Binding TextProperty, Mode=OneWayToSource, Converter={StaticResource blockingConverter}}"/> <Button Content="Click"/> </StackPanel> </Grid>

Tenga en cuenta que debido a que el convertidor tiene un estado, necesita una instancia separada cada vez que se usa el recurso y para esto podemos usar el atributo x:Shared="False" en el recurso.


Error, definitivamente.

si es una "característica", es una muy mala ...

parece que han agregado una llamada a la función get () después de que se haya completado el conjunto (), incluso en el modo OneWayToSource ... ¿alguien puede explicar por qué?

también, gracias por señalar esto, explica un problema que tuve desde que actualicé mi proyecto a .NET 4.0 y que no podía explicar hasta ahora ...

solo una nota al margen: he resuelto esto al usar propiedades de dependencia al final.


Esto es claramente un error. Parece que alguien lo informó al menos una vez. https://connect.microsoft.com/VisualStudio/feedback/details/612444/onewaytosource-broken-in-net-4-0

Estoy de acuerdo con muchos de los otros en que una de las maneras debe ser un período de ida.

Mi escenario es complicado y cambiar la funcionalidad entre las versiones del framework me ha causado un verdadero dolor de cabeza.

Tengo un cuadro de texto vinculado a una propiedad. Tengo un convertidor que cambia el formato sobre la marcha. EG: Ingresé a EU5 en el cuadro de texto, la propiedad obtiene EU005. Conseguí que el conjunto de enlace para disparar en la propiedad cambiara ya que necesito hacer búsquedas dentro del ViewModel a medida que el usuario escribe. La nueva implementación cambia el valor del cuadro de texto a medida que escribo. Entonces, si deseo escribir EU512, no podría hacerlo fácilmente, ya que el texto del cuadro de texto seguiría cambiando.

He intentado muchas cosas: enlace explícito (donde decides cuándo actualizar y en qué sentido). Esto tiene el mismo problema. Si digo, UpdateSource, lo hace, pero también vuelve a leer la propiedad y también cambia el objetivo.

Intenté OneWayToSource y tuve el mismo problema. No he encontrado forma de evitar esto sin hacer cambios molestos en mi VM. La única otra forma sería eliminar el enlace en este campo y comenzar a disparar eventos que serían terribles.

Si MS hizo que el enlace se comportara como se lo denomina lógicamente, mi problema desaparecería. Incluso una propiedad en el enlace para optar por la implementación .net4 y comportarse como 3.5 me funcionaría.

¿Alguien tiene alguna sugerencia sobre cómo puedo evitar esto?


Esto es de hecho por diseño. Por lo general, no debería crear problemas, pero la implementación de su propiedad es, al menos, poco convencional, diría yo. Los getters y setters (accedores) realmente no deberían hacer mucho más que get y set, y cada get debería ser consistente con el último conjunto correspondiente. (Lo siento, no hay fuente para esto, es lo que hemos llamado buena ciudadanía en todos los equipos de desarrollo en los que he estado).

Más detalles sobre la función aquí: http://karlshifflett.wordpress.com/2009/05/27/wpf-4-0-data-binding-change-great-feature/


Tuve una variación de este problema para un enlace bidireccional. Me doy cuenta de que esto no es exactamente lo mismo que el problema que se discute, pero esta respuesta salió a la cabeza durante la búsqueda y me llevó a mi solución. Espero que alguien lo encuentre útil.

Mi solución bloquea la relectura de la propiedad de respaldo pero actualizará la UI cuando la cambie otra fuente. Basé mi solución en el convertidor de bloqueo en la respuesta de Rick Sladkey.

Simplemente agrega un cheque al convert para ver si el lastValue campo lastValue se convertiría al mismo valor de backing store. De lo contrario, el valor del almacén de respaldo debe haber cambiado desde otra fuente y la UI debe actualizarse.

public class MyConverter : IValueConverter { public object lastValue; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (LastValue != null && MyConvertBack(LastValue).Equals(value)) return lastValue; else return MyConvert(value); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { lastValue = value; return MyConvertBack(value); } private object MyConvertBack(Object value) { //Conversion Code Here } private object MyConvert(Object value) { //Conversion Code Here } }

En mi caso de uso particular para esto, tenía un sufijo de longitud y dimensión almacenado en un cuadro de texto (10m, 100mm, etc.). El convertidor lo analizó en un valor doble o agregó el sufijo (según la dirección de conversión). Sin el convertidor agregaría un sufijo en cada actualización del cuadro de texto. Intentar escribir ''10'' daría como resultado ''1m0'' ya que el convertidor se ejecutaría después del primer golpe de tecla.