2012-01-07 26 views
6

WPF puede ser exasperante a veces.¿Cuál es la mejor forma de compartir datos entre una ventana de WPF y sus controles de usuario?

Tengo una aplicación bastante simple que consiste en una única ventana principal que contiene un control de pestañas y varias pestañas. No me gustó la idea de tener el código para todas las pestañas en el mismo archivo, así que utilicé la respuesta de this question para dividir cada pestaña en un control de usuario diferente.

Dentro de la ventana principal tengo una instancia de un objeto que contiene la configuración de la aplicación y algunos otros datos de toda la aplicación. Varias de mis pestañas requieren acceso a estos datos para fines de enlace de datos. No he podido encontrar una buena manera de lograr esto.

Primero intenté acceder a la ventana padre en el evento cargado Controles y obtener una referencia a la propiedad en la ventana principal que expuso el objeto de configuración, como se muestra en el siguiente código. Este tipo de trabajo funciona, excepto que el evento Loaded se activa cada vez que la pestaña gana foco. Además, este evento se produce tarde en el ciclo de vida de control, por lo que no puedo enlazar a ninguna de las propiedades en este objeto en los controles de usuario XAML.

private void MyUserControl_Loaded(object sender, RoutedEventArgs e) 
{ 
    this.ApplicationSettings = ((MainWindow)Window.GetWindow(this)).ApplicationSettings; 
} 

Entonces experimentó con pasar los datos al usuario controles constructor, pero no hay manera de hacerlo en XAML.

Dado que estos son ajustes de toda la aplicación, podría hacer que la clase ApplicationSettings fuera singleton y hacer referencia a ella en todas partes, pero preferiría no hacer eso para pruebas de unidades.

Entonces, ¿cómo se logra algo como esto? ¿Mi enfoque es fundamentalmente defectuoso? En mi opinión, todos estos elementos de la interfaz de usuario son parte de la misma ventana y, por lo tanto, deberían poder acceder a los datos desde la ventana principal, pero el modelo de objetos no parece permitir esto.

Respuesta

2

Se puede poner objeto la configuración en una propiedad estática en una clase contenedora (SettingsHolder en este ejemplo y hacer referencia a ella una amplia aplicación a través de

en XAML:

{Binding SettingName, Source={x:Static local:SettingsHolder.Settings}} 

con local siendo el espacio de nombres de su SettingsHolder clase está en

en Código:.

var x = SettingsHolder.Settings.SettingName; 
SettingsHolder.Settings.SettingName = x; 
+0

Creo que esta es la ruta que voy a tomar. Como dije en la publicación original, quiero un comportamiento singleton sin el singleton real, y esto me da eso. En realidad, probablemente haga la clase singleton, pero dejaré el constructor público para fines de prueba. Gracias! – EricTheRed

1

En la declaración de su control de usuario, puede simplemente establecer el contexto de datos a la instancia del objeto que contiene todas las cosas que necesita vincular.

<someNamespace:EricsUserControl DataContext="{Binding InstanceOfBindingObject}"/>

A continuación, puede acceder a las propiedades de los objetos que instancia dentro del control de usuario como lo haría normalmente.

+0

Esto es realmente bueno de saber, y podría usarlo para otras cosas, pero me gustaría dejar la opción abierta para acceder a la configuración en el código también. – EricTheRed

+0

@EricTheRed perfectamente sensato, pero solo un aviso, también puede acceder al DataContext para un control de usuario dentro del código. Entonces, si enlazaste al objeto de instancia como se muestra arriba y luego dentro del archivo de código subyacente hiciste algo de 'var myInstance = (BindingObjectClass) this.DataContext', ¡podrías acceder a ese objeto desde la variable myInstance! Espero que ayude en algún momento en el futuro! – Kevek

0

Lo que hago es usar un Frame en el Tab y colocar un Page en el Frame. (pero creo que lo mismo puede aplicarse con un Control de usuario). El constructor solo se dispara cuando se crea la página y usted puede controlar cuándo se crea la página y puede pasar información en el constructor. Una página tiene más eventos de ciclo de vida para vincular. También uso el evento Loaded para construir UI (solo se dispara una vez). Si enlaza la página en XAML, se activará cuando inicie la aplicación y no podrá pasar la información. Esto está creando una página y mostrándola en un diálogo, pero esa página podría estar vinculada a un marco.

 NavigationWindow winSearchXML; 
     using (new WaitCursor()) 
     { 
      winSearchXML = new NavigationWindow(); 
      winSearchXML.Content = new PageSearchResultsXML(GabeLib.GetSearchXML(GabeLib.enumXMLtype.Flat)); 
     } 
     winSearchXML.ShowDialog(); 

Tengo que ser honesto, porque algunas veces obtengo un ciclo de vida en una página que simplemente no entiendo. Así que tómenlo con un grano de sal. Pero el punto es que tienes el contructor y los eventos cargados que pueden darte lo que necesitas.

+0

¡Eso es inteligente! Nunca pensé en hacer algo así. Creo que para lo que estoy trabajando, sin embargo, esto es un poco exagerado. Gracias por la idea sin embargo. – EricTheRed

Cuestiones relacionadas