2009-03-25 6 views
20

Tengo un escenario en el que realmente no sé cómo vincular datos a los controles alojados en un UserControl con múltiples contextos de datos.WPF vinculando múltiples controles a diferentes contextos de datos

los datos que desea enlazar proviene de 2 clases

UserInfo, UserExtendedInfo 

El DataContext del UserControl se establece en información del usuario para que pueda obligar a la mayoría de los controles fácilmente haciendo lo siguiente

<Label Name="LblEmail" Text="{Binding Email}" /> 

Sin embargo Pongo No sé cómo enlazar propiedades de la clase UserExtendedInfo fácilmente. Mi idea inicial fue establecer el contexto de datos de cada control que desea utilizar los datos de UserExtendedInfo para que yo pudiera hacer lo mismo. Pero esto parece engorroso ya que tendría que asignar manualmente cada uno individualmente. Los datos de UserExtendedInfo deben obtenerse de la base de datos cada vez que el UserControl se vuelva visible para que no se desincronice.

XAML:

<Label Name="LblTest" Text="{Binding Locale}" /> 

código subyacente:

Private Sub UserManager_IsVisibleChanged(ByVal sender As System.Object, ByVal e As System.Windows.DependencyPropertyChangedEventArgs) 
     If DirectCast(e.NewValue, Boolean) Then 
      Dim user As UserInfo = DirectCast(DataContext, UserInfo) 

      If user IsNot Nothing Then 
       Dim usrExt As UserExtenedInfo = UserController.GetUserExtended(user.userID) 

       LblTest.DataContext = usrExt 
      Else 
       Throw New ArgumentException("UserId doesn't exist or is less than 1") 
      End If 
     End If 
    End Sub 

Respuesta

25

yo tal vez pensar en envolver el objeto de usuario en una clase separada a continuación, establecer las propiedades DataContext de sub-paneles que contienen los datos.

Por ejemplo:

public class UserDataContext 
{ 
    public UserInfo UserInfo { get; set; } 
    public UserExtendedInfo UserExtendedInfo { get; set; } 
} 

Luego, en su UserControl.xaml:

<!-- Binding for the UserControl should be set in its parent, but for clarity --> 
<UserControl DataContext="{Binding UserDataContext}"> 
    <StackPanel> 
    <Grid DataContext="{Binding UserInfo}"> 
     <TextBlock Text="{Binding Email}" /> 
    </Grid> 
    <Grid DataContext="{Binding UserExtendedInfo}"> 
     <TextBlock Text="{Binding Locale}" /> 
     <TextBlock Text="{Binding AboutMe}" /> 
    </Grid> 
    </StackPanel> 
</UserControl> 

Esto supone que la clase de información del usuario tiene una propiedad de correo electrónico

y

Que su clase UserExtendedInfo tiene una propiedad de Locale y AboutMe

+0

Ok, eso tiene mucho sentido. Hay tantas cosas nuevas que aprender en WPF :) – Alex

+1

En lugar de crear un nuevo modelo cuyo único propósito sea admitir esta vista en particular, solo debe agregar UserInfo y UserExtendedInfo como propiedades públicas de un ViewModel que puede vincular a la vista. (Ver [respuesta] de Rich (http://stackoverflow.com/questions/679933/wpf-binding-multiple-controls-to-different-datacontexts/680052#680052)). – totorocat

7

Aquí es donde M-V-VM es muy útil. La idea (como yo lo entiendo, al menos ... aún muy nueva para mí) es que la ventana en sí está vinculada a una clase "ViewModel". La clase ViewModel es solo una clase que representa todos los datos de manera que toda tu página tiene acceso a todo lo que necesita ... simplemente reúne todos los diferentes objetos a los que tendrás que enlazar en una clase ... y configura el DataContext de la Ventana (o Página) a una instancia de esta clase. Sus instancias UserInfo y UserInfoExtended son propiedades públicas del objeto ViewModel, y usted simplemente usa la ruta de acceso de su elemento de enlace para obtener las propiedades apropiadas de los objetos apropiados a los que desea vincular cada control.

Hay un video excelente (pero bastante extenso) que explica este patrón, y muestra un ejemplo completo que ilustra muchas maneras de lograr esto y muchas razones diferentes por las que este es un modelo conveniente y escalable para usar en una aplicación WPF. También cubre muchas características de WPF, así como una introducción a la inyección de dependencia, que también son temas muy relevantes, dado el ejemplo.

Aquí hay un enlace a la entrada del blog que contiene un enlace al video que estoy hablando:

EDITAR: Publicación del blog ha sido eliminado (esta respuesta es bastante antiguo).Aquí está el video en YouTube:

https://www.youtube.com/watch?v=BRxnZahCPFQ

+0

solo una nota, ViewModel no necesita tener propiedades de dependencia. Solo necesita implementar INotifyPropertyChanged si desea que los controles reflejen el cambio en una de sus propiedades. –

+0

El enlace está muerto, ¿podría actualizar el enlace? –

+0

@HassanTareq Lo encontré en YouTube y actualicé el enlace – Rich

6

rico y bendewey tuvieron buenas respuestas. Explorando este mismo tema hoy en Silverlight en lugar de WPF, descubrí que no es necesario establecer múltiples DataContexts. Revisando el ejemplo de bendewey:

<UserControl DataContext="{Binding UserDataContext}"> 
    <StackPanel> 
     <TextBlock Text="{Binding Path=UserInfo.Email}" /> 
     <TextBlock Text="{Binding Path=UserExtendedInfo.Locale}" /> 
     <TextBlock Text="{Binding Path=UserExtendedInfo.AboutMe}" /> 
    </StackPanel> 
</UserControl> 

Uso de la ruta de enlace se obtiene la flexibilidad para mezclar y los enlaces a los partidos propiedades de diferentes clases y sin preocupación por el DataContext de los contenedores de los diversos controles.

También puede ampliar las capacidades de la clase UserDataContext de bendewey agregando propiedades que manipulen las propiedades de las clases UserInfo y UserExtendedInfo. Podría, por ejemplo, combinar el nombre y el apellido.

Es posible que desee implementar INotifyPropertyChanged para que sus controles se actualicen cuando reinicie UserInfo y UserExtendedInfo.

Puede ser arquitectónicamente preferible aislar por completo las clases subyacentes UserInfo y UserExtendedInfo del XAML al exponer las propiedades requeridas directamente en UserDataContext, eliminando así la necesidad de Binding Path.

+1

Esto es una mejora en la respuesta de Bendeway (+1), pero mejoraría algunas cosas más: No necesita "Path =", y en el 95% de los casos usaría tipos anónimos de C# en lugar de una clase explícita. –

15

Este es el método más simple de todos, y funciona muy bien.

En el código subyacente, donde se establece el contexto, basta con utilizar un tipo anónimo que contiene todos los valores deseados:

DataContext = new 
{ 
    info = FetchUserInfoFromDatabase(), 
    extendedInfo = FetchExtendedUserInfoFromDatabase(), 
}; 

En el XAML puede enlazar a cualquier cosa:

<UserControl> 
    <StackPanel> 
    <TextBlock Text="{Binding info.Email}" /> 
    <TextBlock Text="{Binding extendedInfo.Locale} /> 
    ... 

Alternativamente puede enlazar en dos niveles como han descrito otras respuestas:

<UserControl> 
    <StackPanel> 
    <Grid DataContext="{Binding info}"> 
     <TextBlock Text={Binding Email}"> 
     ... 
+0

¡Gracias! ¡Me ayudó mucho! –

Cuestiones relacionadas