Bất kỳ cách nào để làm cho một textblock WPF có thể lựa chọn?


224

Tôi muốn làm cho văn bản được hiển thị trong Witty , một ứng dụng khách Twitter nguồn mở, có thể lựa chọn. Nó hiện đang được hiển thị bằng cách sử dụng một textblock tùy chỉnh. Tôi cần sử dụng TextBlock vì tôi đang làm việc với các dòng nội dung của textblock để hiển thị và định dạng @username và các liên kết dưới dạng siêu liên kết. Một yêu cầu thường xuyên là có thể sao chép-dán văn bản. Để làm được điều đó, tôi cần phải chọn TextBlock.

Tôi đã cố gắng làm cho nó hoạt động bằng cách hiển thị văn bản bằng cách sử dụng TextBox chỉ đọc để trông giống như một textblock nhưng điều này sẽ không hoạt động trong trường hợp của tôi vì TextBox không có đường thẳng. Nói cách khác, tôi không thể định kiểu hoặc định dạng văn bản trong TextBox riêng lẻ như tôi có thể với TextBlock.

Có ý kiến ​​gì không?


1
Tôi sẽ thử sử dụng điều khiển RichTextBox để xem nó có hoạt động không. Nhưng từ kinh nghiệm trước đây làm việc với richtextbox có liên quan nhiều hơn.
Alan Lê

Bạn đã nghĩ đến việc sử dụng FlowDocumentScrollViewer, với FlowDocument có chứa Đoạn và Chạy chưa? - Điều này hoạt động khá tốt đối với tôi khi tôi cần văn bản có thể chọn và mỗi Đoạn và Chạy có thể được tạo kiểu riêng.
BrainSlugs83

Đã thử một số cách giải quyết dưới đây, FlowDocumentScrollViewer là con đường phía trước. Nó dường như chiếm một vị trí trung gian hữu ích giữa RichTextBox và TextBlock.
Tom Makin

bỏ phiếu để chấp nhận một câu trả lời không phù hợp với yêu cầu của bạn.
Blechdose

Câu trả lời:


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

6
Tôi có một dự án chứa nhiều TextBlocks / Nhãn, tôi thực sự không thể biến chúng thành TextBoxes. Những gì tôi muốn làm là, thêm Kiểu áp dụng ma thuật cho tài nguyên cấp ứng dụng để nó sẽ ảnh hưởng đến tất cả Nhãn / TextBlock và làm cho người trình bày văn bản nội bộ của họ dưới dạng TextBox chỉ đọc, bạn có biết cách nào không để làm điều đó?
Shimmy Weitzhandler

5
Bạn có thể muốn thêm IsTabStop = "Sai" tùy theo tình huống của bạn
Karsten

1
+1 giải pháp rất hay! Tôi đã thêm một Padding = "0", vì trong dự án của tôi, phần dưới của văn bản đã bị cắt ... Có lẽ vì một phong cách ở một nơi khác.
reSPAWNed

123
-1 Câu hỏi đặc biệt hỏi làm thế nào để tạo một textblock có thể lựa chọn. Bởi vì anh ta không muốn mất thuộc tính "Inlines" (mà textBoxes không có). 'Câu trả lời' này chỉ gợi ý để làm cho một hộp văn bản trông giống như một văn bản.
00jt

19
@AlanLe Tại sao bạn chấp nhận câu trả lời này khi đó là những gì bạn nói rõ ràng bạn không muốn? Và tại sao 147 người không biết gì lại ủng hộ nó?
Jim Balter

66

Tất cả các câu trả lời ở đây chỉ là sử dụng TextBoxhoặc cố gắng thực hiện lựa chọn văn bản theo cách thủ công, điều này dẫn đến hiệu suất kém hoặc hành vi không bản địa (nhấp nháy TextBox, không hỗ trợ bàn phím khi triển khai thủ công, v.v.)

Sau nhiều giờ tìm hiểu và đọc mã nguồn WPF , thay vào đó tôi phát hiện ra một cách cho phép lựa chọn văn bản WPF gốc cho các TextBlockđiều khiển (hoặc thực sự là bất kỳ điều khiển nào khác). Hầu hết các chức năng xung quanh lựa chọn văn bản được thực hiện trong System.Windows.Documents.TextEditorlớp hệ thống.

