2013-10-16 20 views
5

Chciałbym zadzwonić pod numer ContextMenu po kliknięciu ikony aplikacji lub kliknięciu prawym klawiszem myszy na pasku tytułowym aplikacji.Menu systemowe okna uruchamiania w niestandardowym oknie

To ContextMenu To znaczy:

enter image description here

muszę, bo zrobiłem niestandardowej kontroli, który działa jak okno.
Potrzebuję tego zachowania, aby dokończyć kontrolę.

EDIT:
Leo Lorenzo Luis poprosił mnie kod:

https://skydrive.live.com/?cid=c3392940f5cf5f74&id=C3392940F5CF5F74%21107&authkey=!APd2X3tDxWRfpL4

czyli

Moja MainWindow.xaml:

<!--<Grid> 
     <Border Name="TopBorder" BorderThickness="0.5,0,0,0" BorderBrush="Blue"/> 
     <Border Name="RightBorder" BorderThickness="0,0.5,0,0" BorderBrush="Red"/> 
     <Border Name="BottomBorder" BorderThickness="0,0,0.5,0" BorderBrush="Green"/> 
     <Border Name="LeftBorder" BorderThickness="0,0,0,0.5" BorderBrush="Orange"/> 
     <Grid Margin="0.5"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
       <RowDefinition Height="*"/> 
      </Grid.RowDefinitions> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*"/> 
        <ColumnDefinition Width="Auto"/> 
       </Grid.ColumnDefinitions> 
       <StatusBar Background="Transparent" MouseDoubleClick="TriggerMaximize" MouseDown="StatusBar_MouseDown"> 
        <Image Margin="5,0,0,0" VerticalAlignment="Center" Width="16" Height="16" Source="{Binding Icon, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased"/> 
        <Label VerticalAlignment="Center" FontSize="14" Content="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/> 
       </StatusBar> 
       <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Column="1"> 
        <Button x:Name="Minimize" ToolTip="Minimize" Content="0" Style="{DynamicResource TitleBarButton}" Click="TriggerMinimize"/> 
        <Button x:Name="Restore" ToolTip="Restore" Content="2" Style="{DynamicResource TitleBarButton}" Visibility="Collapsed" Click="TriggerMaximize"/> 
        <Button x:Name="Maximize" ToolTip="Maximize" Content="1" Style="{DynamicResource TitleBarButton}" Click="TriggerMaximize"/> 
        <Button x:Name="Close" ToolTip="Close" Content="r" Style="{DynamicResource TitleBarButton}" Click="TriggerClose"/> 
       </StackPanel> 
      </Grid> 
     </Grid> 
    </Grid>--> 

    <DockPanel LastChildFill="true"> 
     <Border Name="TopBorder" DockPanel.Dock="Top" BorderBrush ="#007ACC" BorderThickness="0.5"/> 
     <Border Name="RightBorder" DockPanel.Dock="Right" BorderBrush ="#007ACC" BorderThickness="0.5"/> 
     <Border Name="BottomBorder" DockPanel.Dock="Bottom" BorderBrush ="#007ACC" BorderThickness="0.5"/> 
     <Border Name="LeftBorder" DockPanel.Dock="Left" BorderBrush="#007ACC" BorderThickness="0.5"/> 
     <Grid> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="Auto"/> 
       <RowDefinition Height="*"/> 
      </Grid.RowDefinitions> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*"/> 
        <ColumnDefinition Width="Auto"/> 
       </Grid.ColumnDefinitions> 
       <StatusBar Background="Transparent" MouseDoubleClick="TriggerMaximize" MouseDown="StatusBar_MouseDown"> 
        <Image Margin="5,0,0,0" Width="16" Height="16" Source="{Binding Icon, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" RenderOptions.BitmapScalingMode="NearestNeighbor" RenderOptions.EdgeMode="Aliased"/> 
        <Label VerticalAlignment="Center" FontSize="14" Content="{Binding Title, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"/> 
       </StatusBar> 
       <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Column="1"> 
        <Button x:Name="Minimize" ToolTip="Minimize" Content="0" Style="{DynamicResource TitleBarButton}" Click="TriggerMinimize"/> 
        <Button x:Name="Restore" ToolTip="Restore" Content="2" Style="{DynamicResource TitleBarButton}" Visibility="Collapsed" Click="TriggerMaximize"/> 
        <Button x:Name="Maximize" ToolTip="Maximize" Content="1" Style="{DynamicResource TitleBarButton}" Click="TriggerMaximize"/> 
        <Button x:Name="Close" ToolTip="Close" Content="r" Style="{DynamicResource TitleBarButton}" Click="TriggerClose"/> 
       </StackPanel> 
      </Grid> 
     </Grid> 
    </DockPanel> 
