19、Context Menu

1、Show a context menu:

     鼠标右键单击图片会显示一个 上下文菜单 (context menu)。使用手势,如 press-and-hould 手势也会触发显示这个菜单。

右键单击应用中的图片(类似于word文档的图标),会在图片的上面显示这个上下文菜单。

图片的  xaml :

<Image x:Name="AttachmentImage" Grid.Row="1" HorizontalAlignment="Left" Stretch="None" 
          Source="Assets/attachment.png"  RightTapped="AttachmentImage_RightTapped"/> //右键单击 或者 手指按住保持

//用来显示命令执行的状态 
<TextBlock x:Name="OutputTextBlock" TextWrapping="Wrap"/>

 相应的 C# 代码:

        private async void AttachmentImage_RightTapped(object sender, RightTappedRoutedEventArgs e)
        {
            // 向菜单中添加按钮,并且指定命令的回调
             // 因为命令的委托是独一无二的,不需要指定命令id。           
             var menu = new PopupMenu();
            menu.Commands.Add(new UICommand("Open with", (command) =>
            {
                  // command.Label : 获取或设置命令的标签。
                    OutputTextBlock.Text = "'" + command.Label + "' selected";
            }));
            menu.Commands.Add(new UICommand("Save attachment", (command) =>
            {
                OutputTextBlock.Text = "'" + command.Label + "' selected";
            }));

           // menu.ShowForSelectionAsync() :  显示指定选择上方的上下文菜单。如果未调用命令将返回 null。
              var chosenCommand = await menu.ShowForSelectionAsync(GetElementRect((FrameworkElement)sender));
            if (chosenCommand == null) 
            {
                //菜单隐藏时, 没有调用命令,
            }
        }

         //获取当前图片所占用的矩形区域
          public static Rect GetElementRect(FrameworkElement element)
        {
           //返回变换对象,该变换对象可用于将 UIElement 中的坐标变换为指定的对象。
            GeneralTransform buttonTransform = element.TransformToVisual(null);

           // 变换指定的点并返回结果。
            Point point = buttonTransform.TransformPoint(new Point());
          return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
        }

 2、Replace a default context menu :

       本示例讲述了,根据选择文本框中的文字之后,对选择文字弹出上下文菜单,效果如图:

     文本框的 xaml :

 <TextBox x:Name="ReadOnlyTextBox" Grid.Row="1" IsReadOnly="True" TextWrapping="Wrap" 
                          Text="Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
                         sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." 
                         // 在系统处理显示上下文菜单的交互时发生。
                         ContextMenuOpening="ReadOnlyTextBox_ContextMenuOpening"/>

 相应的 C# :

       private async void ReadOnlyTextBox_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            e.Handled = true;
            TextBox textbox = (TextBox)sender;
            if (textbox.SelectionLength > 0)
            {
                // 创建一个菜单并且为添加的命令指定一个id值,从而取代为每个命令指定委托。
                  var menu = new PopupMenu();
                menu.Commands.Add(new UICommand("Copy", null, 1));
                menu.Commands.Add(new UICommandSeparator());
                menu.Commands.Add(new UICommand("Highlight", null, 2));
                menu.Commands.Add(new UICommand("Look up", null, 3));

               // 调用下面的 GetTextboxSelectionRect 方法,返回选择文字的矩形代表选择区域。
                 // 注意:这段代码只处理与一行文本框。如果一个文本框有多个行,
               //按照惯例,应该把上下文菜单放置在光标/指针位置 

Rect rect = GetTextboxSelectionRect(textbox); //为选择内容选择上下文菜单 var chosenCommand = await menu.ShowForSelectionAsync(rect); if (chosenCommand != null) { switch ((int)chosenCommand.Id) { case 1:
String selectedText
= ((TextBox)sender).SelectedText; var dataPackage = new DataPackage(); dataPackage.SetText(selectedText); Clipboard.SetContent(dataPackage); OutputTextBlock.Text = "'" + chosenCommand.Label + "'(" + chosenCommand.Id.ToString() + ") selected; '"
+ selectedText + "' copied to clipboard"; break; case 2: OutputTextBlock.Text = "'" + chosenCommand.Label + "'(" + chosenCommand.Id.ToString() + ") selected"; break; case 3: OutputTextBlock.Text = "'" + chosenCommand.Label + "'(" + chosenCommand.Id.ToString() + ") selected"; break; } } else { //上下文菜单消失时进行处理 } } else { //因为没有选中文本内容,所以不会显示上下文菜单 } }
       //返回一个矩形为选中的文本
        private Rect GetTextboxSelectionRect(TextBox textbox)
        {
            Rect rectFirst, rectLast;
            if (textbox.SelectionStart == textbox.Text.Length)
            {
// 摘要:
//     以指定的字符索引返回字符前边缘或后边缘的矩形区域。
   
// 参数:
   
  //   charIndex:
    
   //     要检索其边框的字符的索引,该索引从零开始。
   
  
//   trailingEdge:
    
//     如果获取后边缘,则为 true;如果获取前边缘,则为 false。
  
     //


  // 返回结果:

 
//     指定索引处字符边缘的边框。
     
rectFirst
= textbox.GetRectFromCharacterIndex(textbox.SelectionStart - 1, true); } else { rectFirst = textbox.GetRectFromCharacterIndex(textbox.SelectionStart, false); } int lastIndex = textbox.SelectionStart + textbox.SelectionLength; if (lastIndex == textbox.Text.Length) { rectLast = textbox.GetRectFromCharacterIndex(lastIndex - 1, true); } else { rectLast = textbox.GetRectFromCharacterIndex(lastIndex, false); } GeneralTransform buttonTransform = textbox.TransformToVisual(null); Point point = buttonTransform.TransformPoint(new Point()); //确保我们返回一个有效的矩形如果选择是为多行 //,最终的选择是左边的开始的选择。 double x, y, dx, dy; y = point.Y + rectFirst.Top; dy = rectLast.Bottom - rectFirst.Top; if (rectLast.Right > rectFirst.Left) { x = point.X + rectFirst.Left; dx = rectLast.Right - rectFirst.Left; } else { x = point.X + rectLast.Right; dx = rectFirst.Left - rectLast.Right; } return new Rect(x, dx, y, dy); }
原文地址:https://www.cnblogs.com/hebeiDGL/p/2694095.html