(Há mais a ser feito; transmitir coisas ao longo da cadeia de transferência e cancelar o registro de sua visualização, mas você pode obter isso no artigo )
Funciona apenas no primeiro formulário aberto ... digamos que se eu tiver MyForm1 e myForm2, então eu abro myForm1, então MyForm2, o evento ClipboardChanged será gerado apenas em MyForm1. Quer dizer, em um aplicativo MDI ...
serhio
O link está morto. Algum backup de onde você conhece? 1 no entanto.
Patrick Hofman
1
Para pessoas preguiçosas: Configure um cronômetro para 1 ms. Então, a cada tique, verifique se o conteúdo da área de transferência mudou. Esses ganchos estão gerando alertas de vírus e cavalos de tróia no meu computador.
C4d
1
Ele passa cada MSG do Windows para o formulário e torna tão difícil depurar o código
Da mesma forma, SharpClipboard como uma biblioteca poderia ser mais benéfico, pois encapsula os mesmos recursos em uma biblioteca de componentes finos. Você pode então acessar seu ClipboardChangedevento e detectar vários formatos de dados quando eles são cortados / copiados.
Willy Kimura
78
Para completar, aqui está o controle que estou usando no código de produção. Basta arrastar do designer e clicar duas vezes para criar o manipulador de eventos.
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
namespace ClipboardAssist{// Must inherit Control, not Component, in order to have Handle[DefaultEvent("ClipboardChanged")]publicpartialclassClipboardMonitor:Control{IntPtr nextClipboardViewer;publicClipboardMonitor(){this.BackColor=Color.Red;this.Visible=false;
nextClipboardViewer =(IntPtr)SetClipboardViewer((int)this.Handle);}/// <summary>/// Clipboard contents changed./// </summary>publiceventEventHandler<ClipboardChangedEventArgs>ClipboardChanged;protectedoverridevoidDispose(bool disposing){ChangeClipboardChain(this.Handle, nextClipboardViewer);}[DllImport("User32.dll")]protectedstaticexternintSetClipboardViewer(int hWndNewViewer);[DllImport("User32.dll",CharSet=CharSet.Auto)]publicstaticexternboolChangeClipboardChain(IntPtr hWndRemove,IntPtr hWndNewNext);[DllImport("user32.dll",CharSet=CharSet.Auto)]publicstaticexternintSendMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam);protectedoverridevoidWndProc(refSystem.Windows.Forms.Message m){// defined in winuser.hconstint WM_DRAWCLIPBOARD =0x308;constint WM_CHANGECBCHAIN =0x030D;switch(m.Msg){case WM_DRAWCLIPBOARD:OnClipboardChanged();SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);break;case WM_CHANGECBCHAIN:if(m.WParam== nextClipboardViewer)
nextClipboardViewer = m.LParam;elseSendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);break;default:base.WndProc(ref m);break;}}voidOnClipboardChanged(){try{IDataObject iData =Clipboard.GetDataObject();if(ClipboardChanged!=null){ClipboardChanged(this,newClipboardChangedEventArgs(iData));}}catch(Exception e){// Swallow or pop-up, not sure// Trace.Write(e.ToString());MessageBox.Show(e.ToString());}}}publicclassClipboardChangedEventArgs:EventArgs{publicreadonlyIDataObjectDataObject;publicClipboardChangedEventArgs(IDataObject dataObject){DataObject= dataObject;}}}
Bom trabalho! No entanto, seu código de chamada de evento não é seguro para thread. Você deve criar uma cópia local ou iniciar o evento com um delegado vazio. Você também esqueceu a palavra-chave 'evento' na definição de ClipboardChanged :)
Ohad Schneider
1
@ohadsc Obrigado pelas correções. Pelo que eu sei, WndProc é chamado no thread de interface do usuário. Como a classe deriva de Control, os clientes também devem chamá-la no thread de interface do usuário.
dbkk
Funciona apenas no primeiro formulário aberto ... digamos se eu tenho MyForm1 e myForm2, então eu abro myForm1, depois MyForm2, o evento ClipboardChanged será gerado apenas em MyForm1 ... quer dizer, em um aplicativo MDI ...
serhio
De alguma forma, sua chamada para SetClipboardViewer define o código de erro Win32 1400: "Identificador de janela inválido.". Mas ainda funciona. Isso parece um pouco estranho para mim.
metacírculo de
1
SharpClipboard como uma biblioteca pode ser mais benéfico, pois encapsula os mesmos recursos em uma biblioteca de componentes finos. Você pode então acessar seu ClipboardChangedevento e detectar vários formatos de dados quando eles são cortados / copiados.
Willy Kimura
26
Tive esse desafio no WPF e acabei usando a abordagem descrita a seguir. Para formulários do Windows, há excelentes exemplos em outras partes desta resposta, como o controle ClipboardHelper.
Para WPF, não podemos substituir WndProc, então temos que conectá-lo explicitamente com uma chamada HwndSource AddHook usando o Source de uma janela. O ouvinte da área de transferência ainda usa a chamada de interoperabilidade nativa AddClipboardFormatListener.
Métodos nativos:
internalstaticclassNativeMethods{// See http://msdn.microsoft.com/en-us/library/ms649021%28v=vs.85%29.aspxpublicconstint WM_CLIPBOARDUPDATE =0x031D;publicstaticIntPtr HWND_MESSAGE =newIntPtr(-3);// See http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#message_only[DllImport("user32.dll",SetLastError=true)][return:MarshalAs(UnmanagedType.Bool)]publicstaticexternboolAddClipboardFormatListener(IntPtr hwnd);}
Classe de gerenciador de área de transferência:
using System.Windows;
using System.Windows.Interop;publicclassClipboardManager{publiceventEventHandlerClipboardChanged;publicClipboardManager(Window windowSource){HwndSource source =PresentationSource.FromVisual(windowSource)asHwndSource;if(source ==null){thrownewArgumentException("Window source MUST be initialized first, such as in the Window's OnSourceInitialized handler.", nameof(windowSource));}
source.AddHook(WndProc);// get window handle for interopIntPtr windowHandle =newWindowInteropHelper(windowSource).Handle;// register for clipboard eventsNativeMethods.AddClipboardFormatListener(windowHandle);}privatevoidOnClipboardChanged(){ClipboardChanged?.Invoke(this,EventArgs.Empty);}privatestaticreadonlyIntPtrWndProcSuccess=IntPtr.Zero;privateIntPtrWndProc(IntPtr hwnd,int msg,IntPtr wParam,IntPtr lParam,refbool handled){if(msg ==NativeMethods.WM_CLIPBOARDUPDATE){OnClipboardChanged();
handled =true;}returnWndProcSuccess;}}
Isso é usado em uma janela WPF adicionando o evento OnSourceInitialized ou posterior, como o evento Window.Loaded ou durante a operação. (quando temos informações suficientes para usar os ganchos nativos):
publicpartialclassMainWindow:Window{publicMainWindow(){InitializeComponent();}protectedoverridevoidOnSourceInitialized(EventArgs e){base.OnSourceInitialized(e);// Initialize the clipboard now that we have a window soruce to usevar windowClipboardManager =newClipboardManager(this);
windowClipboardManager.ClipboardChanged+=ClipboardChanged;}privatevoidClipboardChanged(object sender,EventArgs e){// Handle your clipboard update here, debug logging example:if(Clipboard.ContainsText()){Debug.WriteLine(Clipboard.GetText());}}}
Estou usando essa abordagem em um projeto de analisador de itens do Path of Exile, pois o jogo expõe as informações do item por meio da área de transferência quando você pressiona Ctrl-C.
Ok, então este é um post antigo, mas encontramos uma solução que parece muito simples em comparação com o conjunto de respostas atual. Estamos usando o WPF e queríamos ter nossos próprios comandos personalizados (em um ContextMenu) ativados e desativados se a área de transferência contiver texto. Já existe um ApplicationCommands.Cut, Copy e Paste e esses comandos respondem corretamente à mudança da área de transferência. Então, acabamos de adicionar o seguinte EventHandler.
Esta é uma solução fantástica para o problema específico de habilitar ou desabilitar o comando paste. Infelizmente, ele não cobre o cenário específico "o texto foi alterado" e não será acionado ao copiar várias linhas de texto diferentes, por exemplo.
Colin Dabritz
11
Existem várias maneiras de fazer isso, mas esta é a minha favorita e funciona para mim. Eu criei uma biblioteca de classes para que outras pessoas possam adicionar o projeto e incluir a DLL e, em seguida, simplesmente chamá-la e usá-la onde quiserem em seus aplicativos.
Crie um projeto de Biblioteca de Classes e denomine-o ClipboardHelper.
Substitua o nome Class1 por ClipboardMonitor.
Adicione o código abaixo nele.
Adicione a referência System.Windows.Forms.
Mais etapas sob o código.
using System;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
namespace ClipboardHelper{publicstaticclassClipboardMonitor{publicdelegatevoidOnClipboardChangeEventHandler(ClipboardFormat format,object data);publicstaticeventOnClipboardChangeEventHandlerOnClipboardChange;publicstaticvoidStart(){ClipboardWatcher.Start();ClipboardWatcher.OnClipboardChange+=(ClipboardFormat format,object data)=>{if(OnClipboardChange!=null)OnClipboardChange(format, data);};}publicstaticvoidStop(){OnClipboardChange=null;ClipboardWatcher.Stop();}classClipboardWatcher:Form{// static instance of this formprivatestaticClipboardWatcher mInstance;// needed to dispose this formstaticIntPtr nextClipboardViewer;publicdelegatevoidOnClipboardChangeEventHandler(ClipboardFormat format,object data);publicstaticeventOnClipboardChangeEventHandlerOnClipboardChange;// start listeningpublicstaticvoidStart(){// we can only have one instance if this classif(mInstance !=null)return;var t =newThread(newParameterizedThreadStart(x =>Application.Run(newClipboardWatcher())));
t.SetApartmentState(ApartmentState.STA);// give the [STAThread] attribute
t.Start();}// stop listening (dispose form)publicstaticvoidStop(){
mInstance.Invoke(newMethodInvoker(()=>{ChangeClipboardChain(mInstance.Handle, nextClipboardViewer);}));
mInstance.Invoke(newMethodInvoker(mInstance.Close));
mInstance.Dispose();
mInstance =null;}// on load: (hide this window)protectedoverridevoidSetVisibleCore(boolvalue){CreateHandle();
mInstance =this;
nextClipboardViewer =SetClipboardViewer(mInstance.Handle);base.SetVisibleCore(false);}[DllImport("User32.dll",CharSet=CharSet.Auto)]privatestaticexternIntPtrSetClipboardViewer(IntPtr hWndNewViewer);[DllImport("User32.dll",CharSet=CharSet.Auto)]privatestaticexternboolChangeClipboardChain(IntPtr hWndRemove,IntPtr hWndNewNext);[DllImport("user32.dll",CharSet=CharSet.Auto)]privatestaticexternintSendMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam);// defined in winuser.hconstint WM_DRAWCLIPBOARD =0x308;constint WM_CHANGECBCHAIN =0x030D;protectedoverridevoidWndProc(refMessage m){switch(m.Msg){case WM_DRAWCLIPBOARD:ClipChanged();SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);break;case WM_CHANGECBCHAIN:if(m.WParam== nextClipboardViewer)
nextClipboardViewer = m.LParam;elseSendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);break;default:base.WndProc(ref m);break;}}staticreadonlystring[] formats =Enum.GetNames(typeof(ClipboardFormat));privatevoidClipChanged(){IDataObject iData =Clipboard.GetDataObject();ClipboardFormat? format =null;foreach(var f in formats){if(iData.GetDataPresent(f)){
format =(ClipboardFormat)Enum.Parse(typeof(ClipboardFormat), f);break;}}object data = iData.GetData(format.ToString());if(data ==null|| format ==null)return;if(OnClipboardChange!=null)OnClipboardChange((ClipboardFormat)format, data);}}}publicenumClipboardFormat:byte{/// <summary>Specifies the standard ANSI text format. This static field is read-only./// </summary>/// <filterpriority>1</filterpriority>Text,/// <summary>Specifies the standard Windows Unicode text format. This static field/// is read-only.</summary>/// <filterpriority>1</filterpriority>UnicodeText,/// <summary>Specifies the Windows device-independent bitmap (DIB) format. This static/// field is read-only.</summary>/// <filterpriority>1</filterpriority>Dib,/// <summary>Specifies a Windows bitmap format. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>Bitmap,/// <summary>Specifies the Windows enhanced metafile format. This static field is/// read-only.</summary>/// <filterpriority>1</filterpriority>EnhancedMetafile,/// <summary>Specifies the Windows metafile format, which Windows Forms does not/// directly use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>MetafilePict,/// <summary>Specifies the Windows symbolic link format, which Windows Forms does/// not directly use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>SymbolicLink,/// <summary>Specifies the Windows Data Interchange Format (DIF), which Windows Forms/// does not directly use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>Dif,/// <summary>Specifies the Tagged Image File Format (TIFF), which Windows Forms does/// not directly use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>Tiff,/// <summary>Specifies the standard Windows original equipment manufacturer (OEM)/// text format. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>OemText,/// <summary>Specifies the Windows palette format. This static field is read-only./// </summary>/// <filterpriority>1</filterpriority>Palette,/// <summary>Specifies the Windows pen data format, which consists of pen strokes/// for handwriting software, Windows Forms does not use this format. This static/// field is read-only.</summary>/// <filterpriority>1</filterpriority>PenData,/// <summary>Specifies the Resource Interchange File Format (RIFF) audio format,/// which Windows Forms does not directly use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>Riff,/// <summary>Specifies the wave audio format, which Windows Forms does not directly/// use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>WaveAudio,/// <summary>Specifies the Windows file drop format, which Windows Forms does not/// directly use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>FileDrop,/// <summary>Specifies the Windows culture format, which Windows Forms does not directly/// use. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>Locale,/// <summary>Specifies text consisting of HTML data. This static field is read-only./// </summary>/// <filterpriority>1</filterpriority>Html,/// <summary>Specifies text consisting of Rich Text Format (RTF) data. This static/// field is read-only.</summary>/// <filterpriority>1</filterpriority>Rtf,/// <summary>Specifies a comma-separated value (CSV) format, which is a common interchange/// format used by spreadsheets. This format is not used directly by Windows Forms./// This static field is read-only.</summary>/// <filterpriority>1</filterpriority>CommaSeparatedValue,/// <summary>Specifies the Windows Forms string class format, which Windows Forms/// uses to store string objects. This static field is read-only.</summary>/// <filterpriority>1</filterpriority>StringFormat,/// <summary>Specifies a format that encapsulates any type of Windows Forms object./// This static field is read-only.</summary>/// <filterpriority>1</filterpriority>Serializable,}}
Em seus outros projetos, clique com o botão direito na solução e em Adicionar -> Sair do Projeto -> ClipboardHelper.csproj
Em seu projeto, acesse e clique com o botão direito do mouse em Referências -> Adicionar Referência -> Solução -> Selecionar ClipboardHelper.
Em seu arquivo de classe do tipo de projeto usando ClipboardHelper.
Agora você pode digitar ClipboardMonitor.Start ou .Stop ou .OnClipboardChanged
using ClipboardHelper;
namespace Something.Something.DarkSide{publicclassMainWindow{publicMainWindow(){InitializeComponent();Loaded+=MainWindow_Loaded;}voidMainWindow_Loaded(object sender,RoutedEventArgs e){ClipboardMonitor.OnClipboardChange+=ClipboardMonitor_OnClipboardChange;ClipboardMonitor.Start();}privatevoidClipboardMonitor_OnClipboardChange(ClipboardFormat format,object data){// Do Something...}}
Acredito que uma das soluções anteriores não verifica se há um nulo no método dispose:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;
namespace ClipboardAssist{// Must inherit Control, not Component, in order to have Handle[DefaultEvent("ClipboardChanged")]publicpartialclassClipboardMonitor:Control{IntPtr nextClipboardViewer;publicClipboardMonitor(){this.BackColor=Color.Red;this.Visible=false;
nextClipboardViewer =(IntPtr)SetClipboardViewer((int)this.Handle);}/// <summary>/// Clipboard contents changed./// </summary>publiceventEventHandler<ClipboardChangedEventArgs>ClipboardChanged;protectedoverridevoidDispose(bool disposing){if(nextClipboardViewer !=null)ChangeClipboardChain(this.Handle, nextClipboardViewer);}[DllImport("User32.dll")]protectedstaticexternintSetClipboardViewer(int hWndNewViewer);[DllImport("User32.dll",CharSet=CharSet.Auto)]publicstaticexternboolChangeClipboardChain(IntPtr hWndRemove,IntPtr hWndNewNext);[DllImport("user32.dll",CharSet=CharSet.Auto)]publicstaticexternintSendMessage(IntPtr hwnd,int wMsg,IntPtr wParam,IntPtr lParam);protectedoverridevoidWndProc(refSystem.Windows.Forms.Message m){// defined in winuser.hconstint WM_DRAWCLIPBOARD =0x308;constint WM_CHANGECBCHAIN =0x030D;switch(m.Msg){case WM_DRAWCLIPBOARD:OnClipboardChanged();SendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);break;case WM_CHANGECBCHAIN:if(m.WParam== nextClipboardViewer)
nextClipboardViewer = m.LParam;elseSendMessage(nextClipboardViewer, m.Msg, m.WParam, m.LParam);break;default:base.WndProc(ref m);break;}}voidOnClipboardChanged(){try{IDataObject iData =Clipboard.GetDataObject();if(ClipboardChanged!=null){ClipboardChanged(this,newClipboardChangedEventArgs(iData));}}catch(Exception e){// Swallow or pop-up, not sure// Trace.Write(e.ToString());MessageBox.Show(e.ToString());}}}publicclassClipboardChangedEventArgs:EventArgs{publicreadonlyIDataObjectDataObject;publicClipboardChangedEventArgs(IDataObject dataObject){DataObject= dataObject;}}}
Nunca é nulo porque o construtor o define. A única coisa que eu faria diferente seria chamar base.Dispose()o método dispose.
jedmao
De qualquer forma. Para fins de verificação como você listou, você deve usar IntPtr.Zero para NULL (observe que não é equivalente ao C # null) stackoverflow.com/questions/1456861/…
walter
1
ChangeClipboardChain é executado sempre na saída em todos os exemplos do msdn
walter
O objetivo é remover a si mesmo da cadeia de visualização da área de transferência
walter
5
SharpClipboard como uma biblioteca pode ser mais benéfico, pois encapsula os mesmos recursos em uma biblioteca de componentes finos. Você pode então acessar seu ClipboardChangedevento e detectar vários formatos de dados quando eles são cortados / copiados.
Você pode escolher os vários formatos de dados que deseja monitorar:
var clipboard =newSharpClipboard();
clipboard.ObservableFormats.Texts=true;
clipboard.ObservableFormats.Files=true;
clipboard.ObservableFormats.Images=true;
clipboard.ObservableFormats.Others=true;
Aqui está um exemplo usando seu ClipboardChangedevento:
privatevoidClipboardChanged(Object sender,ClipboardChangedEventArgs e){// Is the content copied of text type?if(e.ContentType==SharpClipboard.ContentTypes.Text){// Get the cut/copied text.Debug.WriteLine(clipboard.ClipboardText);}// Is the content copied of image type?elseif(e.ContentType==SharpClipboard.ContentTypes.Image){// Get the cut/copied image.Image img = clipboard.ClipboardImage;}// Is the content copied of file type?elseif(e.ContentType==SharpClipboard.ContentTypes.Files){// Get the cut/copied file/files.Debug.WriteLine(clipboard.ClipboardFiles.ToArray());// ...or use 'ClipboardFile' to get a single copied file.Debug.WriteLine(clipboard.ClipboardFile);}// If the cut/copied content is complex, use 'Other'.elseif(e.ContentType==SharpClipboard.ContentTypes.Other){// Do something with 'e.Content' here...}}
Você também pode descobrir a aplicação em que o evento cortar / copiar ocorreu, juntamente com seus detalhes:
privatevoidClipboardChanged(Object sender,SharpClipboard.ClipboardChangedEventArgs e){// Gets the application's executable name.Debug.WriteLine(e.SourceApplication.Name);// Gets the application's window title.Debug.WriteLine(e.SourceApplication.Title);// Gets the application's process ID.Debug.WriteLine(e.SourceApplication.ID.ToString());// Gets the application's executable path.Debug.WriteLine(e.SourceApplication.Path);}
Existem também outros eventos, como o MonitorChanged evento que escuta sempre que o monitoramento da área de transferência é desabilitado, o que significa que você pode habilitar ou desabilitar o monitoramento da área de transferência em tempo de execução.
Além de tudo isso, por ser um componente, você pode usá-lo no Designer View arrastando-o e soltando-o em um formulário do Windows, tornando muito fácil para qualquer pessoa personalizar suas opções e trabalhar com seus eventos embutidos.
SharpClipboard parece ser a melhor opção para cenários de monitoramento de área de transferência em .NET.
Respostas:
Acho que você terá que usar algum p / invoke:
Veja este artigo sobre como configurar um monitor de área de transferência em c #
Basicamente, você registra seu aplicativo como um visualizador de área de transferência usando
e então você receberá a
WM_DRAWCLIPBOARD
mensagem, que pode ser tratada substituindoWndProc
:(Há mais a ser feito; transmitir coisas ao longo da cadeia de transferência e cancelar o registro de sua visualização, mas você pode obter isso no artigo )
fonte
ClipboardChanged
evento e detectar vários formatos de dados quando eles são cortados / copiados.Para completar, aqui está o controle que estou usando no código de produção. Basta arrastar do designer e clicar duas vezes para criar o manipulador de eventos.
fonte
ClipboardChanged
evento e detectar vários formatos de dados quando eles são cortados / copiados.Tive esse desafio no WPF e acabei usando a abordagem descrita a seguir. Para formulários do Windows, há excelentes exemplos em outras partes desta resposta, como o controle ClipboardHelper.
Para WPF, não podemos substituir WndProc, então temos que conectá-lo explicitamente com uma chamada HwndSource AddHook usando o Source de uma janela. O ouvinte da área de transferência ainda usa a chamada de interoperabilidade nativa AddClipboardFormatListener.
Métodos nativos:
Classe de gerenciador de área de transferência:
Isso é usado em uma janela WPF adicionando o evento OnSourceInitialized ou posterior, como o evento Window.Loaded ou durante a operação. (quando temos informações suficientes para usar os ganchos nativos):
Estou usando essa abordagem em um projeto de analisador de itens do Path of Exile, pois o jogo expõe as informações do item por meio da área de transferência quando você pressiona Ctrl-C.
https://github.com/ColinDabritz/PoeItemAnalyzer
Espero que isso ajude alguém com o manuseio de alterações da área de transferência do WPF!
fonte
ClipboardChanged?.Invoke
ver Usando o Novo Operador Condicional Nulo em C # 6 , seção Outros CenáriosOk, então este é um post antigo, mas encontramos uma solução que parece muito simples em comparação com o conjunto de respostas atual. Estamos usando o WPF e queríamos ter nossos próprios comandos personalizados (em um ContextMenu) ativados e desativados se a área de transferência contiver texto. Já existe um ApplicationCommands.Cut, Copy e Paste e esses comandos respondem corretamente à mudança da área de transferência. Então, acabamos de adicionar o seguinte EventHandler.
Na verdade, estamos controlando o CanExecute em nosso próprio comando dessa maneira. Funciona para o que precisávamos e talvez ajude outras pessoas.
fonte
Existem várias maneiras de fazer isso, mas esta é a minha favorita e funciona para mim. Eu criei uma biblioteca de classes para que outras pessoas possam adicionar o projeto e incluir a DLL e, em seguida, simplesmente chamá-la e usá-la onde quiserem em seus aplicativos.
Essa resposta foi feita com a ajuda deste .
Mais etapas sob o código.
Agora você pode digitar ClipboardMonitor.Start ou .Stop ou .OnClipboardChanged
fonte
Acredito que uma das soluções anteriores não verifica se há um nulo no método dispose:
fonte
base.Dispose()
o método dispose.SharpClipboard como uma biblioteca pode ser mais benéfico, pois encapsula os mesmos recursos em uma biblioteca de componentes finos. Você pode então acessar seu
ClipboardChanged
evento e detectar vários formatos de dados quando eles são cortados / copiados.Você pode escolher os vários formatos de dados que deseja monitorar:
Aqui está um exemplo usando seu
ClipboardChanged
evento:Você também pode descobrir a aplicação em que o evento cortar / copiar ocorreu, juntamente com seus detalhes:
Existem também outros eventos, como o
MonitorChanged
evento que escuta sempre que o monitoramento da área de transferência é desabilitado, o que significa que você pode habilitar ou desabilitar o monitoramento da área de transferência em tempo de execução.Além de tudo isso, por ser um componente, você pode usá-lo no Designer View arrastando-o e soltando-o em um formulário do Windows, tornando muito fácil para qualquer pessoa personalizar suas opções e trabalhar com seus eventos embutidos.
SharpClipboard parece ser a melhor opção para cenários de monitoramento de área de transferência em .NET.
fonte
fonte