Есть ли способ сделать текстовый блок WPF доступным для выбора?

Как разрешить выбор текста TextBlock?

Я попытался заставить его работать, отображая текст с помощью TextBox только для чтения, стилизованного под текстовый блок, но в моем случае это не сработает, потому что TextBox не имеет встроенных строк. Другими словами, как сделать его выбираемым?

Я попробую использовать элемент управления RichTextBox, чтобы посмотреть, сработает ли это. Но, судя по предыдущему опыту, работа с richtextbox намного сложнее.

Alan Le 26.09.2008 02:06

Вы думали об использовании FlowDocumentScrollViewer с FlowDocument, содержащим абзацы и прогоны? - Это очень хорошо работает для меня, когда мне нужен выбираемый текст, и каждый абзац и бег можно стилизовать отдельно.

BrainSlugs83 25.01.2015 07:58

Попробовав некоторые из описанных ниже обходных решений, FlowDocumentScrollViewer был шагом вперед. Кажется, он занимает полезную золотую середину между RichTextBox и TextBlock.

Tom Makin 19.05.2016 18:04

голос "против" за принятие ответа, не соответствующего вашим требованиям.

Blechdose 02.03.2020 10:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
238
4
117 717
15
Перейти к ответу Данный вопрос помечен как решенный

Ответы 15

Я не уверен, что вы можете сделать TextBlock выбираемым, но другой вариант - использовать RichTextBox - это похоже на TextBox, как вы предложили, но поддерживает желаемое форматирование.

Я попытался сделать это, и в процессе мне пришлось сделать RichTextBox привязываемым с помощью свойства зависимости. К сожалению, старые потоковые документы не удаляются должным образом, и память утекает как сумасшедшая. Алан, интересно, ты нашел способ обойти это?

John Noonan 24.04.2009 09:59

@AlanLe Из всех ответов здесь это только один из двух, который действительно отвечает на заданный вопрос ... все остальные говорят о стилизации TextBox, чтобы он выглядел как TextBlock, игнорируя при этом необходимость форматирования. Странно и прискорбно, что OP принял один из этих неответов вместо правильного ответа, чтобы использовать RichTextBox, а не TextBox.

Jim Balter 15.04.2016 06:37

Создайте ControlTemplate для TextBlock и поместите внутри TextBox с набором свойств только для чтения. Или просто используйте TextBox и сделайте его доступным только для чтения, затем вы можете изменить TextBox.Style, чтобы он выглядел как TextBlock.

Как установить ControlTemplate для TextBlock? Я не могу найти недвижимость?

HaxElit 14.01.2010 18:39

Вы также можете установить стиль границы, он должен выглядеть как TextBlock. Я думаю, что TextBox стоит даже меньше, чем TextBlock.

Shimmy Weitzhandler 15.02.2010 13:49

Этот подход не будет работать, если в вашем TextBlock есть встроенные элементы. Что делать, если у вас есть гиперссылки или полужирный или курсивный текст? TextBox их не поддерживает.

dthrasher 03.03.2011 02:11

Не работает, если вы используете встроенные прогоны, и, как спросил HaxElit, я не уверен, что вы имеете в виду под шаблоном управления.

Ritch Melton 24.08.2011 02:33

-1 TextBlock не имеет ControlTemplate, потому что он является прямым подклассом FrameworkElement. TextBox, с другой стороны, является подклассом Control.

reSPAWNed 29.08.2013 14:21

Почему никто не может читать? OP явно сказал, что необходим TextBlock, а не TextBox, потому что TextBlock поддерживает встроенное форматирование, а TextBox - нет. Почему такие совершенно неправильные мусорные ответы получают множество голосов?

Jim Balter 15.04.2016 05:32
Ответ принят как подходящий

Вместо этого используйте TextBox с этими настройками, чтобы он был доступен только для чтения и выглядел как элемент управления TextBlock.

<TextBox Background = "Transparent"
         BorderThickness = "0"
         Text = "{Binding Text, Mode=OneWay}"
         IsReadOnly = "True"
         TextWrapping = "Wrap" />

У меня есть проект, который содержит много текстовых блоков / меток, я не могу превратить их в текстовые поля. Что я действительно хочу сделать, так это добавить волшебный стиль, применимый ко всем, к ресурсу уровня приложения, чтобы он повлиял на все Label / TextBlock, и сделать их внутренний текстовый презентатор как TextBox только для чтения, знаете ли вы какой-либо способ сделать это?

