2010-01-04 18 views
20

Todavía estoy trabajando en modificar mi aplicación WPF existente para que sea "compatible" con el enfoque MVVM. Me estoy acercando bastante, pero no estoy seguro de cómo resolver uno de los pocos obstáculos restantes.MVVM + WPF + Popup = sin pista

Tengo un elemento GUI (actualmente un botón, aunque podría ser una etiqueta), donde cuando el mouse lo ingresa, dispara el evento MouseEnter, y esto crea una ventana emergente en el código subyacente. La ventana emergente se compone de un diseño de panel de pila simple con varios botones. El evento Click de cada botón se asigna actualmente al mismo controlador de eventos, excepto que cambio la propiedad Tag para hacer un parámetro de comando simple (cursi). Estoy luchando con la forma "correcta" de hacer esto en MVVM, porque la forma en que lo estoy haciendo ahora es bastante fea.

Para resolver esto, creo que esta es la dirección que debo seguir, pero agradecería cualquier aporte adicional que me pueda ofrecer. :)

  1. Crear ventana emergente en XAML. Como mi contenido Popup es estático, debería poder crear el Popup completamente en XAML. Además, cada botón estaría vinculado a la misma clase derivada de ICommand. p.ej.

    <Popup x:Key="MyPopup" StaysOpen="False" Placement="Right"> 
        <Border Background="White" BorderBrush="Black" Padding="5" BorderThickness="2" CornerRadius="5"> 
         <StackPanel Orientation="Vertical"> 
          <Button Command="{Binding MyCommand}" CommandParameter="5">5</Button> 
          <Button Command="{Binding MyCommand}" CommandParameter="10">10</Button> 
          <Button Command="{Binding MyCommand}" CommandParameter="15">15</Button> 
          <Button Command="{Binding MyCommand}" CommandParameter="20">20</Button> 
         </StackPanel> 
        </Border> 
    </Popup> 
    
  2. hacen el estallido emergente arriba a través de un disparador, por ejemplo,

         <Button.Triggers> 
              <Trigger Property="Button.IsMouseOver" Value="True"> 
               <Setter TargetName="MyPopup" Property="IsOpen" Value="True" /> 
              </Trigger> 
             </Button.Triggers> 
    

Yo creo # 1 está bien, pero estoy luchando con # 2. ¿Es esta la manera correcta de abordar el problema? Y si es así, ¿cuál es la sintaxis correcta de XAML para que la propiedad IsOpen de Popup se establezca en True? No pude encontrar ejemplos para esto.

Si mi pensamiento es defectuoso, me gustaría saber cuáles son mis otras opciones. ¡Gracias!

+0

No veo cuál es el problema con su # 2, quizás pueda proporcionar más detalles sobre lo que piensa que está mal con él. –

+0

Recibo el error "El miembro 'IsOpen' no es válido porque no tiene un nombre de tipo calificado." – Dave

+0

También probé Popup.IsOpen y obtuve el mismo error. – Dave

Respuesta

17

Esto es lo que haría, primero separaría mis partes reutilizables en recursos, y las referenciaría usando ContentControls en XAML. Esto se aplica al Popup, así como al Button. Sin embargo no quiero limitarme a tener sólo un botón, por lo que voy a utilizar un ContentControl, así como para que:

La plantilla emergente:

<ControlTemplate x:Key="PopupTemplate"> 
    <Border 
       Background="White" 
       BorderBrush="Black" 
       Padding="5" 
       BorderThickness="2" 
       CornerRadius="5"> 
     <StackPanel Orientation="Vertical"> 
      <Button Command="{Binding MyCommand}" 
          CommandParameter="5">5</Button> 
      <Button Command="{Binding MyCommand}" 
          CommandParameter="10">10</Button> 
      <Button Command="{Binding MyCommand}" 
          CommandParameter="15">15</Button> 
      <Button Command="{Binding MyCommand}" 
          CommandParameter="20">20</Button> 
     </StackPanel> 
    </Border> 
</ControlTemplate> 

La plantilla ContentControl:

<ControlTemplate x:Key="MyControlTemplate" TargetType="ContentControl"> 
    <Grid Name="MyControl"> 
     <ContentPresenter Content="{TemplateBinding Content}"/> 
     <Popup Name="MyPopup" StaysOpen="True" Placement="Bottom"> 
      <ContentControl Template="{StaticResource PopupTemplate}"/> 
     </Popup> 
    </Grid> 
    <ControlTemplate.Triggers> 
     <Trigger SourceName="MyControl" 
       Property="UIElement.IsMouseOver" 
       Value="True"> 
      <Setter TargetName="MyPopup" 
        Property="Popup.IsOpen" 
        Value="True"/> 
     </Trigger> 
    </ControlTemplate.Triggers> 
</ControlTemplate> 

Ahora en el XAML de la ventana principal, que crearía la siguiente:

<ContentControl Template="{StaticResource MyControlTemplate}"> 
    <Button Content="Test"/> 
</ContentControl> 

Si tiene alguna pregunta, estaremos encantados de responderle.

+1

¡Gracias por la ayuda! Definitivamente parece una buena dirección para entrar. ¡Te dejaré saber cómo va! – Dave

+0

¡Está casi funcionando! Mi único problema ahora es que cuando hago clic en otro lugar en la GUI, desaparece la ventana emergente (que es lo que quiero), pero cuando vuelvo a pasar sobre ContentControl, la ventana emergente no aparece de nuevo. ¿Tengo que establecer explícitamente IsOpen en False en otro desencadenador?Lo ideal sería que desapareciera Popup si hago clic en algún lugar que * no * sea Popup o ContentControl (es decir, algún tipo de disparador compuesto/múltiple). – Dave

+0

Creo que el problema podría ser que está configurando 'IsOpen' como falso en algún lugar explícitamente, anulando así el desencadenador. ¿Estás haciendo esto en código subyacente? Tal vez en los controladores para las asociaciones de comandos en los botones emergentes? Si es así, entonces necesita borrar su valor para volver a activar el desencadenador ... Esto podría ser complicado. –