图解使用Win8Api进行Metro风格的程序开发十二上下文菜单

  我们紧接着上篇,这篇将介绍如何使用Windows.UI.Popups API,创建PopupMenu菜单
和处理oncontextmenu事件.
-----------------------------------我是华丽的分割线-----------------------------------------
我们紧接着上篇,这篇将介绍如何使用Windows.UI.Popups API,创建PopupMenu菜单
和处理oncontextmenu事件.

本篇将介绍如下2个方面:
  a)为一个文件创建一个上下文菜单
  b)在显示文本中替换原来的上下文菜单

我们的创建的步骤如下:
  1)为了组织文件方便,我们先建一个文件夹ContextMenu
  2)向文件夹中添加如下文件:
    ShowAContextMenu.xaml,ReplaceADefaultContextMenu.xaml
  创建方法请参照前一篇.
3)此时的解决方案结构如下:

4)向我们的DataSource添加导航所需要的信息
  修改我们的SampleDataSource.cs文件中的SampleDataSource类中的代码,
  代码如下: 

View Code
        public SampleDataSource()
        {
            #region Group1
            var group1 = new SampleDataGroup("FilePicker",
              "Use Windows.Storage.Pickers API",
              "Access and save files using the file picker",
              "Assets/FilePicker.jpg",
              "");
            group1.Items.Add(new SampleDataItem("FilePicker-PickASinglePhoto",
                    "Pick a single photo",
                    "only one file can selected,file type is jpg,jpeg,png",
                    "Assets/FilePicker.jpg",
                    "only one file can selected ",
                    "",
                    group1,
                    typeof(PickASinglePhoto)));
            group1.Items.Add(new SampleDataItem("FilePicker-PickMultipleFiles",
                    "Pick multiple files",
                    "you can pick multiple files",
                    "Assets/FilePicker.jpg",
                    "pick multiple files",
                    "",
                    group1,
                    typeof(PickMultipleFiles)));
            group1.Items.Add(new SampleDataItem("FilePicker-PickAFolder",
                    "Pick a folder",
                    "you can pick a folder",
                    "Assets/FilePicker.jpg",
                    "Pick a folder",
                    "",
                    group1,
                    typeof(PickAFolder)));
            group1.Items.Add(new SampleDataItem("FilePicker-SaveAFile",
                    "Save a file",
                    "you can save a file",
                    "Assets/FilePicker.jpg",
                    "Save a file",
                    "",
                    group1,
                    typeof(SaveAFile)));
            this.AllGroups.Add(group1);
            #endregion

            #region Group2
            var group2 = new SampleDataGroup("FileAceess",
           "Using Windows.Storage API",
           "File access",
           "Assets/FileAccess.jpg",
           "");
            group2.Items.Add(new SampleDataItem("FileAceess-CreatingAFile",
                    "Create a file",
                    "Using CreateFileAsync Create a file",
                    "Assets/FileAccess.jpg",
                    "Using CreateFileAsync",
                    "",
                    group2,
                    typeof(CreatingAFile)));

            group2.Items.Add(new SampleDataItem("FileAceess-WritingAndReadingText",
               "Write And Read A Text",
               "Using WriteTextAsync,ReadTextAsync Write And Read  Text",
               "Assets/FileAccess.jpg",
               "Using WriteTextAsync,ReadTextAsync",
               "",
               group2,
               typeof(WritingAndReadingText)));

            group2.Items.Add(new SampleDataItem("FileAceess-WritingAndReadingBytes",
              "Writing and reading bytes in a file",
              "Using WriteBufferAsync,ReadBufferAsync Write And Read bytes",
              "Assets/FileAccess.jpg",
              "Using WriteBufferAsync,ReadBufferAsync",
              "",
              group2,
              typeof(WritingAndReadingBytes)));

            group2.Items.Add(new SampleDataItem("FileAceess-WritingAndReadingUsingStream",
                "Writing and reading using a stream",
                "Using OpenAsync Writing and reading using a stream",
                "Assets/FileAccess.jpg",
                "Using OpenAsync",
                "",
                group2,
                typeof(WritingAndReadingUsingStream)));

            group2.Items.Add(new SampleDataItem("FileAceess-DisplayingFileProperties",
                "Displaying file properties",
                "Using GetBasicPropertiesAsync  Get File Properties",
                "Assets/FileAccess.jpg",
                "Using GetBasicPropertiesAsync",
                "",
                group2,
                typeof(DisplayingFileProperties)));

            group2.Items.Add(new SampleDataItem("FileAceess-PersistingAccess",
                "Persisting access to a storage item for future use",
                "Using MostRecentlyUsedList",
                "Assets/FileAccess.jpg",
                "Using MostRecentlyUsedList",
                "",
                group2,
                typeof(PersistingAccess)));

            group2.Items.Add(new SampleDataItem("FileAceess-CopyAFile",
                "Copy a file",
                "Using CopyAsync Copy a file",
                "Assets/FileAccess.jpg",
                "Using CopyAsync",
                "",
                group2,
                typeof(CopyAFile)));

            group2.Items.Add(new SampleDataItem("FileAceess-DeleteAFile",
                "Delete a file",
                "Using DeleteAsync Delete a file",
                "Assets/FileAccess.jpg",
                "Using DeleteAsync",
                "",
                group2,
                typeof(DeleteAFile)));

            this.AllGroups.Add(group2);
            #endregion

            #region Group3
            var group3 = new SampleDataGroup("AccountPictureName",
              "Use Windows.System.UserProfile API",
              "Account Picture Name",
              "Assets/AccountPictureName.jpg",
              "");
            group3.Items.Add(new SampleDataItem("AccountPictureName-GetUserDisplayName",
                    "Get User DisplayName",
                    "Use UserInformation.GetDisplayNameAsync Get User DisplayName",
                    "Assets/AccountPictureName.jpg",
                    "Use UserInformation.GetDisplayNameAsync",
                    "",
                    group3,
                    typeof(GetUserDisplayName)));
            group3.Items.Add(new SampleDataItem("AccountPictureName-GetUserFirstLastName",
                    "Get First Last Name",
                    "Use UserInformation.GetFirstNameAsync,GetLastNameAsync Get First Name",
                    "Assets/AccountPictureName.jpg",
                    "Use UserInformation.GetFirstNameAsync ",
                    "",
                    group3,
                    typeof(GetUserFirstLastName)));
            group3.Items.Add(new SampleDataItem("AccountPictureName-GetAccountPicture",
                    "Get Account Picture",
                    "Use UserInformation.GetAccountPicture Get Account Picture",
                    "Assets/AccountPictureName.jpg",
                    "Use UserInformation.GetAccountPicture",
                    "",
                    group3,
                    typeof(GetAccountPicture)));
            group3.Items.Add(new SampleDataItem("AccountPictureName-SetAccountPictureAndListen",
                    "Set AccountPicture And Listen",
                    "Use UserInformation.SetAccountPicturesAsync Set AccountPicture",
                    "Assets/AccountPictureName.jpg",
                    "Use UserInformation.SetAccountPicturesAsync",
                    "",
                    group3,
                    typeof(SetAccountPictureAndListen)));
            this.AllGroups.Add(group3);
            #endregion

            #region Group4
            var group4 = new SampleDataGroup("ApplicationSettings",
              "ApplicationSettings",
              " Use the Windows.UI.ApplicationSettings namespace and WinJS.UI.SettingsFlyout",
              "Assets/ApplicationSettings.jpg",
              "");
            group4.Items.Add(new SampleDataItem("ApplicationSettings-Default",
                    "Default behavior with no settings integration",
                    "Default behavior ",
                    "Assets/ApplicationSettings.jpg",
                    "Default behavior with no settings integration",
                    "",
                    group4,
                    typeof(Default)));
            group4.Items.Add(new SampleDataItem("ApplicationSettings-AddSettings",
                    "Add settings commands to the settings charm",
                    "Add settings",
                    "Assets/ApplicationSettings.jpg",
                    "Add settings commands to the settings charm ",
                    "",
                    group4,
                    typeof(AddSettings)));

            this.AllGroups.Add(group4);
            #endregion

            #region Group5
            var Group5 = new SampleDataGroup("AssociationLaunching",
              "Use Windows.System.Launcher API",
              "Association Launching",
              "Assets/AssociationLaunching.jpg",
              "");
            Group5.Items.Add(new SampleDataItem("AssociationLaunching-LaunchFile",
                    "Launching a file",
                    "Use Windows.System.Launcher.LaunchFileAsync",
                    "Assets/AssociationLaunching.jpg",
                    "Use Windows.System.Launcher.LaunchFileAsync",
                    "",
                    Group5,
                    typeof(LaunchFile)));
            Group5.Items.Add(new SampleDataItem("AssociationLaunching-LaunchUri",
                    "Launching a URI",
                    "Use Windows.System.Launcher.LaunchUriAsync",
                    "Assets/AssociationLaunching.jpg",
                    "Use Windows.System.Launcher.LaunchUriAsync",
                    "",
                    Group5,
                    typeof(LaunchUri)));
            Group5.Items.Add(new SampleDataItem("AssociationLaunching-ReceiveFile",
                    "Receiving a file",
                    "Receiving a file",
                    "Assets/AssociationLaunching.jpg",
                    "Receiving a file",
                    "",
                    Group5,
                    typeof(ReceiveFile)));
            Group5.Items.Add(new SampleDataItem("AssociationLaunching-ReceiveUri",
                    "Receiving a URI",
                    "Receiving a URI",
                    "Assets/AssociationLaunching.jpg",
                    "Receiving a URI",
                    "",
                    Group5,
                    typeof(ReceiveUri)));
            this.AllGroups.Add(Group5);
            #endregion

            #region Group6
            var Group6 = new SampleDataGroup("BackgroundTransfer",
              "Use Windows.Networking.BackgroundTransfer API",
              "BackgroundDownloader And BackgroundUploader",
              "Assets/BackgroundTransfer.jpg",
              "");
            Group6.Items.Add(new SampleDataItem("BackgroundTransfer-DownloadFile",
                    "Download Files",
                    "Use BackgroundDownloader",
                    "Assets/BackgroundTransfer.jpg",
                    "BackgroundDownloader",
                    "",
                    Group6,
                    typeof(DownloadFile)));
            Group6.Items.Add(new SampleDataItem("BackgroundTransfer-UploadFile",
                    "Upload Files",
                    "Use BackgroundUploader",
                    "Assets/BackgroundTransfer.jpg",
                    "BackgroundUploader",
                    "",
                    Group6,
                    typeof(UploadFile)));

            this.AllGroups.Add(Group6);
            #endregion

            #region Group7
            var Group7 = new SampleDataGroup("Clipboard",
              "Use Windows.ApplicationModel.DataTransfer API",
              "ClipboardOperation",
              "Assets/Clipboard.jpg",
              "");
            Group7.Items.Add(new SampleDataItem("Clipboard-CopyAndPasteText",
                    "Copy and paste text",
                    "Use Clipboard.GetContent,Clipboard.SetContent",
                    "Assets/Clipboard.jpg",
                    "Clipboard.GetContent,Clipboard.SetContent",
                    "",
                    Group7,
                    typeof(CopyAndPasteText)));
            Group7.Items.Add(new SampleDataItem("Clipboard-CopyAndPasteImage",
                    "Copy and paste an image",
                    "Use Clipboard.GetContent,Clipboard.SetContent",
                    "Assets/Clipboard.jpg",
                    "Clipboard.GetContent,Clipboard.SetContent",
                    "",
                    Group7,
                    typeof(CopyAndPasteImage)));
            Group7.Items.Add(new SampleDataItem("Clipboard-CopyAndPasteFile",
                    "Copy and paste files",
                    "Use Clipboard.GetContent,Clipboard.SetContent",
                    "Assets/Clipboard.jpg",
                    "Clipboard.GetContent,Clipboard.SetContent",
                    "",
                    Group7,
                    typeof(CopyAndPasteFile)));
            Group7.Items.Add(new SampleDataItem("Clipboard-OtherClipboardOperation",
                    "Other Clipboard operations",
                    "Use Clipboard.GetContent,Clipboard.SetContent",
                    "Assets/Clipboard.jpg",
                    "Clipboard.GetContent,Clipboard.SetContent",
                    "",
                    Group7,
                    typeof(OtherClipboardOperation)));

            this.AllGroups.Add(Group7);
            #endregion

            #region Group8
            var Group8 = new SampleDataGroup("Compression",
              "Use Windows.Storage.Compression API",
              "Compression And Decompression",
              "Assets/Compression.jpg",
              "");
            Group8.Items.Add(new SampleDataItem("Compression-CompressionAndDecompression",
                    "Compression And Decompression",
                    "Use Windows.Storage.Compression API",
                    "Assets/Compression.jpg",
                    "Compression And Decompression",
                    "",
                    Group8,
                    typeof(CompressionAndDecompression)));

            this.AllGroups.Add(Group8);
            #endregion

            #region Group9
            var Group9 = new SampleDataGroup("MediaButtons",
              "Use Windows.Media API",
              "Media Buttons",
              "Assets/MediaButtons.jpg",
              "");
            Group9.Items.Add(new SampleDataItem("MediaButtons-MediaEvents",
                    "Media Events",
                    "Use Windows.Media API",
                    "Assets/MediaButtons.jpg",
                    "Listening to hardware media transport events",
                    "",
                    Group9,
                    typeof(MediaEvents)));

            this.AllGroups.Add(Group9);
            #endregion

            #region Group10
            var Group10 = new SampleDataGroup("ContactPicker",
              "Use Windows.ApplicationModel.Contacts API",
              "Contact Picker",
              "Assets/ContactPicker.jpg",
              "");
            Group10.Items.Add(new SampleDataItem("ContactPicker-SinglePicker",
                    "Pick a single contact",
                    "Use ContactPicker.PickSingleContactAsync()",
                    "Assets/ContactPicker.jpg",
                    "PickSingleContactAsync",
                    "",
                    Group10,
                    typeof(SinglePicker)));
            Group10.Items.Add(new SampleDataItem("ContactPicker-MultiplePicker",
                    "Pick multiple contacts",
                    "Use ContactPicker.PickMultipleContactsAsync()",
                    "Assets/ContactPicker.jpg",
                    "PickMultipleContactsAsync",
                    "",
                    Group10,
                    typeof(MultiplePicker)));

            this.AllGroups.Add(Group10);
            #endregion

            #region Group11
            var Group11 = new SampleDataGroup("ContextMenu",
              "Use Windows.UI.Popups API",
              "Context Menu",
              "Assets/ContextMenu.jpg",
              "");
            Group11.Items.Add(new SampleDataItem("ContextMenu-ShowAContextMenu",
                    "Show a context menu",
                    "Show a context menu",
                    "Assets/ContextMenu.jpg",
                    "Show a context menu",
                    "",
                    Group11,
                    typeof(ShowAContextMenu)));
            Group11.Items.Add(new SampleDataItem("ContextMenu-ReplaceADefaultContextMenu",
                    "Replace a default context menu",
                    "Replace a default context menu",
                    "Assets/ContextMenu.jpg",
                    "Replace a default context menu",
                    "",
                    Group11,
                    typeof(ReplaceADefaultContextMenu)));

            this.AllGroups.Add(Group11);
            #endregion
        }