Shimmy Weitzhandler 18.01.2011 11:34

Вы можете добавить IsTabStop = "False" в зависимости от вашей ситуации.

Karsten 25.10.2012 15:51

+1 Очень красивое решение! Я добавил Padding = "0", так как в моем проекте нижняя часть текста была обрезана ... Возможно, из-за какого-то другого стиля.

reSPAWNed 29.08.2013 16:11

Единственная проблема, с которой я столкнулся, заключается в том, что вы теряете TextTrimming.

Mike Fuchs 21.08.2014 16:07

-1 Вопрос конкретно спрашивает, как сделать текстовый блок доступным для выбора. Потому что он не хочет терять свойство «Inlines» (которого нет в текстовых полях). Этот «ответ» просто предлагает сделать текстовое поле похожим на текстовый блок.

00jt 14.11.2014 18:07

@AlanLe Почему вы приняли этот ответ, когда вы прямо сказали, что не хотите? И почему за него проголосовали 147 невежественных людей?

Jim Balter 15.04.2016 05:27

@Ray: Почему? Что произойдет, если вы этого не сделаете?

Heinzi 18.10.2016 17:39

Я добавил решение ниже, которое позволяет текстовому блоку работать так, как было запрошено в исходном решении, я согласен, почему так много голосов за решение, которое точно соответствует тому, что, по его словам, он не хотел делать?

Billy Willoughby 02.10.2017 18:47

Согласитесь с @ 00jt - вопрос касается TextBlock, а НЕ TextBox. На мой взгляд, это не должно было быть выбрано в качестве ответа.

Bertie 21.03.2018 19:08

Поместив этот тип TextBox рядом с TextBlock, я заметил, что у TextBox есть небольшая «граница», даже если свойство Margin равно 0. Вы знаете, почему и как от него избавиться?

Kyle Delaney 26.06.2018 21:37

@KyleDelaney Это, наверное, Padding. Немного поздно, но может это кому-то поможет

Biesi Grr 07.08.2019 12:37

Существует альтернативное решение, которое может быть адаптировано к RichTextBox, указанному в этом Сообщение блога - он использовал триггер для замены шаблона элемента управления при наведении курсора на элемент управления - должно помочь с производительностью.

Ваша ссылка мертва. Пожалуйста, включите всю соответствующую информацию в ответ и используйте ссылки только в качестве цитат.

Jim Balter 15.04.2016 06:42


new TextBox
{
   Text = text,
   TextAlignment = TextAlignment.Center,
   TextWrapping = TextWrapping.Wrap,
   IsReadOnly = true,
   Background = Brushes.Transparent,
   BorderThickness = new Thickness()
         {
             Top = 0,
             Bottom = 0,
             Left = 0,
             Right = 0
         }
};

Это бесполезно. Прочтите вопрос, чтобы узнать, чего на самом деле хотел ОП.

Jim Balter 15.04.2016 06:55

TextBlock не имеет шаблона. Итак, чтобы добиться этого, нам нужно использовать TextBox, стиль которого изменен, чтобы вести себя как textBlock.

<Style x:Key = "TextBlockUsingTextBoxStyle" BasedOn = "{x:Null}" TargetType = "{x:Type TextBox}">
    <Setter Property = "Foreground" Value = "{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
    <Setter Property = "Background" Value = "Transparent"/>
    <Setter Property = "BorderBrush" Value = "{StaticResource TextBoxBorder}"/>
    <Setter Property = "BorderThickness" Value = "0"/>
    <Setter Property = "Padding" Value = "1"/>
    <Setter Property = "AllowDrop" Value = "true"/>
    <Setter Property = "FocusVisualStyle" Value = "{x:Null}"/>
    <Setter Property = "ScrollViewer.PanningMode" Value = "VerticalFirst"/>
    <Setter Property = "Stylus.IsFlicksEnabled" Value = "False"/>
    <Setter Property = "Template">
        <Setter.Value>
            <ControlTemplate TargetType = "{x:Type TextBox}">
                <TextBox BorderThickness = "{TemplateBinding BorderThickness}" IsReadOnly = "True" Text = "{TemplateBinding Text}" Background = "{x:Null}" BorderBrush = "{x:Null}" />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Какие преимущества предлагает этот подход по сравнению с другими ответами? Я ничего не вижу.

surfen 22.12.2011 05:09

Я пробовал этот стиль: TextBoxBorder не определен. Если закомментировать, работает нормально

