Любой способ сделать текстовый блок WPF выбираемым? - PullRequest
204 голосов
/ 26 сентября 2008

Я хочу, чтобы текст отображался в Witty , клиенте Twitter с открытым исходным кодом, по выбору. В настоящее время он отображается с использованием пользовательского текстового блока. Мне нужно использовать TextBlock, потому что я работаю со встроенными текстовыми блоками для отображения и форматирования @username и ссылок как гиперссылок. Частым запросом является возможность копирования и вставки текста. Для этого мне нужно сделать TextBlock доступным для выбора.

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

Есть идеи?

Ответы [ 15 ]

1 голос
/ 07 июля 2014

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

<jc:SelectableTextBlock Text="Some text" />
1 голос
/ 10 ноября 2010

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

0 голосов
/ 28 марта 2019

Добавление к ответу @ 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;
            }
        }
    }
}
0 голосов
/ 14 ноября 2018
public MainPage()
{
    this.InitializeComponent();
    ...
    ...
    ...
    //Make Start result text copiable
    TextBlockStatusStart.IsTextSelectionEnabled = true;
}
0 голосов
/ 25 марта 2016
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;
    }
}
...