Để cho phép lựa chọn văn bản cho điều khiển của bạn, bạn cần thực hiện hai điều:

  1. Gọi TextEditor.RegisterCommandHandlers()một lần để đăng ký xử lý sự kiện lớp

  2. Tạo một thể hiện TextEditorcho từng thể hiện của lớp của bạn và truyền thể hiện cơ bản của bạn System.Windows.Documents.ITextContainercho nó

Ngoài ra còn có một yêu cầu là Focusabletài sản kiểm soát của bạn được đặt thành True.

Đây là nó! Nghe có vẻ dễ, nhưng tiếc TextEditorlà lớp được đánh dấu là nội bộ. Vì vậy, tôi đã phải viết một trình bao bọc phản chiếu xung quanh nó:

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

Tôi cũng đã tạo ra một SelectableTextBlockdẫn xuất từ TextBlockđó thực hiện các bước được ghi chú ở trên:

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

Một tùy chọn khác là tạo một thuộc tính đính kèm TextBlockđể cho phép lựa chọn văn bản theo yêu cầu. Trong trường hợp này, để vô hiệu hóa lựa chọn một lần nữa, người ta cần tách a TextEditorbằng cách sử dụng phản xạ tương đương với mã này:

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

1
Làm thế nào bạn sẽ sử dụng lớp SelectableTextBlock trong một xaml khác có chứa nó?
Yoav Feuerstein

1
giống như cách bạn sẽ sử dụng bất kỳ điều khiển tùy chỉnh nào khác. xem stackoverflow.com/a/3768178/332528 chẳng hạn
torvin

3
@BillyWilloughby giải pháp của bạn chỉ cần mô phỏng lựa chọn. Nó thiếu rất nhiều tính năng lựa chọn riêng: hỗ trợ bàn phím, menu ngữ cảnh, vv Giải pháp của tôi cho phép tính năng chọn gốc
torvin

3
Có vẻ như giải pháp này không hoạt động khi TextBlockđã nhúng Hyperlinks miễn Hyperlinklà không phải là dòng cuối cùng trong nó. Thêm một dấu trống Runvào nội dung sẽ khắc phục bất cứ vấn đề tiềm ẩn nào dẫn đến việc ExecutionEngineExceptionbị ném.
Anton Tykhyy

