2012-01-22 14 views
13

Mam przycisk z obrazem jako jego zawartość na pasku narzędzi. Chciałbym, aby ten przycisk otwierał menu pod nim po kliknięciu. W jaki sposób?Jak otworzyć menu kontekstowe po kliknięciu przycisku?

<Toolbar> 
      <Button> 
       <Button.Content> 
        <Image Source="../Resources/help.png"></Image> 
       </Button.Content> 
      </Button> 
</Toolbar> 

Dzięki!

+5

Czy próbowałeś czegoś? –

Odpowiedz

1

Istnieje wiele sposobów, aby to zrobić, a może warto rozważyć to podejście ...

<ToolBar DockPanel.Dock="Top"> 
    <MenuItem IsSubmenuOpen="{Binding SomeProperty}"> 
     <MenuItem.Header> 
      <Button Height="28"> 
       <Button.Content> 
        <Image Source="---your image---"></Image> 
       </Button.Content> 
      </Button> 
     </MenuItem.Header> 
     <Menu> 
      <MenuItem Header="Do this" /> 
      <MenuItem Header="Do that"/> 
     </Menu> 
    </MenuItem> 
</ToolBar> 

ten owija swój przycisk na MenuItem który ma podmenu. Jak pokazano tutaj, właściwość o nazwie IsSubMenuOpen jest powiązana z powiadomioną właściwością typu bool w twoim ViewModelu o nazwie SomeProperty.

Musisz mieć swój ViewModel przełączać tę właściwość w zależności od tego, co faktycznie próbujesz zrobić. Możesz zastanowić się nad ustawieniem przycisku jako przełącznikiem, aby ułatwić zamknięcie podmenu, w przeciwnym razie będziesz musiał połączyć dodatkowe zachowanie w swoim ViewModelu.

8

Znalazłem dwa rozwiązania po wyszukaniu go:

1) Split Button in WPF

2) DropDownButtons in WPF

drugie rozwiązanie jest mój ulubiony (źródło pochodzi ze strony internetowej przez Andrew Wilkinson)

public class DropDownButton : ToggleButton 
{ 
    // *** Dependency Properties *** 

    public static readonly DependencyProperty DropDownProperty = 
    DependencyProperty.Register("DropDown", 
           typeof(ContextMenu), 
           typeof(DropDownButton), 
           new UIPropertyMetadata(null)); 

    // *** Constructors *** 

    public DropDownButton() { 
    // Bind the ToogleButton.IsChecked property to the drop-down's IsOpen property 

    Binding binding = new Binding("DropDown.IsOpen"); 
    binding.Source = this; 
    this.SetBinding(IsCheckedProperty, binding); 
    } 

    // *** Properties *** 

    public ContextMenu DropDown { 
    get { return (ContextMenu)this.GetValue(DropDownProperty); } 
    set { this.SetValue(DropDownProperty, value); } 
    } 

    // *** Overridden Methods *** 

    protected override void OnClick() { 
    if (this.DropDown != null) { 
     // If there is a drop-down assigned to this button, then position and display it 

     this.DropDown.PlacementTarget = this; 
     this.DropDown.Placement = PlacementMode.Bottom; 

     this.DropDown.IsOpen = true; 
    } 
    } 
} 

użycie

<ctrl:DropDownButton Content="Drop-Down"> 
    <ctrl:DropDownButton.DropDown> 
    <ContextMenu> 
     <MenuItem Header="Item 1" /> 
     <MenuItem Header="Item 2" /> 
     <MenuItem Header="Item 3" /> 
    </ContextMenu> 
    </ctrl:DropDownButton.DropDown> 
</ctrl:DropDownButton> 

nadzieję, że pomaga ...

+3

To podejście nie jest podobne do WPF - należy zastosować właściwość załączoną, a nie podklasę. Powody: 1. style już nie działają 2. możesz czerpać tylko z jednej klasy, ale mają wiele różnych załączonych właściwości na tym samym obiekcie – Mikhail

+0

@Mikhail masz rację, to był tylko przykład – punker76

+1

Jako początkujący WPF, są to również niezwykle trudno jest pracować. Tyle brakujących informacji. – Chris

30

Zamiast korzystać z podklasy Button, można użyć właściwości dołączonego lub zachowanie do wdrożenia rozwijane funkcjonalności przycisku, bardziej WPF podobnego podejścia i tak don „t wpłynąć przycisk styl:

using System.Windows.Interactivity; 