sthiers 23.05.2014 11:58

Этот пример кода превосходен, он показывает, как получить цвет по умолчанию для TextBlock.

Contango 06.02.2015 18:54

Это довольно запутанно. Во-первых, x: Key «TextBlockUsingTextBoxStyle» перевернут; это должно быть TextBoxUsingTextBlockStyle. Во-вторых, OP уже знал, как стилизовать TextBox как TextBlock, но неоднократно говорил, что не может использовать это, потому что ему нужны встроенные строки для форматирования.

Jim Balter 15.04.2016 06:53

Примените этот стиль к своему TextBox и все (вдохновлено эта статья):

<Style x:Key = "SelectableTextBlockLikeStyle" TargetType = "TextBox" BasedOn = "{StaticResource {x:Type TextBox}}">
    <Setter Property = "IsReadOnly" Value = "True"/>
    <Setter Property = "IsTabStop" Value = "False"/>
    <Setter Property = "BorderThickness" Value = "0"/>
    <Setter Property = "Background" Value = "Transparent"/>
    <Setter Property = "Padding" Value = "-2,0,0,0"/>
    <!-- The Padding -2,0,0,0 is required because the TextBox
        seems to have an inherent "Padding" of about 2 pixels.
        Without the Padding property,
        the text seems to be 2 pixels to the left
        compared to a TextBlock
    -->
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property = "IsMouseOver" Value = "False" />
                <Condition Property = "IsFocused" Value = "False" />
            </MultiTrigger.Conditions>
            <Setter Property = "Template">
                <Setter.Value>
                <ControlTemplate TargetType = "{x:Type TextBox}">
                    <TextBlock Text = "{TemplateBinding Text}" 
                             FontSize = "{TemplateBinding FontSize}"
                             FontStyle = "{TemplateBinding FontStyle}"
                             FontFamily = "{TemplateBinding FontFamily}"
                             FontWeight = "{TemplateBinding FontWeight}"
                             TextWrapping = "{TemplateBinding TextWrapping}"
                             Foreground = "{DynamicResource NormalText}"
                             Padding = "0,0,0,0"
                                       />
                </ControlTemplate>
                </Setter.Value>
            </Setter>
        </MultiTrigger>
    </Style.Triggers>
</Style>

Кстати, на сегодняшний день ссылка на статью кажется мертвой

superjos 20.10.2015 21:49

Еще одно дополнение: Padding должен быть -2,0, -2,0. Внутри TextBox создается элемент управления TextBoxView со значением Margin по умолчанию 2,0,2,0. К сожалению, вы не можете переопределить его стиль, потому что он помечен как внутренний.

fdub 17.12.2015 14:14

Кажется, никто не умеет читать. OP нуждается в TextBlock, а не в TextBox в стиле TextBlock.

Jim Balter 15.04.2016 05:35

Я реализовал SelectableTextBlock в своей библиотеке элементов управления с открытым исходным кодом. Вы можете использовать это так:

<jc:SelectableTextBlock Text = "Some text" />

Здесь просто используется TextBox, как и многие другие ответы за много лет до этого.

Chris 16.08.2016 19:25

Мне не удалось найти ни одного примера реального ответа на вопрос. Во всех ответах использовалось текстовое поле или RichTextbox. Мне нужно было решение, позволяющее использовать TextBlock, и это решение, которое я создал.

Я считаю, что правильный способ сделать это - расширить класс TextBlock. Это код, который я использовал для расширения класса TextBlock, чтобы я мог выделить текст и скопировать его в буфер обмена. «sdo» - это ссылка на пространство имен, которую я использовал в WPF.

WPF с использованием расширенного класса:

xmlns:sdo = "clr-namespace:iFaceCaseMain"

<sdo:TextBlockMoo x:Name = "txtResults" Background = "Black" Margin = "5,5,5,5" 
      Foreground = "GreenYellow" FontSize = "14" FontFamily = "Courier New"></TextBlockMoo>

Код позади для расширенного класса:

public partial class TextBlockMoo : TextBlock 
{
    TextPointer StartSelectPosition;
    TextPointer EndSelectPosition;
    public String SelectedText = "";

