图解使用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类中的代码,
代码如下:
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
<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>
修改后台代码:
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
<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>
修改后台代码:
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/