2013-10-16 94 views
5

當您單擊應用程序的圖標或在應用程序的標題欄上單擊鼠標右鍵時,我想調用ContextMenu在自定義窗口中啓動窗口的系統菜單

這是ContextMenu我的意思是:

enter image description here

我需要它,因爲我做的,就像窗口自定義控件。
我需要此行爲才能完成我的控制。

編輯:
利奧洛倫佐·路易斯問我代碼:

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

或:

我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> 

我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); 
     } 
    } 
} 

我的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> 

會感謝你的幫助。

+0

在您的自定義控件中,例如您分享的圖像,您可以使Visual Studio(圖標)成爲一個按鈕,並在點擊時顯示ContextMenu? –

+0

是的。我只需要知道如何調用特定的ContextMenu。我需要自己做一個還是我可以直接打給這個?(我的控制是基於窗口控制) – Ron

+0

請從你的問題中刪除多餘的代碼..這將幫助其他人迅速 – Nitin

回答

7

要顯示的菜單是系統ContextMenu。要使用該功能,您需要導入一些user32函數,如下面的代碼所示。我點擊了按鈕後啓動了系統菜單。您可以通過任何操作啓動它,右鍵單擊等。

GetSystemMenu獲取系統菜單,並使用TrackPopupMenuEx來顯示它。 PostMessage是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

已經非常接近我想要的東西。我有一個問題 - 即使窗口最大化時,最大化項目也是啓用的,關於恢復也是一樣的(當它不是最大化時) - 我如何強制它按照它應該的方式行事? – Ron

+0

更新的答案最大化菜單項啓用/禁用......同樣,你需要處理 – Nitin

+0

偉大工程等項目,但我希望它會自動檢測但無論如何,只要它的作品。非常感謝你! – Ron

0

在您的自定義控件中,例如您共享的圖像,使Visual Studio(圖標)成爲圖像按鈕/按鈕,並在點擊時從該處顯示ContextMenu。

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

然後在Click處理程序,只說buttonName.ContextMenu.IsOpen =真

更多關於你如何能做到這一點,可以發現here

已經有一個依賴屬性,你可以設置顯示上下文菜單。我不確定你的意思是「你需要自己製作一個還是你可以直接打電話給這個」

編輯:我不明白你爲什麼是重新創建而不是繼承你的自定義窗口添加到Window類並覆蓋您需要自定義的內容。

+0

得到的問題是,我可以看到你不明白我的正確。我知道如何製作ContextMenu並調用它。我不想讓我自己的ContextMenu,但使用的窗口的文本菜單(與恢復,移動,大小等等項目) - 我敢肯定有一種方法,但我不知道如何.. – Ron

+0

我剛編輯我的答案。 –

+0

看到它,第一我不知道我知道如何繼承。第二個我重寫了基於Windows 8設計http://stackoverflow.com/questions/19335343/wpf-net-framework-3-5-window-metro-style整個設計(由窗口 - 貓採取一些預先製作的,因爲他們的目標是框架4+,所以我必須做我自己的)+ overritten的一些功能(例如:當沒有最大化時添加邊框) – Ron