    public delegate void TextSelectedHandler(string SelectedText);
    public event TextSelectedHandler TextSelected;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);
        Point mouseDownPoint = e.GetPosition(this);
        StartSelectPosition = this.GetPositionFromPoint(mouseDownPoint, true);            
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Point mouseUpPoint = e.GetPosition(this);
        EndSelectPosition = this.GetPositionFromPoint(mouseUpPoint, true);

        TextRange otr = new TextRange(this.ContentStart, this.ContentEnd);
        otr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.GreenYellow));

        TextRange ntr = new TextRange(StartSelectPosition, EndSelectPosition);
        ntr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.White));

        SelectedText = ntr.Text;
        if (!(TextSelected == null))
        {
            TextSelected(SelectedText);
        }
    }
}

Пример кода окна:

    public ucExample(IInstanceHost host, ref String WindowTitle, String ApplicationID, String Parameters)
    {
        InitializeComponent();
        /*Used to add selected text to clipboard*/
        this.txtResults.TextSelected += txtResults_TextSelected;
    }

    void txtResults_TextSelected(string SelectedText)
    {
        Clipboard.SetText(SelectedText);
    }

Это должен быть принятый ответ! Никаких хаков с отражением, без использования TextBox ... И его можно легко реорганизовать в многоразовое поведение. Очень мило спасибо!

Thomas Levesque 07.01.2020 14:22

Согласно Центр разработки для Windows:

TextBlock.IsTextSelectionEnabled property

[ Updated for UWP apps on Windows 10. For Windows 8.x articles, see the archive ]

Gets or sets a value that indicates whether text selection is enabled in the TextBlock, either through user action or calling selection-related API.

К сожалению, не совместим с Win7 (иногда это обязательное требование)

Yury Schkatula 10.03.2016 21:44

Амсвер кажется неверным. IsTextSelectionEnabled предназначен только для UWP, а не для WPF - в исходном вопросе указан WPF.

Puffin 29.03.2017 04:23

Really nice and easy solution, exactly what I wanted !

Приношу небольшие доработки

public class TextBlockMoo : TextBlock 
{
    public String SelectedText = "";

    public delegate void TextSelectedHandler(string SelectedText);
    public event TextSelectedHandler OnTextSelected;
    protected void RaiseEvent()
    {
        if (OnTextSelected != null){OnTextSelected(SelectedText);}
    }

    TextPointer StartSelectPosition;
    TextPointer EndSelectPosition;
    Brush _saveForeGroundBrush;
    Brush _saveBackGroundBrush;

    TextRange _ntr = null;

    protected override void OnMouseDown(MouseButtonEventArgs e)
    {
        base.OnMouseDown(e);

        if (_ntr!=null) {
            _ntr.ApplyPropertyValue(TextElement.ForegroundProperty, _saveForeGroundBrush);
            _ntr.ApplyPropertyValue(TextElement.BackgroundProperty, _saveBackGroundBrush);
        }

        Point mouseDownPoint = e.GetPosition(this);
        StartSelectPosition = this.GetPositionFromPoint(mouseDownPoint, true);            
    }

    protected override void OnMouseUp(MouseButtonEventArgs e)
    {
        base.OnMouseUp(e);
        Point mouseUpPoint = e.GetPosition(this);
        EndSelectPosition = this.GetPositionFromPoint(mouseUpPoint, true);

        _ntr = new TextRange(StartSelectPosition, EndSelectPosition);

        // keep saved
        _saveForeGroundBrush = (Brush)_ntr.GetPropertyValue(TextElement.ForegroundProperty);
        _saveBackGroundBrush = (Brush)_ntr.GetPropertyValue(TextElement.BackgroundProperty);
        // change style
        _ntr.ApplyPropertyValue(TextElement.BackgroundProperty, new SolidColorBrush(Colors.Yellow));
        _ntr.ApplyPropertyValue(TextElement.ForegroundProperty, new SolidColorBrush(Colors.DarkBlue));

        SelectedText = _ntr.Text;
    }
}

Пожалуйста, объясните, что вы изменили в ответе ниже. -1

Alex Hope O'Connor 14.03.2017 06:53

Строка 51 дает: System.ArgumentNullException: «Значение не может быть нулевым. Имя параметра: position1 '

rolls 06.05.2018 12:50

Хотя в вопросе действительно написано «Выбираемый», я считаю, что преднамеренные результаты заключаются в том, чтобы поместить текст в буфер обмена. Этого можно легко и элегантно достичь, добавив контекстное меню и пункт меню с именем copy, который помещает значение свойства Textblock Text в буфер обмена. Во всяком случае, это просто идея.

Все ответы здесь просто используют TextBox или пытаются реализовать выбор текста вручную, что приводит к плохой производительности или неродному поведению (мигающий курсор в TextBox, отсутствие поддержки клавиатуры в ручных реализациях и т. д.)

