c# - two - Enlace de datos a un método en WPF
wpf binding types (5)
Estoy teniendo problemas para TextBox.Text
datos de una propiedad TextBox.Text
con el método de un objeto. La idea es permitirle al usuario escribir en un TextBox
un nombre de archivo y luego tener un TextBlock
que produzca la extensión de ese archivo.
class GetFileInfo
{
public string GetFileExtension(string fileName)
{
return Path.GetExtension(fileName);
}
}
Aquí está mi XAML:
<Window.Resources>
<ObjectDataProvider x:Key="getFileInfo" MethodName="GetFileExtension" ObjectType="{x:Type local:GetFileInfo}">
<ObjectDataProvider.MethodParameters>
<sys:String>abc.text</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
<StackPanel>
<TextBox Name="textBox1">
<TextBox.Text>
<Binding Source="{StaticResource getFileInfo}" Path="MethodParameters[0]" BindsDirectlyToSource="True" UpdateSourceTrigger="PropertyChanged" />
</TextBox.Text>
</TextBox>
<TextBlock Name="textBlock1" Text="{Binding Source={StaticResource getFileInfo}}"/>
</StackPanel>
Por alguna razón, no está haciendo nada. ¿Alguno de ustedes podría señalar cuáles pueden ser las razones? Esto es lo que veo en el diseñador y cuando ejecuto la aplicación:
texto alternativo http://img64.imageshack.us/img64/6922/f0rki14feo3oa3groxm5kgm.png
Y esto es lo que sucede cuando intento configurar otro texto en tiempo de ejecución:
alt text http://img684.imageshack.us/img684/1057/b52pnq1dm4i23qivizvpaqq.png Aquí está el error dado por el depurador al intentar establecer otro texto en tiempo de ejecución:
System.Windows.Data Error: 8: No se puede guardar el valor del objetivo de nuevo a la fuente. BindingExpression: Path = MethodParameters [0]; DataItem = ''ObjectDataProvider'' (HashCode = 2207369); el elemento objetivo es ''TextBox'' (Name = ''textBox1''); target property es ''Text'' (tipo ''String'') ArgumentException: ''System.ArgumentException: objeto de tipo'' MS.Internal.Data.PropertyPathWorker + IListIndexerArg ''no se puede convertir a tipo'' System.Int32 ''. en System.RuntimeType.TryChangeType (Valor del objeto, Binder Binder, CultureInfo culture, Boolean needsSpecialCast) en System.RuntimeType.CheckValue (Valor del objeto, Binder Binder, CultureInfo culture, BindingFlags invokeAttr) en System.Reflection.MethodBase.CheckArguments (Object [] parámetros, Binder Binder, BindingFlags invokeAttr, CultureInfo culture, Signature sig) en System.Reflection.RuntimeMethodInfo.Invoke (Object obj, BindingFlags invokeAttr, Binder Binder, Object [] parámetros, CultureInfo culture, Boolean skipVisibilityChecks) en System.Reflection.RuntimeMethodInfo. Invoke (Object obj, BindingFlags invokeAttr, Binder Binder, Object [] parámetros, CultureInfo culture) en System.Reflection.RuntimePropertyInfo.SetValue (Object obj, Object value, BindingFlags invokeAttr, Binder Binder, Object [] index, CultureInfo culture) en MS .Internal.Data.PropertyPathWorker.SetValue (Objeto, Valor del objeto) en MS.Internal.Data.ClrBindingWorker.UpdateValue (Valor del objeto) en System.Windows.Data.BindingExpre ssion.UpdateSource (valor del objeto) ''
¿Se establece DataContext
? En su código subyacente, ¿estableció el valor de su TextBlock
en "saadsas" (lo único que puedo adivinar), lo que rompió su enlace de datos?
La vinculación de datos requiere que se NotifyPropertyChanged
evento NotifyPropertyChanged
cuando se actualiza la fuente. En este caso, querría envolver esta llamada de función en un get / set como tal:
public class FileWrapper: System.ComponentModel.INotifyPropertyChanged{
private string m_filename;
public string FileExtension{
get{ return GetFileExtension(FileName);}
}
public string FileName{
get{ return m_filename;}
set{ m_filename = value; OnPropertyChanged("FileName"); OnPropertyChanged( "FileExtension");
}
public string GetFileExtension( string filename){
//implementation
}
public event System.ComponentModel.NotifyPropertyChangedEvent PropertyChanged = (a,b)=>{};
protected void OnPropertyChanged(string property){
PropertyChanged( this, new System.ComponentModel.PropertyChangedEventArgs( property ));
}
}
Ok, parece que esto es un error al ejecutar WPF 4.0, como se puede ver en los comentarios aquí .
Woops, estaba un poco apresurado ... el ejemplo funciona perfectamente siempre que lo compile para el framework 3.5 (en VS 2010). Pero si lo convierte a proyecto WPF 4.0, el método WeightOnPlanet en ObjectDataProvider no se invoca en el odp2 cuando edita el cuadro de texto. He intentado encontrar nuevos atributos en el Binding o en ObjectDataProvider, pero nada ha funcionado hasta ahora ...
Al compilar en 3.5, funciona bien aquí.
Parece que necesita obtener una comprensión de MVVM, consulte este clásico artículo http://msdn.microsoft.com/en-us/magazine/dd419663.aspx
Si bien es posible usar Binding
para llamar a un método y obtener su valor de retorno, no es sencillo. Es mucho más sencillo vincular las propiedades y usar la combinación de enlace y notificación de cambio para obtener el resultado que está buscando.
Crea una clase con dos propiedades, Filename
y Extension
. Filename
es solo una propiedad de cadena de lectura / escritura. Extension
es una propiedad de cadena de solo lectura cuyo captador llama al método al que está intentando llamar.
Ahora haga que esa clase implemente INotifyPropertyChanged
, porque si una propiedad puede cambiar en el código, necesita una forma de decirle al enlace que lo ha hecho. Haga que el colocador de la propiedad Filename
de Filename
notifique los enlaces que la propiedad de Extension
ha cambiado.
Agregue un Binding
a un TextBox
que se una a la propiedad Filename
utilizando el modo TwoWay
. Agregue un Binding
a un TextBox
que se une a la Extension
utilizando el modo OneWay
predeterminado.
La secuencia de eventos es:
- El usuario escribe un nuevo
Filename
en unTextBox
encuadernado y presiona TAB. - El
TextBox
pierde el foco. - Debido a que el modo de
Binding
esTwoWay
, y está usando el comportamiento predeterminado de actualizar la fuente cuando el objetivo pierde el foco, eso es lo que hace. - El
Binding
actualiza la fuente llamando al establecedor deFilename
. - El definidor de
Filename
aumentaPropertyChanged
. - La
Binding
manejaPropertyChanged
, mira su argumento y ve que la propiedadExtension
ha cambiado. - El
Binding
llama al getter de la propiedadExtension
. - El getter de la propiedad
Extension
llama al método para determinar la extensión deFilename
y la devuelve alBinding
. - El
Binding
actualiza suTextBox
destino con el nuevo valor deExtension
.
Este es el concepto central subyacente al enlace de datos y el patrón MVVM. Una vez que lo entiendes, se convierte en una segunda naturaleza, y el desarrollo de WPF se vuelve aproximadamente diez millones de veces más fácil.