</Window> 

Moi MainWindow.cs (Code-Behind):

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Runtime.InteropServices; 
using System.Text; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.Windows.Documents; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Imaging; 
using System.Windows.Navigation; 
using System.Windows.Shapes; 
using System.Windows.Interop; 
using System.Windows.Forms; 

namespace WpfApplication16 
{ 
    /// <summary> 
    /// Interaction logic for MainWindow.xaml 
    /// </summary> 
    public partial class MainWindow : Window 
    { 
     public MainWindow() 
     { 
      InitializeComponent(); 
      this.SourceInitialized += new EventHandler(win_SourceInitialized); 
     } 

     private void TriggerMaximize(object sender, MouseButtonEventArgs e) 
     { 
      TriggerMaximize(); 
     } 

     private void TriggerMaximize(object sender, RoutedEventArgs e) 
     { 
      TriggerMaximize(); 
     } 

     private void TriggerMaximize() 
     { 
      if (WindowState == System.Windows.WindowState.Maximized) 
      { 
       WindowState = System.Windows.WindowState.Normal; 
       Restore.Visibility = Visibility.Collapsed; 
       Maximize.Visibility = Visibility.Visible; 
      } 
      else if (WindowState == System.Windows.WindowState.Normal) 
      { 
       WindowState = System.Windows.WindowState.Maximized; 
       Maximize.Visibility = Visibility.Collapsed; 
       Restore.Visibility = Visibility.Visible; 
      } 
     } 

     private void Window_LocationChanged(object sender, EventArgs e) 
     { 
      TriggerBorderChanges(); 
     } 


     private void Window_SizeChanged(object sender, SizeChangedEventArgs e) 
     { 
      TriggerBorderChanges(); 
     } 

     private void TriggerBorderChanges() 
     { 
      TopBorder.BorderThickness = new Thickness(0.5); 
      RightBorder.BorderThickness = new Thickness(0.5); 
      BottomBorder.BorderThickness = new Thickness(0.5); 
      LeftBorder.BorderThickness = new Thickness(0.5); 

      if (Top == 0) 
      { 
       TopBorder.BorderThickness = new Thickness(0); 
       BottomBorder.BorderThickness = new Thickness(0); 
      } 

      if (Left == 0) 
      { 
       LeftBorder.BorderThickness = new Thickness(0); 
      } 

      // need to test in dual view -if not needed, remove drawing and windows.forms (from refereance and from the using) 
      //Screen currentScreen = Screen.FromPoint(System.Windows.Forms.Cursor.Position); 
      //if (Left == (currentScreen.WorkArea.Width - Width)) 
      if (Left == (System.Windows.SystemParameters.WorkArea.Width - 1 - Width)) 
      { 
       RightBorder.BorderThickness = new Thickness(0); 
      } 
     } 

     private void TriggerClose(object sender, RoutedEventArgs e) 
     { 
      Close(); 
     } 

     private void TriggerMinimize(object sender, RoutedEventArgs e) 
     { 
      WindowState = System.Windows.WindowState.Minimized; 
     } 


     private void StatusBar_MouseDown(object sender, MouseButtonEventArgs e) 
     { 
      if (e.ChangedButton == MouseButton.Left) 
       this.DragMove(); 
     } 


     void win_SourceInitialized(object sender, EventArgs e) 
     { 
      System.IntPtr handle = (new WindowInteropHelper(this)).Handle; 
      HwndSource.FromHwnd(handle).AddHook(new HwndSourceHook(WindowProc)); 
     } 

     /// <summary> 
     /// POINT aka POINTAPI 
     /// </summary>5 
     [StructLayout(LayoutKind.Sequential)] 
     public struct POINT 
     { 
      /// <summary> 
      /// x coordinate of point. 
      /// </summary> 
      public int x; 
      /// <summary> 
      /// y coordinate of point. 
      /// </summary> 
      public int y; 