public class DropDownButtonBehavior : Behavior<Button> 
{ 
    private bool isContextMenuOpen; 

    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     AssociatedObject.AddHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click), true); 
    } 

    void AssociatedObject_Click(object sender, System.Windows.RoutedEventArgs e) 
    { 
     Button source = sender as Button; 
     if (source != null && source.ContextMenu != null) 
     { 
      if (!isContextMenuOpen) 
      { 
       // Add handler to detect when the ContextMenu closes 
       source.ContextMenu.AddHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed), true); 
       // If there is a drop-down assigned to this button, then position and display it 
       source.ContextMenu.PlacementTarget = source; 
       source.ContextMenu.Placement = PlacementMode.Bottom; 
       source.ContextMenu.IsOpen = true; 
       isContextMenuOpen = true; 
      } 
     }    
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     AssociatedObject.RemoveHandler(Button.ClickEvent, new RoutedEventHandler(AssociatedObject_Click)); 
    } 

    void ContextMenu_Closed(object sender, RoutedEventArgs e) 
    { 
     isContextMenuOpen = false; 
     var contextMenu = sender as ContextMenu; 
     if (contextMenu != null) 
     { 
      contextMenu.RemoveHandler(ContextMenu.ClosedEvent, new RoutedEventHandler(ContextMenu_Closed)); 
     } 
    } 
} 

Zastosowanie:

<!-- NOTE: xmlns:i="schemas.microsoft.com/expression/2010/interactivity‌​" --> 
<Button> 
    <i:Interaction.Behaviors> 
     <local:DropDownButtonBehavior/> 
    </i:Interaction.Behaviors> 
    <Button.Content> 
     <StackPanel Orientation="Horizontal"> 
      <Image Source="/DropDownButtonExample;component/Assets/add.png" SnapsToDevicePixels="True" Height="16" Width="16" /> 
      <TextBlock Text="Add"/> 
      <Separator Margin="2,0"> 
       <Separator.LayoutTransform> 
        <TransformGroup> 
         <TransformGroup.Children> 
          <TransformCollection> 
           <RotateTransform Angle="90"/> 
          </TransformCollection> 
         </TransformGroup.Children> 
        </TransformGroup> 
       </Separator.LayoutTransform> 
      </Separator> 
      <Path Margin="2" VerticalAlignment="Center" Width="6" Fill="#FF527DB5" Stretch="Uniform" HorizontalAlignment="Right" Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z "/> 
     </StackPanel> 
    </Button.Content> 
    <Button.ContextMenu> 
     <ContextMenu> 
      <MenuItem Header="Attribute"/> 
      <MenuItem Header="Setting"/> 
      <Separator/> 
      <MenuItem Header="Property"/> 
     </ContextMenu> 
    </Button.ContextMenu> 
</Button> 

Obecny GIST źródło i przykład here.

+2

To powinno być oznaczone jako odpowiedź, miłe schludne rozwiązanie! –

+0

Chciałbym, aby kliknięcie otworzyło się i ponownie zamknęło kliknięcie, tak jak rozwijane są przyciski dzielenia Visual Studio. Ta implementacja jest otwierana przy każdym kliknięciu. Próbowałem ustawić IsOpen =! IsOpen i zmieniałem po uruchomieniu zdarzenia (np. Na PreviewMouseDown), ale wydaje się, że menu kontekstowe jest zamknięte, zanim dotrze do zdarzenia kliknięcia. Czy potrafisz rozwiązać tę zagadkę? Nie jestem nawet pewien, czy można to zrobić w ramach zachowania. –

+0

To jest dobre pytanie. Ponieważ mówisz, że 'IsOpen =! IsOpen' nie działa, możesz dołączyć do zdarzeń ContextMenu' Open' i 'Closed', abyś mógł stwierdzić, czy ContextMenu jest rzeczywiście otwarte (zakładając, że przywoływana instancja ContextMenu się nie zmienia). Jeśli chodzi o to, dlaczego tak się dzieje, zakładam, że po ponownym naciśnięciu przycisku DropDownButton, menu kontekstowe traci ostrość i zamyka się, więc próba '! IsOpen' kończy się niepowodzeniem przed wykonaniem kodu zachowania. Byłoby interesujące zobaczyć, jak Visual Studio to robi. To powinno być znacznie łatwiejsze niż to. – Ryan

8

Jeśli masz luksus kierowania na platformę .NET 4 lub nowszą, nowa biblioteka wstążek ma taką możliwość, co RibbonMenuButton. W 4.5 jest to tak proste, jak odniesienie do System.Windows.Controls.Ribbon w twoim projekcie:

<RibbonMenuButton x:Name="ExampleMenu" SmallImageSource="/Images/Example.png"> 
    <RibbonMenuItem x:Name="ExampleMenuItem" Header="Save" /> 
</RibbonMenuButton> 
+0

Biblioteka wstążki dla WPF (zawiera link do pobrania dla .Net 4.0): https://msdn.microsoft.com/en-us/library/ff799534.aspx – Chris

Powiązane problemy