5)我们的导航这样就做好了,效果图:

  点击 ContextMenu

6)为一个文件创建一个上下文菜单
  我们使用控件的RightTapped事件,来处理右击,然后在右击的位置创建一个PopupMenu,
  使用PopupMenu的ShowForSelectionAsync方法显示上下文菜单。
  修改ShowAContextMenu.xaml的xaml

View Code
   <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid x:Name="Input" Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <TextBlock Grid.Row="0" Style="{StaticResource SubheaderTextStyle}" TextWrapping="Wrap">
                Right-click the image to show a simple context menu. Using touch, the press-and-hold gesture will also trigger the context menu.
            </TextBlock>
            <Image x:Name="AttachmentImage" Grid.Row="1" HorizontalAlignment="Left" Stretch="None" Source="../Assets/logo.jpg" />
        </Grid>

        <Grid x:Name="Output" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top">
            <TextBlock x:Name="OutputTextBlock" Style="{StaticResource SubheaderTextStyle}" TextWrapping="Wrap"/>
        </Grid>
    </Grid>

  修改后台代码:

View Code
    public sealed partial class ShowAContextMenu : Page
    {
        public ShowAContextMenu()
        {
            this.InitializeComponent();
            //注册右击事件
            AttachmentImage.RightTapped += new RightTappedEventHandler(AttachmentImage_RightTapped);
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        private async void AttachmentImage_RightTapped(object sender, RightTappedRoutedEventArgs e)
        {
            // Create a menu and add commands specifying a callback delegate for each.
            // Since command delegates are unique, no need to specify command Ids.
            var menu = new PopupMenu();
            menu.Commands.Add(new UICommand("Open with", (command) =>
            {
                OutputTextBlock.Text = "'" + command.Label + "' selected";
            }));
            menu.Commands.Add(new UICommand("Save attachment", (command) =>
            {
                OutputTextBlock.Text = "'" + command.Label + "' selected";
            }));

            // We don't want to obscure content, so pass in a rectangle representing the sender of the context menu event.
            // We registered command callbacks; no need to handle the menu completion event
            OutputTextBlock.Text = "Context menu shown";
            //显示上下文菜单
            var chosenCommand = await menu.ShowForSelectionAsync(GetElementRect((FrameworkElement)sender));
            if (chosenCommand == null) // The command is null if no command was invoked.
            {
                OutputTextBlock.Text = "Context menu dismissed";
            }
        }

        public static Rect GetElementRect(FrameworkElement element)
        {
            GeneralTransform buttonTransform = element.TransformToVisual(null);
            Point point = buttonTransform.TransformPoint(new Point());
            return new Rect(point, new Size(element.ActualWidth, element.ActualHeight));
        }
    }

  效果图

  点击 Open with

7)在显示文本中替换原来的上下文菜单
  我们使用控件的ContextMenuOpening事件,通过设置 e.Handled = true;来处理掉系统默认的
  上下文菜单,然后在右击的位置创建一个PopupMenu,
  使用PopupMenu的ShowForSelectionAsync方法显示上下文菜单。
  修改ReplaceADefaultContextMenu.xaml的xaml