2
Điều đó thật tuyệt! Ngoại trừ nếu bạn có TextTrimming="CharacterEllipsis"trên TextBlockvà chiều rộng có sẵn là không đủ, nếu bạn di chuyển con trỏ chuột qua máy tính, nó sẽ gặp sự cố với System.ArgumentException "Khoảng cách được yêu cầu nằm ngoài nội dung của tài liệu được liên kết." tại System.Windows.Document.TextPulum.Initialize Offerset (vị trí TextPulum, khoảng cách Int32, hướng LogicalDirection) :( Không biết có cách khắc phục nào khác ngoài việc đặt TextTrinkle thành Không.
Dave Huang

32

Tôi đã không thể tìm thấy bất kỳ ví dụ về việc thực sự trả lời câu hỏi. Tất cả các câu trả lời đã sử dụng Textbox hoặc RichTextbox. Tôi cần một giải pháp cho phép tôi sử dụng TextBlock và đây là giải pháp tôi đã tạo.

Tôi tin rằng cách chính xác để làm điều này là mở rộng lớp TextBlock. Đây là mã tôi đã sử dụng để mở rộng lớp TextBlock để cho phép tôi chọn văn bản và sao chép nó vào clipboard. "sdo" là tham chiếu không gian tên tôi đã sử dụng trong WPF.

WPF sử dụng lớp mở rộng:

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>

Mã phía sau cho lớp mở rộng:

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

Mã cửa sổ mẫu:

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

1
Đây phải là câu trả lời được chấp nhận! Không có hack phản chiếu, không sử dụng TextBox ... Và nó có thể dễ dàng được tái cấu trúc thành một hành vi có thể sử dụng lại. Rất đẹp, cảm ơn!
Thomas Levesque

19

Áp dụng kiểu này cho TextBox của bạn và đó là (lấy cảm hứng từ bài viết này ):

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

1
BTW tính đến ngày hôm nay, liên kết đến bài viết dường như đã chết
superjos

2
Một bổ sung khác: Đệm nên là -2,0, -2,0. Bên trong TextBox, một điều khiển TextBoxView được tạo ra có Margin mặc định là 2,0,2,0. Thật không may, bạn không thể xác định lại Phong cách của nó vì nó được đánh dấu nội bộ.
fdub

11
Không ai có thể đọc được. OP cần có TextBlock, không phải là TextBox theo kiểu như TextBlock.
Jim Balter

18

Tạo ControlTemplate cho TextBlock và đặt TextBox bên trong với tập thuộc tính chỉ đọc. Hoặc chỉ cần sử dụng TextBox và làm cho nó chỉ đọc, sau đó bạn có thể thay đổi TextBox.Style để làm cho nó trông giống như TextBlock.


11
Làm cách nào để bạn thiết lập ControlTemplate cho TextBlock? Tôi không thể tìm thấy tài sản?
HaxElit

18
Cách tiếp cận này sẽ không hoạt động nếu TextBlock của bạn có các thành phần nội tuyến bên trong nó. Điều gì xảy ra nếu bạn có siêu liên kết hoặc chạy văn bản in đậm hoặc in nghiêng? TextBox không hỗ trợ những thứ này.
dthrasher

1
Không hoạt động nếu bạn đang sử dụng chạy nội tuyến và như HaxElit đã hỏi, tôi không chắc ý của bạn về mẫu điều khiển.
Ritch Melton

7
-1 TextBlock không có ControlTemplate vì đây là lớp con trực tiếp của FrameworkEuity. Mặt khác, TextBox là một lớp con của Control.
reSPAWNed

5
Tại sao không ai đọc được? OP nói rõ ràng là cần có TextBlock, không phải là TextBox, vì TextBlock hỗ trợ định dạng nội tuyến và TextBox thì không. Tại sao các câu trả lời rác hoàn toàn sai như thế này lại nhận được rất nhiều sự ủng hộ?
Jim Balter

10

Tôi không chắc liệu bạn có thể chọn TextBlock được không, nhưng một tùy chọn khác sẽ là sử dụng RichTextBox - nó giống như một TextBox như bạn đề xuất, nhưng hỗ trợ định dạng bạn muốn.


1
Tôi đã thử làm điều này và trong quá trình phải làm cho RichTextBox liên kết với một thuộc tính phụ thuộc. Thật không may, các luồng dữ liệu cũ không được loại bỏ đúng cách và bộ nhớ bị rò rỉ như điên. Alan, tôi tự hỏi nếu bạn tìm thấy một cách xung quanh này?
John Noonan

@AlanLe Trong tất cả các câu trả lời ở đây, đây chỉ là một trong hai câu trả lời thực sự cho câu hỏi ... tất cả những người khác nói về việc tạo kiểu cho TextBox để trông giống như TextBlock, trong khi bỏ qua nhu cầu định dạng. Thật kỳ lạ, và thật không may, OP đã chấp nhận một trong những câu trả lời không phải đó, thay vì câu trả lời đúng để sử dụng RichTextBox thay vì TextBox.
Jim Balter

9

Theo Trung tâm Dev Windows :

Thuộc tính TextBlock.IsTextSelectionEnables

[Đã cập nhật cho các ứng dụng UWP trên Windows 10. Đối với các bài viết về Windows 8.x, hãy xem kho lưu trữ ]

Nhận hoặc đặt một giá trị cho biết liệu lựa chọn văn bản có được bật trong TextBlock hay không , thông qua hành động của người dùng hoặc gọi API liên quan đến lựa chọn.


5
Thật không may, không tương thích với Win7 (đôi khi nó là một-phải yêu cầu)
Yury Schkatula

24
Amswer xuất hiện không chính xác. IsTextSelectionEnables chỉ dành cho UWP, không phải WPF - câu hỏi ban đầu đã chỉ định WPF.
Puffin

6

Trong khi câu hỏi có nội dung 'Có thể lựa chọn', tôi tin rằng kết quả có chủ ý là đưa văn bản vào bảng tạm. Điều này có thể dễ dàng và thanh lịch đạt được bằng cách thêm một Menu ngữ cảnh và mục menu được gọi là bản sao đặt giá trị thuộc tính Textblock Text trong clipboard. Dù sao cũng chỉ là một ý tưởng.


4

TextBlock không có mẫu. Vì vậy, inorder để đạt được điều này, chúng ta cần sử dụng một TextBox có kiểu dáng được thay đổi để hoạt động như một 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>

Cách tiếp cận này cung cấp những lợi thế so với các câu trả lời khác? Tôi không thấy cái nào cả.
lướt

Tôi đã thử kiểu này: TextBoxBorder không được xác định. Nếu bạn nhận xét nó, nó hoạt động tốt
sthiers

Mã ví dụ này là tuyệt vời, nó chỉ ra cách lấy màu mặc định cho TextBlock.
Contango 6/2/2015

1
Điều này khá bối rối. Đầu tiên, x: Key, "TextBlockUsingTextBoxStyle", là ngược; nó phải là "TextBoxUsingTextBlockStyle". Thứ hai, OP đã biết cách tạo kiểu cho TextBox như TextBlock, nhưng nói lặp đi lặp lại rằng anh ta không thể sử dụng điều đó vì anh ta cần nội tuyến để định dạng.
Jim Balter

2

Có một giải pháp thay thế có thể thích ứng với RichTextBox được thay thế trong bài đăng trên blog này - nó đã sử dụng một trình kích hoạt để trao đổi mẫu điều khiển khi sử dụng di chuyển qua điều khiển - sẽ giúp hiệu suất


1
Liên kết của bạn đã chết. Vui lòng bao gồm tất cả các thông tin có liên quan trong một câu trả lời và chỉ sử dụng các liên kết như trích dẫn.
Jim Balter

1

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


1
Điều này không hữu ích. Đọc câu hỏi để xem OP thực sự muốn gì.
Jim Balter

1

Thêm vào câu trả lời của @ torvin và như @Dave Huang đã đề cập trong các nhận xét nếu bạn đã TextTrimming="CharacterEllipsis"bật ứng dụng gặp sự cố khi bạn di chuột qua dấu chấm lửng.

Tôi đã thử các tùy chọn khác được đề cập trong luồng về cách sử dụng TextBox nhưng thực sự nó không phải là giải pháp vì nó không hiển thị 'dấu chấm lửng' và nếu văn bản quá dài để phù hợp với vùng chứa chọn nội dung của hộp văn bản 'cuộn' bên trong không phải là hành vi TextBlock.

Tôi nghĩ rằng giải pháp tốt nhất là câu trả lời của @ torvin nhưng gặp sự cố khó chịu khi di chuột qua dấu chấm lửng.

Tôi biết nó không đẹp, nhưng đăng ký / hủy đăng ký nội bộ để xử lý các ngoại lệ và xử lý ngoại lệ là cách duy nhất tôi tìm thấy để giải quyết vấn đề này, vui lòng chia sẻ nếu ai đó có giải pháp tốt hơn :)

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

Tôi đã triển khai SelectableTextBlock trong thư viện điều khiển mã nguồn mở của mình. Bạn có thể sử dụng nó như thế này:

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

4
Điều này chỉ sử dụng một TextBox, giống như rất nhiều câu trả lời khác từ nhiều năm trước.
Chris

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

-1
Really nice and easy solution, exactly what I wanted !

Tôi mang đến một số sửa đổi nhỏ

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
Bạn cần giải thích những gì bạn đã thay đổi từ câu trả lời dưới đây. -1
Alex Hope O'Connor

Dòng 51 đưa ra: System.ArgumentNullException: 'Giá trị không thể là null. Tên tham số: vị trí1 '
cuộn
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.