      /// <summary> 
      /// Construct a point of coordinates (x,y). 
      /// </summary> 
      public POINT(int x, int y) 
      { 
       this.x = x; 
       this.y = y; 
      } 
     } 

     [StructLayout(LayoutKind.Sequential)] 
     public struct MINMAXINFO 
     { 
      public POINT ptReserved; 
      public POINT ptMaxSize; 
      public POINT ptMaxPosition; 
      public POINT ptMinTrackSize; 
      public POINT ptMaxTrackSize; 
     }; 

     [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] 
     public class MONITORINFO 
     { 
      /// <summary> 
      /// </summary>    
      public int cbSize = Marshal.SizeOf(typeof(MONITORINFO)); 

      /// <summary> 
      /// </summary>    
      public RECT rcMonitor = new RECT(); 

      /// <summary> 
      /// </summary>    
      public RECT rcWork = new RECT(); 

      /// <summary> 
      /// </summary>    
      public int dwFlags = 0; 
     } 

     /// <summary> Win32 </summary> 
     [StructLayout(LayoutKind.Sequential, Pack = 0)] 
     public struct RECT 
     { 
      /// <summary> Win32 </summary> 
      public int left; 
      /// <summary> Win32 </summary> 
      public int top; 
      /// <summary> Win32 </summary> 
      public int right; 
      /// <summary> Win32 </summary> 
      public int bottom; 

      /// <summary> Win32 </summary> 
      public static readonly RECT Empty = new RECT(); 

      /// <summary> Win32 </summary> 
      public int Width 
      { 
       get { return Math.Abs(right - left); } // Abs needed for BIDI OS 
      } 

      /// <summary> Win32 </summary> 
      public int Height 
      { 
       get { return bottom - top; } 
      } 

      /// <summary> Win32 </summary> 
      public RECT(int left, int top, int right, int bottom) 
      { 
       this.left = left; 
       this.top = top; 
       this.right = right; 
       this.bottom = bottom; 
      } 

      /// <summary> Win32 </summary> 
      public RECT(RECT rcSrc) 
      { 
       this.left = rcSrc.left; 
       this.top = rcSrc.top; 
       this.right = rcSrc.right; 
       this.bottom = rcSrc.bottom; 
      } 

      /// <summary> Win32 </summary> 
      public bool IsEmpty 
      { 
       get 
       { 
        // BUGBUG : On Bidi OS (hebrew arabic) left > right 
        return left >= right || top >= bottom; 
       } 
      } 

      /// <summary> Return a user friendly representation of this struct </summary> 
      public override string ToString() 
      { 
       if (this == RECT.Empty) { return "RECT {Empty}"; } 
       return "RECT { left : " + left + "/top : " + top + "/right : " + right + "/bottom : " + bottom + " }"; 
      } 

      /// <summary> Determine if 2 RECT are equal (deep compare) </summary> 
      public override bool Equals(object obj) 
      { 
       if (!(obj is Rect)) { return false; } 
       return (this == (RECT)obj); 
      } 

      /// <summary>Return the HashCode for this struct (not garanteed to be unique)</summary> 
      public override int GetHashCode() 
      { 
       return left.GetHashCode() + top.GetHashCode() + right.GetHashCode() + bottom.GetHashCode(); 
      } 

      /// <summary> Determine if 2 RECT are equal (deep compare)</summary> 
      public static bool operator ==(RECT rect1, RECT rect2) 
      { 
       return (rect1.left == rect2.left && rect1.top == rect2.top && rect1.right == rect2.right && rect1.bottom == rect2.bottom); 
      } 

      /// <summary> Determine if 2 RECT are different(deep compare)</summary> 
      public static bool operator !=(RECT rect1, RECT rect2) 
      { 
       return !(rect1 == rect2); 
      } 
     } 

     [DllImport("user32")] 
     internal static extern bool GetMonitorInfo(IntPtr hMonitor, MONITORINFO lpmi); 

     [DllImport("User32")] 
     internal static extern IntPtr MonitorFromWindow(IntPtr handle, int flags); 

