2010-02-15 8 views
9

Estoy ocupado creando mi primera aplicación MVVM en WPF.WPF: TreeViewItem vinculado a un ICommand

Básicamente el problema que tengo es que tengo un TreeView (System.Windows.Controls.TreeView) que he colocado en mi ventana de WPF, he decidido enlazar a un elemento ReadOnlyCollection de CommandViewModel, y estos los elementos consisten en DisplayString, Tag y RelayCommand.

Ahora en el XAML, tengo mi TreeView y he vinculado con éxito mi ReadOnlyCollection a esto. Puedo ver esto y todo se ve bien en la interfaz de usuario.

El problema ahora es que tengo que vincular el RelayCommand al Comando del TreeViewItem, sin embargo, por lo que puedo ver, TreeViewItem no tiene un Comando. ¿Esto me obliga a hacerlo en la propiedad IsSelected o incluso en el código detrás del método TreeView_SelectedItemChanged o hay una manera de hacerlo mágicamente en WPF?

Este es el código que tengo:

<TreeView BorderBrush="{x:Null}" 
     HorizontalAlignment="Stretch" 
     VerticalAlignment="Stretch"> 
<TreeView.Items> 
    <TreeViewItem 
     Header="New Commands" 
     ItemsSource="{Binding Commands}" 
     DisplayMemberPath="DisplayName" 
     IsExpanded="True"> 
    </TreeViewItem> 
</TreeView.Items> 

e, idealmente, me encantaría ir:

<TreeView BorderBrush="{x:Null}" 
     HorizontalAlignment="Stretch" 
     VerticalAlignment="Stretch"> 
<TreeView.Items> 
    <TreeViewItem 
     Header="New Trade" 
     ItemsSource="{Binding Commands}" 
     DisplayMemberPath="DisplayName" 
     IsExpanded="True" 
     Command="{Binding Path=Command}"> 
    </TreeViewItem> 
</TreeView.Items> 

¿Alguien tiene una solución que me permite usar la infraestructura RelayCommand que tengo.

Gracias muchachos, muy apreciados!

Richard

Respuesta

2

Gracias por la entrada en el tema, y ​​sí, yo he dicho que no quería un código detrás de solución, sin embargo en ese momento yo era todavía muy bajo la impresión de que simplemente me faltaba algo ... así que terminé usando el evento TreeView_SelectedItemChanged.

Aunque el enfoque de Will parece ser un buen trabajo, para mi situación personal decidí que usaría el código. La razón para esto es para que View y XAML permanezcan como lo serían si TreeViewItem tuviera una propiedad de "Comando" a la que se pudiera vincular mi Command. Ahora no tengo que cambiar las plantillas o las vistas, todo lo que tengo que hacer es agregar el código y el evento para TreeView_SelectedItemChanged.

Mi solución:

private void TreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e) 
    { 
     if (sender != null) 
     { 
      var treeView = sender as TreeView; 
      if (treeView != null) 
      { 
       var commandViewModel = treeView.SelectedItem as CommandViewModel; 
       if (commandViewModel != null) 
       { 
        var mi = commandViewModel.Command.GetType().GetMethod("Execute"); 
        mi.Invoke(commandViewModel.Command, new Object[] {null}); 
       } 
      } 
     } 
    } 

Como ya tengo la RelayCommand unido a la TreeViewItem, todo lo que estoy haciendo ahora es simplemente invocar manualmente el método "Ejecutar" en la que RelayCommand específica.

Si esta es la forma completamente equivocada de hacer las cosas, por favor hágamelo saber ...

Gracias!

+1

Creo que con la vista de árbol ASP.NET puede extender TreeView y TreeViewItem para agregar este tipo de funcionalidad. Cambiaría el TVI para agregar lo que necesitaba y luego anularía un método en TV para crear una nueva instancia de su TVI. No sé si el mismo patrón está disponible en la vista de árbol de WPF; Lo revisé pero no tan a fondo. – Will

1

lo que he hecho se establece the Header del TreeViewItem a ser un botón, a continuación, aspectos al botón para que no se ve o actúa como uno, a continuación, realizar la unión contra el botón de mi mando.

