2009-06-15 8 views
30

Revisé esta web y google y las soluciones no funcionaron para mí.Uso del DataContext del padre (WPF - Encuadernación de comandos del menú dinámico)

Tengo un comando en el ViewModel de un UserControl. Bueno, el usercontrol tiene un ItemsControl enlazado a un ObservableCollection. Dentro de DataTemplate de ItemsControl.ItemTemplate tengo un botón y quiero usar el comando. No puedo vincular el comando porque dentro de DataTemplate, el contexto de datos no es ViewModel, sino un elemento de ObservableCollection.

La pregunta es: ¿Cómo puedo vincular el botón al comando si se pierde el contexto de datos padre?

Creo que esto necesita una solución fácil porque creo que este es un problema común.

imaginar esto sceneario:

usted tiene un artículo ListBox con un ObservableCollection como el ItemsSource, por lo que están utilizando un DataTemplate dentro del cuadro de lista para cada elemento de la colección. Bueno, quiere eliminar el elemento seleccionado y pone un botón en cada fila para ese trabajo. ¿Cómo haces eso?

En el MVP, puedo hacer esto en el evento clic del botón:

Button but = e.Source as Button; 

if (but != null) 
     Presenter.ActualNote = but.DataContext as Note; 

En resumen. Envía el contexto de datos de la fila (el elemento seleccionado) al presentador.

Pero, ¿cómo puedo hacerlo a la manera mvvm? Porque necesito usar un comando pero no puedo asignar el comando al botón porque el botón no sabe nada sobre ViewModel (donde existe el comando).

Como puede ver, el botón debe existir dentro de la plantilla de datos, entonces el contexto de datos ya no es el ViewModel .... Por eso necesito acceder al DataContext del padre para acceder al comando.

Espero que entienda mejor mi problema.

Gracias.

Respuesta

5

Si desea una solución sucia, que rompe MVVM, establezca Tag = "{Binding}" en el botón y maneje el evento Click. En el controlador de eventos, llame al comando en su ViewModel.

+0

: P. Estoy buscando una buena solución sin romper mvvm: P, pero gracias, es una solución: P –

+2

Soy un desarrollador SL, por lo que romper mvvm es el par para el curso :) – geofftnz

+0

¿Por qué está usando SL! = MVVM? – user112889

89

Utilice el enlace de abajo para el mando de su botón:

{Binding DataContext.CommandName, 
     RelativeSource={RelativeSource FindAncestor, 
         AncestorType={x:Type MyUserControl}}} 

Esto le dirá que se encuentra el control de usuario y utilizar su DataContext.

+0

Eso es es la solución que encontré, pero no funciona para mí.Si se pone: Command = "{Vinculando DataContext.CommandName, RelativeSource = {RelativeSource FindAncestor, AncestorType = {x: Type UserControl}}}" Dice que AncestorType debe especificarse para RelativeSource en el modo FindAncestor. ¿Dónde está el problema? Gracias por la respuesta. –

+1

Acabo de probar esto en una muestra y funcionó para mí. Parece un error de sintaxis. ¿Puedes copiar y pegar el XAML de tu botón? –

+0

Oh, no hay ningún error, VS lo marcó pero compila. Estoy intentando saber algo simple. Pongo un elemento Tag en el usercontrol y quiero imprimirlo en el encabezado de un elemento de menú: . Pero, visual studio dice: No se puede encontrar el origen para el enlace con la referencia 'RelativeSource FindAncestor, AncestorType =' System.Windows.Controls.UserControl ', AncestorLevel =' 1 ''. BindingExpression: Path = Tag; DataItem = null; el elemento objetivo es 'MenuItem' (Name = ''); target property es 'Encabezado' (escribe 'Objeto' –

3

RelativeSource funciona, pero no creo que sea correcto dejar que los controles merodeen entre las propiedades de los demás. Es extraño que el botón colocado dentro de una vista de elemento haga algo con una fuente de datos externa en lugar de con el elemento encuadernado. Es posible que deba revisar el diseño del código del programa.

+0

me gusta su responda, pero lo necesito para esta solución. Tengo un control de elementos con una cuadrícula adentro, cada artículo es una nota. Bueno, tengo un menú contextual en la grilla que tiene algunas opciones sobre la nota "seleccionada". Cada opción es un comando, pero el contexto de datos del menú es la nota real y no el modelo de vista. No puedo dejar el menú afuera porque necesito el menú para cada artículo. –

+0

Hm, sí, no creo que sea una solución ideal, pero puede colocar su objeto ModelView como un recurso estático en un elemento Window.Resources, tal vez usando ObjectDataProvider, y luego hacer referencia a él por extensión estática dentro de cualquier enlace de datos desde cualquier parte de la ventana. –

+0

Estoy de acuerdo, siempre se sintió como un truco cuando utilicé esta solución, pero es un truco que funciona. ;) –

3

Bien, entonces, ¿qué hay de modificar su clase de elemento de datos para que tenga una propiedad que haga referencia a la vista de modelo completa?

Si su ItemsSource es de tipo ObservableCollection<DataItem> a continuación, modificar DataItem tipo así:

public class DataItem 
{ 
    public BusinessObject Value { get; set; } 

    private ModelView modelView; 

    public ModelView ModelView 
    { 
     get 
     { 
      return modelView; 
     } 
    } 

    public DataItem(ModelView modelView) 
    { 
     this.modelView = modelView; 
    } 
} 
+0

¿Puedes explicar eso de nuevo? Con mi inglés no entiendo qué estás tratando de explicarme. Lo siento. –

+0

Agregó una explicación más detallada. –

+0

Es un pequeño truco, pero debería funcionar. –

Cuestiones relacionadas