この方法は、不具合がありました。改訂版は「TextBlock に Clipboard へのコピー機能を追加する(改訂版)」で紹介してます。
とあるお客さんで 「TextBlock に表示している文字列を他のアプリへコピーしたいんだけど...」と要求がありました。
Silverlightで作成したプログラムはすでに完成間近。
手間がかからず、短期間で実装したコードを紹介する。
操作は、TextBlockのテキストを右クリックすると、コンテキストメニューが表示され、メニューを選択すると、クリップボードへコピーする。
参考URL:Silverlight で ContextMenu を使ってみる
MainPage.xamlは
<UserControl x:Class="TextBlockClipboard.MainPage" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:my="clr-namespace:TextBlockClipboard" mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="200" > <Grid> <StackPanel> <TextBlock Text="TextBlock123456" my:TextBlockClipBoardService.ID=""/> <TextBlock Text="あああああああああ" my:TextBlockClipBoardService.ID="" /> </StackPanel> </Grid> </UserControl>
TextBlockClipBoardService.cs は
using System; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Imaging; namespace TextBlockClipboard { /// <summary> /// TextBlock の Text 文字列を Clipboard へ コピーするサービス /// </summary> public static class TextBlockClipBoardService { /// <summary> /// ID 添付プロパティ /// </summary> public static readonly DependencyProperty IDProperty = DependencyProperty.RegisterAttached("ID", typeof(string), typeof(TextBlockClipBoardService), new PropertyMetadata(null, IDPropertyChanged)); /// <summary> /// ID設定 /// </summary> public static void SetID(DependencyObject obj, string value) { obj.SetValue(IDProperty, value); } /// <summary> /// ID取得 /// </summary> public static string GetID (DependencyObject obj) { return (string)obj.GetValue(IDProperty); } /// <summary> /// ID設定(TextBlockに仕掛けを設定) /// </summary> /// <param name="d"></param> /// <param name="e"></param> private static void IDPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { var uiTextBlock = d as TextBlock; if (uiTextBlock != null) { // TextBlockなら ContextMenu menu = new ContextMenu(); MenuItem menuItem = new MenuItem(); var img = new Image { Source = new BitmapImage(new Uri("notecheck32.png", UriKind.RelativeOrAbsolute)) }; img.Height = 16; menuItem.Icon = img; menuItem.Click += (menuItemSender, _) => { // メニューを選択した MenuItem localMenuItem = (MenuItem)menuItemSender; try { Clipboard.SetText((string)localMenuItem.Tag); } catch (System.Security.SecurityException) { } }; menu.Tag = new WeakReference(uiTextBlock, false); menu.Items.Add(menuItem); menu.Opened += (menuOpendSender, _) => { // 左クリックしてメニューが開いた ContextMenu localMenu = (ContextMenu)menuOpendSender; MenuItem localMenuItem = (MenuItem)localMenu.Items[0]; var localTextBlock = (TextBlock)((WeakReference)localMenu.Tag).Target; localMenuItem.Header = "「" + localTextBlock.Text + "」をコピーします"; localMenuItem.Tag = localTextBlock.Text; }; ContextMenuService.SetContextMenu(uiTextBlock, menu); } else { throw new InvalidProgramException("TextBlockClipBoardService は TextBlock のみサポートしてます"); } } } }
ミソは、65行目でWeakReferenceを使って、相互参照地獄から逃れています。
プロジェクトファイル:TextBlockClipboard.zip
0 件のコメント:
コメントを投稿