Quero tornar o texto exibido no Witty , um cliente do Twitter de código aberto, selecionável. Atualmente, ele é exibido usando um bloco de texto personalizado. Preciso usar um TextBlock porque estou trabalhando com as linhas do bloco de texto para exibir e formatar o @username e links como hiperlinks. Uma solicitação frequente é poder copiar e colar o texto. Para fazer isso, preciso tornar o TextBlock selecionável.
Tentei fazê-lo funcionar, exibindo o texto usando um TextBox somente leitura com estilo para parecer um bloco de texto, mas isso não funcionará no meu caso, porque um TextBox não possui linhas embutidas. Em outras palavras, não consigo estilizar ou formatar o texto dentro de uma TextBox individualmente, como posso com um TextBlock.
Alguma ideia?
Respostas:
fonte
Todas as respostas aqui estão apenas usando
TextBox
ou tentando implementar a seleção de texto manualmente, o que leva a um desempenho ruim ou a um comportamento não nativo (sinal de intermitênciaTextBox
, nenhum suporte de teclado em implementações manuais etc.)Depois de horas pesquisando e lendo o código fonte do WPF , descobri uma maneira de ativar a seleção de texto WPF nativa para
TextBlock
controles (ou realmente quaisquer outros controles). A maioria das funcionalidades relacionadas à seleção de texto é implementada naSystem.Windows.Documents.TextEditor
classe do sistema.Para habilitar a seleção de texto para seu controle, você precisa fazer duas coisas:
Ligue
TextEditor.RegisterCommandHandlers()
uma vez para registrar os manipuladores de eventos da classeCrie uma instância de
TextEditor
para cada instância da sua classe e passe a instância subjacente da suaSystem.Windows.Documents.ITextContainer
para elaTambém é necessário que a
Focusable
propriedade do seu controle esteja definidaTrue
.É isso! Parece fácil, mas infelizmente a
TextEditor
classe está marcada como interna. Então eu tive que escrever um invólucro de reflexão:Eu também criei um
SelectableTextBlock
derivadoTextBlock
que executa as etapas mencionadas acima:Outra opção seria criar uma propriedade anexada para
TextBlock
ativar a seleção de texto sob demanda. Nesse caso, para desativar a seleção novamente, é necessário desanexar aTextEditor
usando o equivalente de reflexão deste código:fonte
TextBlock
tem incorporadoHyperlink
s, enquanto oHyperlink
não é a última linha na mesma. A adição de um rastro vazioRun
ao conteúdo corrige qualquer problema subjacente que resulte noExecutionEngineException
lançamento.TextTrimming="CharacterEllipsis"
oTextBlock
e a largura disponível for insuficiente, se você mover o ponteiro do mouse sobre o…, ele trava com System.ArgumentException "A distância solicitada está fora do conteúdo do documento associado". em System.Windows.Documents.TextPointer.InitializeOffset (posição de TextPointer, distância de Int32, direção de LogicalDirection) :( Não sei se há uma solução alternativa diferente para deixar TextTrimming definido como None.Não consegui encontrar nenhum exemplo de realmente responder à pergunta. Todas as respostas usaram uma caixa de texto ou RichTextbox. Eu precisava de uma solução que me permitisse usar um TextBlock, e essa é a solução que eu criei.
Acredito que a maneira correta de fazer isso é estender a classe TextBlock. Este é o código que eu usei para estender a classe TextBlock para permitir que eu selecione o texto e copie-o para a área de transferência. "sdo" é a referência de espaço para nome que usei no WPF.
WPF usando classe estendida:
Código Atrás para Classe Estendida:
Exemplo de código da janela:
fonte
Aplique esse estilo ao seu TextBox e pronto (inspirado neste artigo ):
fonte
Crie ControlTemplate para o TextBlock e coloque um TextBox dentro com o conjunto de propriedades readonly. Ou basta usar o TextBox e torná-lo somente leitura, então você pode alterar o TextBox.Style para parecer com o TextBlock.
fonte
Não tenho certeza se você pode tornar um TextBlock selecionável, mas outra opção seria usar um RichTextBox - é como um TextBox, como você sugeriu, mas suporta a formatação desejada.
fonte
De acordo com o Windows Dev Center :
fonte
Embora a pergunta diga 'Selecionável', acredito que os resultados intencionais são levar o texto para a área de transferência. Isso pode ser feito de maneira fácil e elegante adicionando um Menu de Contexto e um item de menu chamado copy que coloca o valor da propriedade Textblock Text na área de transferência. Apenas uma idéia de qualquer maneira.
fonte
O TextBlock não possui um modelo. Portanto, para conseguir isso, precisamos usar um TextBox cujo estilo foi alterado para se comportar como um bloco de texto.
fonte
Há uma solução alternativa que pode ser adaptável ao RichTextBox excluído nesta postagem do blog - ele usou um gatilho para trocar o modelo de controle quando o uso passa o mouse sobre o controle - deve ajudar no desempenho
fonte
fonte
Adicionando à resposta de @ torvin e como @Dave Huang mencionado nos comentários, se você tiver
TextTrimming="CharacterEllipsis"
ativado o aplicativo trava ao passar o mouse sobre as reticências.Tentei outras opções mencionadas no tópico sobre o uso de um TextBox, mas ele realmente não parece ser a solução, pois não mostra as 'reticências' e também se o texto é muito longo para caber no contêiner, selecionando o conteúdo de a caixa de texto 'rola' internamente, o que não é um comportamento do TextBlock.
Eu acho que a melhor solução é a resposta de @ torvin, mas tem uma falha grave ao passar o mouse sobre as reticências.
Eu sei que não é bonito, mas assinar / cancelar a assinatura internamente de exceções não tratadas e manipular a exceção foi a única maneira que encontrei para resolver esse problema. Compartilhe se alguém tiver uma solução melhor :)
fonte
Eu implementei o SelectableTextBlock na minha biblioteca de controles de código-fonte aberto. Você pode usá-lo assim:
fonte
fonte
Trago algumas pequenas modificações
fonte