После нескольких часов копания и чтения Исходный код WPF я вместо этого обнаружил способ включить собственный выбор текста WPF для элементов управления TextBlock (или действительно любых других элементов управления). Большая часть функциональных возможностей выделения текста реализована в системном классе System.Windows.Documents.TextEditor.

Чтобы включить выделение текста для вашего элемента управления, вам нужно сделать две вещи:

  1. Позвоните в TextEditor.RegisterCommandHandlers() один раз, чтобы зарегистрировать класс обработчики событий

  2. Создайте экземпляр TextEditor для каждого экземпляра вашего класса и передайте ему базовый экземпляр вашего System.Windows.Documents.ITextContainer.

Также существует требование, чтобы для свойства Focusable вашего элемента управления было установлено значение True.

Это оно! Звучит просто, но, к сожалению, класс TextEditor отмечен как внутренний. Поэтому мне пришлось написать вокруг него обертку отражения:

class TextEditorWrapper
{
    private static readonly Type TextEditorType = Type.GetType("System.Windows.Documents.TextEditor, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
    private static readonly PropertyInfo IsReadOnlyProp = TextEditorType.GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly PropertyInfo TextViewProp = TextEditorType.GetProperty("TextView", BindingFlags.Instance | BindingFlags.NonPublic);
    private static readonly MethodInfo RegisterMethod = TextEditorType.GetMethod("RegisterCommandHandlers", 
        BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(Type), typeof(bool), typeof(bool), typeof(bool) }, null);

    private static readonly Type TextContainerType = Type.GetType("System.Windows.Documents.ITextContainer, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");
    private static readonly PropertyInfo TextContainerTextViewProp = TextContainerType.GetProperty("TextView");

    private static readonly PropertyInfo TextContainerProp = typeof(TextBlock).GetProperty("TextContainer", BindingFlags.Instance | BindingFlags.NonPublic);

    public static void RegisterCommandHandlers(Type controlType, bool acceptsRichContent, bool readOnly, bool registerEventListeners)
    {
        RegisterMethod.Invoke(null, new object[] { controlType, acceptsRichContent, readOnly, registerEventListeners });
    }

    public static TextEditorWrapper CreateFor(TextBlock tb)
    {
        var textContainer = TextContainerProp.GetValue(tb);

        var editor = new TextEditorWrapper(textContainer, tb, false);
        IsReadOnlyProp.SetValue(editor._editor, true);
        TextViewProp.SetValue(editor._editor, TextContainerTextViewProp.GetValue(textContainer));

        return editor;
    }

    private readonly object _editor;

    public TextEditorWrapper(object textContainer, FrameworkElement uiScope, bool isUndoEnabled)
    {
        _editor = Activator.CreateInstance(TextEditorType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance, 
            null, new[] { textContainer, uiScope, isUndoEnabled }, null);
    }
}

Я также создал SelectableTextBlock, производный от TextBlock, который выполняет шаги, указанные выше:

public class SelectableTextBlock : TextBlock
{
    static SelectableTextBlock()
    {
        FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true));
        TextEditorWrapper.RegisterCommandHandlers(typeof(SelectableTextBlock), true, true, true);

        // remove the focus rectangle around the control
        FocusVisualStyleProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata((object)null));
    }

    private readonly TextEditorWrapper _editor;

    public SelectableTextBlock()
    {
        _editor = TextEditorWrapper.CreateFor(this);
    }
}

Другой вариант - создать присоединенное свойство для TextBlock, чтобы разрешить выбор текста по запросу. В этом случае, чтобы снова отключить выбор, необходимо отсоединить TextEditor, используя эквивалент отражения этого кода:

_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;

как бы вы использовали класс SelectableTextBlock в другом xaml, который должен его содержать?

Yoav Feuerstein 15.08.2017 15:57

так же, как вы использовали бы любой другой настраиваемый элемент управления. см., например, stackoverflow.com/a/3768178/332528

torvin 16.08.2017 07:42

Я пробовал что-то подобное, но не смог сослаться на это из другого xaml. Кроме того, чтобы убедиться, может ли пользователь в предложенном вами решении выделить текст в нескольких элементах / объектах Run, находящихся внутри TextBlock?

Yoav Feuerstein 16.08.2017 09:37

Да, он работает с несколькими элементами Run и даже сохраняет форматирование при копировании

