Quiero que el texto que se muestra en Witty , un cliente de código abierto de Twitter, sea seleccionable. Actualmente se muestra usando un bloque de texto personalizado. Necesito usar un TextBlock porque estoy trabajando con las líneas del bloque de texto para mostrar y formatear el nombre de usuario y los enlaces como hipervínculos. Una solicitud frecuente es poder copiar y pegar el texto. Para hacer eso, necesito hacer que TextBlock sea seleccionable.
Intenté que funcionara mostrando el texto usando un TextBox de solo lectura diseñado para parecerse a un bloque de texto, pero esto no funcionará en mi caso porque un TextBox no tiene líneas. En otras palabras, no puedo diseñar o formatear el texto dentro de un TextBox individualmente como puedo hacerlo con un TextBlock.
¿Algunas ideas?
Respuestas:
fuente
Todas las respuestas aquí solo usan
TextBox
o intentan implementar la selección de texto manualmente, lo que conduce a un bajo rendimiento o un comportamiento no nativo (parpadeoTextBox
, no hay soporte de teclado en implementaciones manuales, etc.)Después de horas de buscar y leer el código fuente de WPF , descubrí una forma de habilitar la selección de texto WPF nativo para los
TextBlock
controles (o realmente cualquier otro control). La mayor parte de la funcionalidad en torno a la selección de texto se implementa en laSystem.Windows.Documents.TextEditor
clase del sistema.Para habilitar la selección de texto para su control, debe hacer dos cosas:
Llame
TextEditor.RegisterCommandHandlers()
una vez para registrar controladores de eventos de claseCrea una instancia de
TextEditor
para cada instancia de tu clase y pasa la instancia subyacente de tuSystem.Windows.Documents.ITextContainer
a ellaTambién existe el requisito de que la
Focusable
propiedad de su control esté establecidaTrue
.¡Eso es todo! Suena fácil, pero desafortunadamente la
TextEditor
clase está marcada como interna. Así que tuve que escribir un envoltorio de reflexión a su alrededor:También creé un
SelectableTextBlock
derivado deTextBlock
que toma los pasos mencionados anteriormente:Otra opción sería crear una propiedad adjunta para
TextBlock
habilitar la selección de texto a pedido. En este caso, para deshabilitar la selección nuevamente, uno necesita separar unTextEditor
usando el equivalente de reflexión de este código:fuente
TextBlock
ha incrustadoHyperlink
s, siempre que elHyperlink
no es la última línea en el mismo. Agregar un vacío finalRun
al contenido corrige el problema subyacente que resulta en queExecutionEngineException
se arroje.TextTrimming="CharacterEllipsis"
en elTextBlock
y la anchura disponible es insuficiente, si se mueve el puntero del ratón sobre la ..., se estrella con System.ArgumentException "distancia solicitada está fuera del contenido del documento asociado." en System.Windows.Documents.TextPointer.InitializeOffset (posición del puntero de texto, distancia Int32, dirección de la dirección lógica) :( No sé si existe una solución alternativa que no sea dejar TextTrimming en Ninguno.No he podido encontrar ningún ejemplo de responder realmente la pregunta. Todas las respuestas usaron un Textbox o RichTextbox. Necesitaba una solución que me permitiera usar un TextBlock, y esta es la solución que creé.
Creo que la forma correcta de hacer esto es extender la clase TextBlock. Este es el código que usé para extender la clase TextBlock para permitirme seleccionar el texto y copiarlo al portapapeles. "sdo" es la referencia de espacio de nombres que utilicé en el WPF.
WPF usando clase extendida:
Código detrás de la clase extendida:
Código de ventana de ejemplo:
fuente
Aplique este estilo a su TextBox y listo (inspirado en este artículo ):
fuente
Cree ControlTemplate para TextBlock y coloque un TextBox dentro con el conjunto de propiedades de solo lectura. O simplemente use TextBox y hágalo de solo lectura, luego puede cambiar TextBox.Style para que se vea como TextBlock.
fuente
No estoy seguro de si puede seleccionar un TextBlock, pero otra opción sería usar un RichTextBox; es como un TextBox como sugirió, pero admite el formato que desee.
fuente
Según el Centro de desarrollo de Windows :
fuente
Si bien la pregunta dice 'Seleccionable', creo que los resultados intencionales son llevar el texto al portapapeles. Esto se puede lograr de manera fácil y elegante agregando un menú contextual y un elemento de menú llamado copia que coloca el valor de la propiedad Textblock Text en el portapapeles. Solo una idea de todos modos.
fuente
TextBlock no tiene una plantilla. Entonces, para lograr esto, necesitamos usar un cuadro de texto cuyo estilo se cambie para comportarse como un bloque de texto.
fuente
Hay una solución alternativa que podría ser adaptable al RichTextBox incluido en esta publicación de blog : utilizaba un disparador para cambiar la plantilla de control cuando el uso se desplaza sobre el control, debería ayudar con el rendimiento
fuente
fuente
Agregando a la respuesta de @ torvin y como @Dave Huang mencionó en los comentarios si ha
TextTrimming="CharacterEllipsis"
habilitado la aplicación se bloquea cuando pasa el cursor sobre los puntos suspensivos.Probé otras opciones mencionadas en el hilo sobre el uso de un TextBox, pero realmente no parece ser la solución, ya que no muestra los 'puntos suspensivos' y también si el texto es demasiado largo para caber en el contenedor seleccionando el contenido de el cuadro de texto 'se desplaza' internamente, lo que no es un comportamiento de TextBlock.
Creo que la mejor solución es la respuesta de @ torvin, pero tiene el desagradable accidente cuando se cierne sobre los puntos suspensivos.
Sé que no es bonito, pero suscribir / cancelar la suscripción internamente a excepciones no controladas y manejar la excepción fue la única forma que encontré de resolver este problema, por favor comparta si alguien tiene una mejor solución :)
fuente
He implementado SelectableTextBlock en mi biblioteca de controles de código abierto. Puedes usarlo así:
fuente
fuente
Traigo algunas pequeñas modificaciones
fuente