2012-12-06 12 views
6

Sto provando ad intercettare i dati incollati in una casella di testo WPF.Consentire 'incolla dati' in una casella di testo WPF

Ad esempio, l'utente crea un'acquisizione di schermate con lo strumento di snipping di Windows, che colloca automaticamente i dati dell'immagine negli Appunti. L'idea qui è di consentire all'utente di semplicemente CTRL + V sul TextBox in modo che io possa intercettarlo, controllare se si tratta di dati e quindi fare quello che voglio con esso.

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

Utilizzando il comportamento precedente, il codice venga attivato quando il testo viene incollato in TextBox ma sembrerebbe TextBox non consente altro per essere incollato in modo che non raggiunge mai, anche questo codice se non è il testo .

mi chiedo, c'è una proprietà che deve essere impostata sul TextBox, o qualcos'altro che permetterebbe ai dati di essere incollati (anche se il TextBox non potrà mai visualizzare i dati)

caso contrario , quali elementi dell'interfaccia utente consentono di incollare i dati, poiché potrei essere in grado di utilizzarli a mio vantaggio.

Aggiornamento qualcuno ha postato a me che avrei dovuto usare un RichTextBox per consentire incollare
come questo, che non è qualcosa che posso usare, così ho deciso di adottare un approccio diverso (un po '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(); 
     } 
    } 
} 

Questo mi permette di incollare immagini e file nella casella di testo, ma solo utilizzando i tasti CTRL + V, non utilizzando il menu contestuale di default del controllo TextBox.

Quindi sono ancora interessato a sapere se c'è un modo migliore/più facile

Update 2 Sulla base della soluzione di Daniel, che funziona davvero bene, ho aggiornato il OnAttached:

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

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

E rimosso PreviewKeyDownHandler.

+0

In uno dei suoi frammenti di codice, si sta movimentazione CTRL + V in modo esplicito - non farlo mai! - l'utente potrebbe avere incollato configurato per essere una combinazione di tasti diversa, ad esempio. Ci deve essere un messaggio "Incolla" più ampio dal sistema operativo che puoi gestire. – BrainSlugs83

risposta

7

È possibile utilizzare gli eventi instradati CommandManager.PreviewExecuted e CommandManager.PreviewCanExecute per gestire la logica di incastro.

Ad esempio, supponiamo di voler accettare un'immagine dagli Appunti quando un utente tenta di incollarlo nel TextBox. Quindi, prima, definire i metodi che gestiranno entrambi gli eventi:

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

     } 
    } 

Poi, si deve associare questi metodi con gli eventi indirizzati (questo potrebbe andare nel costruttore, per esempio):

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

E dovrebbe funzionare sia con la scorciatoia da tastiera che con il 'pulsante' del menu.

È importante gestire l'evento PreviewCanExecute. Per impostazione predefinita, TextBox accetta il testo solo come contenuto "incollabile", quindi è necessario contrassegnarlo in qualche modo per incollarlo.

MODIFICA: Inoltre, è una buona pratica rimuovere gli 'ascoltatori' dall'evento se è possibile. Mentre stai usando i comportamenti, puoi farlo sovrascrivendo il metodo "OnDetaching" nel tuo comportamento. Questo potrebbe impedire perdite di memoria se gli eventi non sono eventi deboli:

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

Lasciami fare una prova in un minuto – TimothyP

+0

Funziona come un incantesimo! Thnx! – TimothyP

+0

Prego. Lieto che funzionasse –

Problemi correlati