2011-06-15 10 views
5

Tengo un enlace de datos configurado con un convertidor para transformar una fuente XML incómoda en un árbol de clases internas de visualización y edición. Todo funciona muy bien para leer desde el origen XML, pero me está costando muchísimo intentar que los cambios realizados en las clases internas se propaguen nuevamente a la fuente XML.Enlace de datos bidireccional con el convertidor no actualiza la fuente

Aquí está el XAML para el sitio de uso:

 <local:SampleConverter x:Key="SampleConverter" /> 
     <Expander Header="Sample" > 
      <local:SampleControl 
       Sample="{Binding Path=XmlSource, 
           Converter={StaticResource SampleConverter}, 
           Mode=TwoWay}" /> 
     </Expander> 

XmlSource es un CLR lectura y escritura de propiedad (no DependencyProperty) de los datos de los padres objeto dependiente. Es un tipo .NET generado desde un XSD.

SampleConverter implementa IValueConverter. Se llama al método Convert y devuelve datos no nulos, pero nunca se llama al método ConvertBack.

SampleControl es un UserControl que encapsula la interacción de UI con el árbol de datos de muestra. Se XAML se ve así:

<UserControl x:Class="SampleControl"> 
    [... other stuff ...] 

    <UserControl.Content> 
     <Binding Path="Sample" RelativeSource="{RelativeSource Mode=Self}" Mode="TwoWay" TargetNullValue="{StaticResource EmptySampleText}" /> 
    </UserControl.Content> 

    <UserControl.ContentTemplateSelector> 
     <local:BoxedItemTemplateSelector /> 
    </UserControl.ContentTemplateSelector> 
</UserControl> 

La propiedad de la muestra es una propiedad de dependencia en el código SampleControl atrás:

public static readonly DependencyProperty SampleProperty = 
    DependencyProperty.Register("Sample", typeof(SampleType), typeof(SampleControl), new PropertyMetadata(new PropertyChangedCallback(OnSampleChanged))); 

public SampleType Sample 
{ 
    get { return (SampleType)GetValue(SampleProperty); } 
    set { SetValue(SampleProperty, value); } 
} 

private static void OnSampleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    if (e.NewValue != null) 
    { 
     ((INotifyPropertyChanged)e.NewValue).PropertyChanged += ((SampleControl)d).MyPropertyChanged; 
    } 
    else if (e.OldValue != null) 
    { 
     ((INotifyPropertyChanged)e.OldValue).PropertyChanged -= ((SampleControl)d).MyPropertyChanged; 
    } 
} 

private void MyPropertyChanged(object sender, PropertyChangedEventArgs e) 
{ 
    ; // breakpoint here shows change notices are happening 
} 

Las clases internas que la XmlSource se convierte a aplicar INotifyPropertyChanged, y están enviando notificaciones de cambio de hasta el árbol, como lo indica un punto de interrupción en MyPropertyChanged arriba.

Entonces, si los datos indican que ha cambiado, ¿por qué WPF no está llamando al método ConvertBack de mi convertidor?

+0

El ejemplo de código para el cambio de propiedad sólo indica que las propiedades de la muestra están cambiando, y no la propia muestra. – Ragepotato

+0

@Ragepotato: ¿Está diciendo que el enlace de datos solo funciona si se asigna una nueva instancia a la propiedad Sample, pero no si las propiedades de la instancia existente a la que hace referencia la propiedad Sample cambian y notifican sus cambios a través de INotifyPropertyChanged? – dthorpe

+0

Sí. La muestra nunca cambió. Es el mismo objeto. Las propiedades dentro de esto cambiaron. Puede probar esto. Ponga un botón en su control después de que todo esté cargado y Sample obtenga su asignación inicial de su máquina virtual. Luego asigne la muestra a un nuevo SampleType. Recuerde que tiene que ser el tipo correcto o el motor de enlace lo ignorará. Si configura su enlace bidireccional a la derecha, verá que se llama su convert devuelta. – Ragepotato

Respuesta

2

Con consejos de varias preguntas similares y casi respuestas aquí en SO, tengo una solución de trabajo que conserva el enlace. Se puede forzar manualmente la unión para actualizar el origen en un evento estratégicamente colocados, como LostFocus:

private void mycontrol_LostFocus(object sender, RoutedEventArgs e) 
{ 
    if (mycontrol.IsModified) 
    { 
     var binding = mycontrol.GetBindingExpression(MyControl.SampleProperty); 
     binding.UpdateSource(); 
    } 
} 
0

XmlSource es un CLR lectura y escritura de propiedad (no DependencyProperty) de los datos de los padres objeto dependiente. Es un tipo .NET generado a partir de un XSD.

Creo que este es su problema. Una propiedad CLR básica no notificará y, por lo tanto, no podrá participar en el enlace de datos bidireccional. ¿Supongo que recibirás un enlace por única vez? ¿Tiene algún error de enlace de datos en su ventana de salida?

Usted puede tratar de crear un envoltorio que contiene la clase de la propiedad XmlSource, hacen que clase implemente INotifyPropertyChanged, y exponer XmlSource como una propiedad de notificación (que hace no necesita ser una propiedad de dependencia).

Además, con respecto a este comentario:

¿Estás diciendo que los datos obligatorios solamente funciona si una nueva instancia se asigna a la propiedad de la muestra, pero no si propiedades de la instancia existente referidos por la propiedad Sample es modificada y señal sus cambios a través de INotifyPropertyChanged?

Las implementaciones de muestra de INotifyPropertyChanged suelen tener la notificación que se produce cuando la propiedad cambia, no cuando cambian los elementos secundarios u otras propiedades. Sin embargo, puede activar el evento de notificación en cualquier propiedad en cualquier momento.Por ejemplo, puede tener una propiedad de "Nombre completo" que notifica cada vez que cambian "Nombre" o "Apellido".

Si lo anterior no es útil, sugeriría que publique un poco más de su código, tal vez una reproducción simplificada de lo que está intentando hacer funcionar.

Editar:

Creo que no he entendido bien su pregunta. Creo que el problema es a lo que aludiste en tus comentarios, es un tipo de referencia. Podría valer la pena intentar esto en su OnSampleChanged:

private static void OnSampleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var oldValue = Sample; 
    Sample = new SampleType(); 
    Sample = oldValue; 
} 

creo que esto obligará al sistema de unión a reconocer que algo cambió en el lado de destino.

+0

La propiedad XmlSource CLR ya implementa INotifyPropertyChanged.Además, se necesitaría llamar primero al ConvertBack del convertidor para obtener un valor para asignar a la propiedad XmlSource, y no se llamará a ConvertBack. – dthorpe

0

Tenía un problema similar. La solución fue la siguiente:

En lugar de un enlace bidireccional, utilicé una forma y un convertidor. El convertidor convierte (encapsula) el objeto (en su caso, el objeto principal de la propiedad xmlsource) en un modelo de vista, y el control se une a él.

viewModel funciona como un proxy, contiene una referencia al objeto, administra sus propiedades y, por supuesto, implementa INotifyPropertyChanged. En este caso, no necesita llamar al método ConvertBack, ya que las operaciones se realizan en la instancia adecuada a través de viewModel.

para que tenga una visión clara, no es necesario ningún código en los xaml.cs

Cuestiones relacionadas