2012-12-06 48 views
6

WPFのテキストボックスに貼り付けられたデータをインターセプトしようとしています。WPFテキストボックスに「データを貼り付ける」ことを許可する

たとえば、ユーザーはWindowsスナップツール を使用して画像キャプチャを作成し、自動的に画像データをクリップボードに配置します。ここでのアイデアは にあります。私はそれを傍受して、それが のデータであるかどうかを確認して、それから私が望むものを何でもしようとするために、ユーザーにTextBoxを単純にCTRL + Vすることができます。

上記の動作を使用して
public class PasteBehavior : Behavior<UIElement> 
{ 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     DataObject.AddPastingHandler(AssociatedObject, new DataObjectPastingEventHandler(OnPaste)); 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
    } 

    private void OnPaste(object sender, DataObjectPastingEventArgs e) 
    { 
     if (e.SourceDataObject.GetDataPresent(DataFormats.Text)) 
      return; 

     var formats = e.SourceDataObject.GetFormats(); 
     foreach (var format in formats) 
      Console.WriteLine(format); 
    } 
} 

、テキストはテキストボックス に貼り付けられたときにコードがトリガ取得んが、それは、テキストではない場合はそれもこのコードに到達したことがないので、テキストボックスに何かを貼り付けることを許可しないと思われます。

私は(テキストボックスは、そのデータを表示することはできませんが)データを貼り付けることができるようになるのTextBoxに設定する必要が財産、または何か他のもの があり、思ったんだけど

ない場合どのUI要素でデータを貼り付けることができるのか、私の利点にも使えるかもしれません。

更新 誰かが私は私が使用できるものではありません。このような
を、貼り付けできるように、リッチテキストボックスを使用する必要があるだろうと私にアウト投稿ので、私は別の(ややハック)アプローチを取ることにしました:

public class PasteBehavior : Behavior<UIElement> 
{ 
    protected override void OnAttached() 
    { 
     base.OnAttached(); 
     AssociatedObject.PreviewKeyDown += AssociatedObject_PreviewKeyDown; 
    } 

    void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e) 
    { 
     if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V) 
     { 
      if (Clipboard.ContainsData(DataFormats.Dib)) 
      { 
       using (var stream = new MemoryStream()) 
       { 
        var image = Clipboard.GetImage(); 
        var message = new ImagePastedMessage() 
        { 
         ImageData = GetImagePngData(image) 
        }; 

        Messenger.Default.Send(message); 
       } 

       e.Handled = true; 
      } 
      else if (Clipboard.ContainsFileDropList()) 
      { 
       var results = Clipboard.GetFileDropList(); 
       var filenames = new string[results.Count]; 
       results.CopyTo(filenames, 0); 

       var message = new FilesDroppedMessage() 
       { 
        Filenames = filenames 
       }; 

       Messenger.Default.Send(message); 
       e.Handled = true; 
      } 
     } 
    } 

    protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
    } 

    private byte[] GetImagePngData(BitmapSource source) 
    { 
     using (var stream = new MemoryStream())    
     { 
      var encoder = new PngBitmapEncoder(); 
      encoder.Frames.Add(BitmapFrame.Create(source)); 
      encoder.Save(stream); 
      return stream.ToArray(); 
     } 
    } 
} 

これは私がテキストボックスに画像やファイルを貼り付けるだけ のTextBoxのデフォルトのコンテキストメニューを使用していない、CTRL + Vキーを使用することができます。

より良い/簡単な方法

があるのであれば、私はまだ知ることに興味がアップデート2 本当によく働くダニエルによるソリューションに基づいて、私はOnAttachedを更新しました:

protected override void OnAttached() 
{ 
    base.OnAttached(); 

    CommandManager.AddPreviewCanExecuteHandler(AssociatedObject, onPreviewCanExecute); 
    CommandManager.AddPreviewExecutedHandler(AssociatedObject, onPreviewExecuted); 
} 

PreviewKeyDownHandlerを削除しました。

+0

コードスニペットの1つで、CTRL + Vを明示的に処理しています。 - ユーザーは、たとえば、異なるキーの組み合わせになるようにペーストを構成している可能性があります。あなたが扱うことができるOSからのより広い "ペースト"メッセージがなければなりません。 – BrainSlugs83

答えて

7

貼り付けロジックを処理するには、CommandManager.PreviewExecutedCommandManager.PreviewCanExecuteルーティングイベントを使用できます。

たとえば、クリップボードからユーザーがTextBoxに画像を貼り付けようとしたときに、画像を受け入れるとします。あなたはルーティングイベント(これは例えば、コンストラクタに行くことができる)と、それらのメソッドを関連付ける必要があり、その後

private void onPreviewCanExecute(object sender, CanExecuteRoutedEventArgs e) 
    { 
     // In this case, we just say it always can be executed (only for a Paste command), but you can 
     // write some checks here 
     if (e.Command == ApplicationCommands.Paste) 
     { 
      e.CanExecute = true; 
      e.Handled = true; 
     } 
    } 

    private void onPreviewExecuted(object sender, ExecutedRoutedEventArgs e) 
    { 
     // If it is a paste command.. 
     if (e.Command == ApplicationCommands.Paste) 
     { 
      // .. and the clipboard contains an image 
      if (Clipboard.ContainsImage()) 
      { 
       // proccess it somehow 
       e.Handled = true; 
      } 

     } 
    } 

::だから最初、両方のイベントを処理するメソッドを定義

CommandManager.AddPreviewExecutedHandler(myTextBox, onPreviewExecuted); 
CommandManager.AddPreviewCanExecuteHandler(myTextBox, onPreviewCanExecute); 

そして、それはキーボードショートカットとメニュー 'ボタン'の両方で動作するはずです。

PreviewCanExecuteイベントを処理することが重要です。デフォルトでは、TextBoxはテキストを「ペースト可能な」コンテンツとしてのみ受け入れるため、そのコンテンツを何らかの形で貼り付ける必要があります。

EDIT: 可能であれば、イベントから「リスナー」を削除することも良い方法です。ビヘイビアを使用しているときは、ビヘイビアで 'OnDetaching'メソッドをオーバーライドすることでこれを行うことができます。これは、イベントが弱いイベントでない場合、メモリリークを防ぐことができます。

protected override void OnDetaching() 
    { 
     base.OnDetaching(); 
     CommandManager.RemovePreviewExecutedHandler(myTextBox, onPreviewExecuted); 
     CommandManager.RemovePreviewCanExecuteHandler(myTextBox, onPreviewCanExecute); 
    } 
+0

1分で試してみましょう – TimothyP

+0

魅力的な作品です! Thnx! – TimothyP

+0

ようこそ。うまくいきました –

関連する問題