     private static System.IntPtr WindowProc(
       System.IntPtr hwnd, 
       int msg, 
       System.IntPtr wParam, 
       System.IntPtr lParam, 
       ref bool handled) 
     { 
      switch (msg) 
      { 
       case 0x0024: 
        WmGetMinMaxInfo(hwnd, lParam); 
        handled = true; 
        break; 
      } 

      return (System.IntPtr)0; 
     } 

     private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam) 
     { 
      MINMAXINFO mmi = (MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(MINMAXINFO)); 

      // Adjust the maximized size and position to fit the work area of the correct monitor 
      int MONITOR_DEFAULTTONEAREST = 0x00000002; 
      System.IntPtr monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST); 

      if (monitor != System.IntPtr.Zero) 
      { 

       MONITORINFO monitorInfo = new MONITORINFO(); 
       GetMonitorInfo(monitor, monitorInfo); 
       RECT rcWorkArea = monitorInfo.rcWork; 
       RECT rcMonitorArea = monitorInfo.rcMonitor; 
       mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left); 
       mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top); 
       mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left); 
       mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top); 
      } 

      Marshal.StructureToPtr(mmi, lParam, true); 
     } 
    } 
} 

My App.xaml:

<Application 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero" x:Class="WpfApplication16.App" 
      StartupUri="MainWindow.xaml"> 
    <Application.Resources> 


     <Style x:Key="TitleBarButton" TargetType="Button"> 
      <Setter Property="Foreground" Value="Black"/> 
      <Setter Property="Background" Value="Transparent"/> 
      <Setter Property="BorderThickness" Value="0"/> 
      <Setter Property="Padding" Value="12,7"/> 
      <Setter Property="FocusVisualStyle" Value="{x:Null}"/> 
      <Setter Property="FontFamily" Value="Marlett"/> 
      <Setter Property="FontSize" Value="12"/> 
      <Setter Property="Template"> 
       <Setter.Value> 
        <ControlTemplate TargetType="Button"> 
         <Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}"> 
          <Grid> 
           <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" TextBlock.FontFamily="{TemplateBinding FontFamily}" TextBlock.FontSize="{TemplateBinding FontSize}" /> 
          </Grid> 
         </Border> 
         <ControlTemplate.Triggers> 
          <Trigger Property="IsMouseOver" Value="True"> 
           <Setter Property="Background" Value="#EFEFF2" /> 
          </Trigger> 
          <Trigger Property="IsPressed" Value="True"> 
           <Setter Property="Background" Value="#007ACC"/> 
           <Setter Property="Foreground" Value="White"/> 
          </Trigger> 
         </ControlTemplate.Triggers> 
        </ControlTemplate> 
       </Setter.Value> 
      </Setter> 
     </Style> 

    </Application.Resources> 
</Application> 

Czy wdzięczni za pomoc.

+0

W swoim sterowaniu niestandardowym, takim jak obraz, który udostępniłeś, czy możesz uczynić Visual Studio (ikonę) przyciskiem i pokazać stamtąd Menu kontekstowe po kliknięciu? –

+0

Tak. Po prostu muszę wiedzieć, jak nazwać to konkretne Menu kontekstowe. Czy muszę go wykonać samodzielnie lub mogę zadzwonić bezpośrednio do tego?(moja kontrola opiera się na kontroli okna) – Ron

+0

proszę usunąć dodatkowy kod z pytania .. to pomoże innym szybko uzyskać odpowiedź na pytanie – Nitin

Odpowiedz

7

Menu, które chcesz wyświetlić, to system ContextMenu. Aby pracować z tym, musisz zaimportować niektóre funkcje user32, jak pokazano w poniższym kodzie. Uruchomiłem menu systemowe po kliknięciu przycisku. Możesz uruchomić go przy każdej akcji, prawym kliknięciu myszy itp.

GetSystemMenu otrzymuje menu systemowe, a do jego wyświetlania służy TrackPopupMenuEx. PostMessage to polecenie systemu wysyłania w menuitem.

public partial class Window3 : Window 
{ 