View Code
    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid x:Name="Input" Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <TextBlock Grid.Row="0" Style="{StaticResource SubheaderTextStyle}" TextWrapping="Wrap">
                Select and right-click or tap on the selection in the below text box to show a custom context menu for text.
            </TextBlock>
            <TextBox x:Name="ReadOnlyTextBox" Grid.Row="1" IsReadOnly="True" TextWrapping="Wrap" Text="http://www.cnblogs.com/refactor"/>
        </Grid>

        <Grid x:Name="Output" Grid.Row="1" HorizontalAlignment="Left" VerticalAlignment="Top">
            <TextBlock x:Name="OutputTextBlock" Style="{StaticResource SubheaderTextStyle}" TextWrapping="Wrap"/>
        </Grid>

    </Grid>

  修改后台代码:

View Code
    public sealed partial class ReplaceADefaultContextMenu : Page
    {
        public ReplaceADefaultContextMenu()
        {
            this.InitializeComponent();
            //在系统处理显示上下文菜单交互时发生的时间
            ReadOnlyTextBox.ContextMenuOpening += new ContextMenuOpeningEventHandler(ReadOnlyTextBox_ContextMenuOpening);
        }

        /// <summary>
        /// Invoked when this page is about to be displayed in a Frame.
        /// </summary>
        /// <param name="e">Event data that describes how this page was reached.  The Parameter
        /// property is typically used to configure the page.</param>
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

        // returns a rect for selected text
        // if selection is multiline then rect is unreliable
        // if no text is selected, returns caret location
        // textbox should not be empty
        private Rect GetTextboxSelectionRect(TextBox textbox)
        {
            Rect rectFirst, rectLast;
            if (textbox.SelectionStart == textbox.Text.Length)
            {
                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());

            return new Rect(point.X + rectFirst.Left,
                point.Y + rectFirst.Top,
                rectLast.Right - rectFirst.Left,
                rectLast.Bottom - rectFirst.Top);
        }

        private async void ReadOnlyTextBox_ContextMenuOpening(object sender, ContextMenuEventArgs e)
        {
            //将系统上下文菜单标记成已处理
            e.Handled = true;
            TextBox textbox = (TextBox)sender;
            if (textbox.SelectionLength > 0)
            {
                // Create a menu and add commands specifying an id value for each instead of a delegate.
                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));

                OutputTextBlock.Text = "Context menu shown";
                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);
                            //Copy
                            Windows.ApplicationModel.DataTransfer.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
                {
                    OutputTextBlock.Text = "Context menu dismissed";
                }
            }
            else
            {
                OutputTextBlock.Text = "Context menu not shown because there is no text selected";
            }
        }
    }

  效果图

  点击Copy


未完待续,敬请期待...
转载请注明出处:http://www.cnblogs.com/refactor/

原文地址:https://www.cnblogs.com/refactor/p/2551894.html