Puede necesitar hacer esto a través de un DataTemplate, o puede necesitar cambiar la plantilla del mismo TreeViewItem. Nunca lo hice, pero así es como he hecho cosas similares (como encabezados de página con pestañas).


He aquí un ejemplo de lo que estoy hablando (que puede caer en esta Kaxaml y jugar un rato con él):

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Page.Resources> 
     <Style x:Key="ClearButan" TargetType="Button"> 
     <Setter Property="Template"> 
      <Setter.Value> 
       <ControlTemplate TargetType="Button">    
       <Border Name="border" 
        Padding="4" 
        Background="transparent"> 
        <Grid > 
        <ContentPresenter HorizontalAlignment="Center" 
            VerticalAlignment="Center"> 
        </ContentPresenter> 
        </Grid> 
       </Border> 
       </ControlTemplate> 
      </Setter.Value> 
     </Setter> 
     </Style> 
    </Page.Resources> 
    <Grid> 
     <TreeView> 
     <TreeViewItem> 
      <Button Style="{StaticResource ClearButan}"> 
      easy peasy 
      </Button> 
     </TreeViewItem> 
     </TreeView> 
    </Grid> 
</Page> 

He creado un nuevo estilo claro para un botón. Luego, simplemente coloco un botón en el TVI y establezco su estilo. Puede hacer lo mismo usando plantillas de datos, por supuesto.

+0

Hola, veo lo que estás tratando de hacer, y aprecio la respuesta rápida, pero ¿es esta realmente la mejor solución? ¡He buscado la red alta y baja y no puedo encontrar una buena manera de hacerlo! Tengo que decir que es molesto que esto no esté solo incorporado. Pero al menos has proporcionado una forma de hacerlo, pero ahora ¿cómo se obtiene el encabezado para mostrar el botón y el texto encuadernado? – Richard

+0

@richard actualizado con la muestra – Will

+1

Gracias Will por la actualización y veo que esto probablemente funcione. He tomado una ruta diferente, pero aprecio mucho la ayuda. Esperemos que esto ayude a alguien más que tenga este problema. – Richard

0

Este es un buen ejemplo de cómo el MVVM es una mera idea en WPF. Esperas que haya compatibilidad con el comando de ciertos elementos de la interfaz gráfica de usuario, pero no los hay, por lo que te obligan a pasar por un proceso complejo (como se muestra en el ejemplo de Will) solo para obtener un comando adjunto a algo. esperanza

Vamos abordan esta en WPF 2.0 :-)

+4

MVVM vino después de WPF, por lo que no era exactamente una "idea de último momento", era una forma de aplicar los principios de MVC a WPF. Además, esto es más un defecto de la vista de árbol que WPF. La vista de árbol no fue desarrollada para este tipo de uso, que fue un poco corto de miras. – Will

23

Sé que esto fue "respondido" hace un tiempo, pero dado que las respuestas no fueron ideales, pensé que pondría mi granito de arena. Utilizo un método que me permite no tener que recurrir a ningún "truco de botones con estilo" o incluso usar código subyacente y, en cambio, mantener toda mi separación en MVVM. En su TreeView añadir el siguiente XAML:

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="SelectedItemChanged"> 
     <i:InvokeCommandAction Command="{Binding TreeviewSelectedItemChanged}" CommandParameter="{Binding ElementName=treeView, Path=SelectedItem}"/> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

en su añadir cabecera xaml:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity" 

y entonces usted tiene que agregar una referencia al conjunto anterior en su proyecto.

Después de eso, todo actúa igual que cualquier otro comando con un botón o algo así.

+0

+1 - Esta es una gran respuesta ya que no es una solución de código subyacente. Sin embargo, esta no es una solución lista para usar :(. – TheCloudlessSky

+0

¿Se puede redistribuir 'System.Windows.Interactivity'? – AMissico

+0

Sí, vea" C: \ Archivos de programa (x86) \ Microsoft SDKs \ Expression \ Blend \. NETFramework \ v4.0 \ Redist.en.txt ". – AMissico

Cuestiones relacionadas