2012-12-06 50 views
6

Tôi đang cố chặn dữ liệu được dán vào hộp văn bản WPF.Cho phép 'dán dữ liệu' vào hộp văn bản WPF

Ví dụ: người dùng tạo ảnh chụp màn hình bằng công cụ bẻ khóa Windows, tự động đặt dữ liệu hình ảnh vào khay nhớ tạm. Ý tưởng ở đây là để cho phép người dùng chỉ đơn giản là CTRL + V trên TextBox để tôi có thể chặn nó, kiểm tra xem đó là dữ liệu và sau đó làm bất cứ điều gì tôi muốn với nó.

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); 
    } 
} 

Sử dụng các hành vi trên, các mã này được kích hoạt khi văn bản được dán vào TextBox nhưng nó sẽ có vẻ TextBox không cho phép bất cứ điều gì khác để được dán nên nó không bao giờ thậm chí đạt đến mã này nếu nó không phải là văn bản .

Tôi đang tự hỏi, liệu có một tài sản cần phải được thiết lập trên TextBox, hay cái gì khác mà sẽ cho phép dữ liệu được dán (mặc dù TextBox không bao giờ có thể hiển thị dữ liệu đó)

Nếu không , các yếu tố giao diện người dùng nào cho phép dán dữ liệu, vì tôi cũng có thể sử dụng các yếu tố đó cho lợi thế của mình.

Cập nhật người gửi ra cho tôi rằng tôi sẽ phải sử dụng một RichTextBox để cho phép dán
như thế này, mà không phải là điều mà tôi có thể sử dụng, vì vậy tôi quyết định tham gia một cách tiếp cận khác nhau (hơi hacky) :

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(); 
     } 
    } 
} 

này cho phép tôi để dán hình ảnh và các tập tin vào TextBox nhưng chỉ sử dụng + V phím CTRL, không sử dụng menu ngữ cảnh mặc định của TextBox.

Vì vậy, tôi vẫn muốn biết nếu có một/cách tốt hơn dễ dàng hơn

Cập nhật 2 Dựa trên các giải pháp của Daniel, trong đó hoạt động thực sự tốt, tôi đã cập nhật các OnAttached:

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

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

Và xóa tệp PreviewKeyDownHandler.

+0

Trong một trong các đoạn mã của bạn, bạn đang xử lý CTRL + V một cách rõ ràng - đừng bao giờ làm điều đó! - ví dụ: người dùng có thể đã dán cấu hình là một tổ hợp phím khác. Phải có thông báo "Dán" rộng hơn từ hệ điều hành mà bạn có thể xử lý. – BrainSlugs83

Trả lời

7

Bạn có thể sử dụng CommandManager.PreviewExecutedCommandManager.PreviewCanExecute sự kiện được định tuyến để xử lý logic dán của mình.

Ví dụ: giả sử bạn muốn chấp nhận hình ảnh từ khay nhớ tạm khi người dùng cố gắng dán hình ảnh đó vào Hộp văn bản của bạn. Vì vậy, đầu tiên, xác định các phương pháp mà sẽ xử lý cả hai sự kiện:

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; 
      } 

     } 
    } 

Sau đó, bạn phải kết hợp các phương pháp đó với các sự kiện chuyển (điều này có thể đi vào các nhà xây dựng, ví dụ):

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

Và nó sẽ hoạt động với cả phím tắt và nút 'menu'.

Điều quan trọng là phải xử lý sự kiện PreviewCanExecute. Theo mặc định, TextBox sẽ chỉ chấp nhận văn bản dưới dạng nội dung 'có thể dán', vì vậy bạn cần đánh dấu nội dung đó bằng cách nào đó để dán nội dung đó.

EDIT: Ngoài ra, thực tiễn tốt là xóa 'người nghe' khỏi sự kiện nếu có thể. Khi bạn đang sử dụng các hành vi, bạn có thể làm điều này bằng cách ghi đè phương thức 'OnDetaching' trong hành vi của bạn. Điều này có thể ngăn chặn rò rỉ bộ nhớ nếu các sự kiện không phải là Sự kiện yếu:

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

Hãy để tôi thử một phút – TimothyP

+0

Làm việc như một sự quyến rũ! Thnx! – TimothyP

+0

Bạn được chào đón. Vui mừng nó làm việc –

Các vấn đề liên quan