この方法は、不具合がありました。改訂版は「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 件のコメント:
コメントを投稿