    private const int WM_SYSCOMMAND = 0x112; 
    uint TPM_LEFTALIGN = 0x0000; 
    uint TPM_RETURNCMD = 0x0100; 
    const UInt32 MF_ENABLED = 0x00000000; 
    const UInt32 MF_GRAYED = 0x00000001; 
    internal const UInt32 SC_MAXIMIZE = 0xF030; 
    internal const UInt32 SC_RESTORE = 0xF120; 

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert); 

    [DllImport("user32.dll")] 
    static extern int TrackPopupMenuEx(IntPtr hmenu, uint fuFlags, 
     int x, int y, IntPtr hwnd, IntPtr lptpm); 

    [DllImport("user32.dll")] 
    public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam); 

    [DllImport("user32.dll")] 
    static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, 
     uint uEnable); 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     WindowInteropHelper helper = new WindowInteropHelper(this); 
     IntPtr callingWindow = helper.Handle; 
     IntPtr wMenu = GetSystemMenu(callingWindow, false); 
     // Display the menu 
     if (this.WindowState == System.Windows.WindowState.Maximized) 
     { 
      EnableMenuItem(wMenu, SC_MAXIMIZE, MF_GRAYED); 
     } 
     else 
     { 
      EnableMenuItem(wMenu, SC_MAXIMIZE, MF_ENABLED); 
     } 

     int command = TrackPopupMenuEx(wMenu, TPM_LEFTALIGN | TPM_RETURNCMD, 100, 100, callingWindow, IntPtr.Zero); 
     if (command == 0) 
      return; 

     PostMessage(callingWindow, WM_SYSCOMMAND, new IntPtr(command), IntPtr.Zero); 
    } 
+0

Bardzo blisko do tego, co chcę. Mam jeden problem - element maksymalizacji jest włączony, nawet gdy okno jest zmaksymalizowane, to samo dotyczy przywracania (gdy nie jest zmaksymalizowane) - jak mogę zmusić go do działania tak, jak powinien? – Ron

+0

zaktualizowana odpowiedź dla zmaksymalizowania menuitem włącz/wyłącz ... podobnie będziesz potrzebować obsługiwać inne elementy – Nitin

+0

Działa świetnie, chociaż miałem nadzieję, że wykryje to automatycznie, ale niezależnie od tego, jak długo działa. Dziękuję Ci bardzo! – Ron

0

W formancie niestandardowym, takim jak obraz, który udostępniono, ustaw Visual Studio (ikonę) jako przycisk/przycisk obrazka i pokaż stamtąd ContextMenu po kliknięciu.

<Button Click="SomeEventHandler"> 
    <Button.ContextMenu> 
    <ContextMenu> 
     <!-- DO WHATEVER --> 
    </ContextMenu> 
    </Button.ContextMenu> 
</Button> 

Następnie na przewodnika Click, wystarczy powiedzieć buttonName.ContextMenu.IsOpen = true

Więcej w jaki sposób można to osiągnąć można znaleźć here

Istnieje już właściwość zależność, że możesz ustawić, aby wyświetlało menu kontekstowe. Nie jestem pewien, co masz na myśli, mówiąc: "Czy musisz zrobić to samemu lub możesz zadzwonić bezpośrednio do tego"

Edycja: Nie rozumiem, dlaczego jestodtworzenie zachowania okna zamiast dziedziczenia niestandardowego okno do klasy okna i nadpisaj to, co musisz dostosować.

+0

Tak, widzę, że nie zrozumiałeś mnie poprawnie. Wiem, jak zrobić ContextMenu i zadzwonić do niego. Nie chcę tworzyć własnego ContextMenu, ale używać ContextMenu okna (z przywracaniem, przenoszeniem, wielkością itp.) ... - Jestem pewien, że jest sposób, ale nie wiem jak ... – Ron

+0

Właśnie zredagowałem swoją odpowiedź. –

+0

Widziałem to, 1. Nie jestem pewien, czy wiem, jak odziedziczyć. 2. Zastąpiłem cały projekt (wykonałem Window oparty na Windows 8 Design http://stackoverflow.com/questions/19335343/wpf-net-framework-3-5-window-meto-style - cat weź coś z góry, ponieważ ich celem jest framework 4+, więc musiałem zrobić własne) + przesłoniłem niektóre funkcje (na przykład: dodawaj ramki, gdy nie są zmaksymalizowane). – Ron

Powiązane problemy