torvin 16.08.2017 10:40

В целом это работает неплохо. Однако не используйте это, если вы встроили Hyperlink в TextBlock ... он выдаст ExecutionEngineException.

DonBoitnott 09.04.2018 22:41

В чем улучшение по сравнению с ответом, который я дал, расширяя класс TextBlock? Это выглядит сложнее, и я пытаюсь понять, что делает его лучше? Я вижу несколько комментариев, в которых говорится: «Наконец-то используется TextBlock», но он также расширяет его. Пожалуйста, помогите мне понять. Спасибо; Билли

Billy Willoughby 04.06.2018 15:17

@BillyWilloughby ваше решение просто имитирует выделение. В нем отсутствует множество встроенных функций выбора: поддержка клавиатуры, контекстное меню и т. д. Мое решение включает функцию встроенного выбора.

torvin 05.06.2018 02:16

Предупреждение: хотя при нормальных обстоятельствах это работает достаточно хорошо, оно может вызвать неприятные сбои при использовании в других элементах управления или когда элементы управления встроены в него.

DonBoitnott 12.06.2018 21:51

Кажется, что это решение делает работает, когда TextBlock имеет встроенные Hyperlink, если Hyperlink не является последним встроенным в него. Добавление завершающего пустого Run к содержимому устраняет любую основную проблему, которая приводит к выбрасыванию ExecutionEngineException.

Anton Tykhyy 06.10.2018 13:05

Отлично! За исключением случаев, когда на TextTrimming = "CharacterEllipsis" установлен TextBlock, а доступной ширины недостаточно, при наведении указателя мыши на… происходит сбой с System.ArgumentException «Запрошенное расстояние выходит за пределы содержимого связанного документа». в System.Windows.Documents.TextPointer.InitializeOffset (внутреннее положение TextPo‌, расстояние Int32, направление LogicalDirection) :( Не знаю, есть ли обходной путь, кроме как оставить для TextTrimming значение None.

Dave Huang 26.02.2019 03:15

Если вы установите _editor.TextContainer.TextView на null, повторное включение выбора не будет работать. Включение / отключение работает без этой строки.

GregorMohorko 19.02.2020 13:42

public MainPage()
{
    this.InitializeComponent();
    ...
    ...
    ...
    //Make Start result text copiable
    TextBlockStatusStart.IsTextSelectionEnabled = true;
}

На это был дан ответ как таковой выше ... и работает только с UWP, а не с WPF

ΩmegaMan 29.06.2020 20:04

Добавление к ответу @torvin и, как упоминал @Dave Huang в комментариях, если у вас включен TextTrimming = "CharacterEllipsis", приложение вылетает при наведении курсора на многоточие.

Я пробовал другие варианты, упомянутые в потоке об использовании TextBox, но на самом деле это не кажется решением, поскольку он не показывает `` многоточие '', а также, если текст слишком длинный, чтобы соответствовать контейнеру, выбирающему содержимое текстовое поле «прокручивается» внутри, что не является поведением TextBlock.

Я думаю, что лучшим решением является ответ @torvin, но при наведении курсора на многоточие возникает неприятный сбой.

Я знаю, что это некрасиво, но внутренняя подписка / отказ от подписки на необработанные исключения и обработка исключения были единственным способом, который я нашел для решения этой проблемы, пожалуйста, поделитесь, если у кого-то есть лучшее решение :)

public class SelectableTextBlock : TextBlock
{
    static SelectableTextBlock()
    {
        FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true));
        TextEditorWrapper.RegisterCommandHandlers(typeof(SelectableTextBlock), true, true, true);

        // remove the focus rectangle around the control
        FocusVisualStyleProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata((object)null));
    }

    private readonly TextEditorWrapper _editor;

    public SelectableTextBlock()
    {
        _editor = TextEditorWrapper.CreateFor(this);

        this.Loaded += (sender, args) => {
            this.Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
            this.Dispatcher.UnhandledException += Dispatcher_UnhandledException;
        };
        this.Unloaded += (sender, args) => {
            this.Dispatcher.UnhandledException -= Dispatcher_UnhandledException;
        };
    }

    private void Dispatcher_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
    {
        if (!string.IsNullOrEmpty(e?.Exception?.StackTrace))
        {
            if (e.Exception.StackTrace.Contains("System.Windows.Controls.TextBlock.GetTextPositionFromDistance"))
            {
                e.Handled = true;
            }
        }
    }
}

Другие вопросы по теме