Adakah cara untuk membuat blokir WPF dapat dipilih?

224

Saya ingin membuat teks ditampilkan di Witty , klien Twitter open source, dapat dipilih. Saat ini ditampilkan menggunakan blok teks khusus. Saya perlu menggunakan TextBlock karena saya bekerja dengan inline textblock untuk menampilkan dan memformat @namapengguna dan tautan sebagai hyperlink. Permintaan yang sering adalah untuk dapat menyalin-menempelkan teks. Untuk melakukan itu saya perlu membuat TextBlock dipilih.

Saya mencoba membuatnya bekerja dengan menampilkan teks menggunakan TextBox read-only yang ditata agar terlihat seperti textblock tetapi ini tidak akan berfungsi dalam kasus saya karena TextBox tidak memiliki inline. Dengan kata lain, saya tidak bisa mendesain atau memformat teks dalam TextBox secara individual seperti saya bisa dengan TextBlock.

Ada ide?

Alan Le
sumber
1
Saya akan mencoba menggunakan kontrol RichTextBox untuk melihat apakah itu akan berhasil. Tetapi dari pengalaman sebelumnya bekerja dengan richtextbox jauh lebih terlibat.
Alan Le
Pernahkah Anda berpikir tentang menggunakan FlowDocumentScrollViewer, dengan FlowDocument yang berisi Paragraph dan Runs? - Ini berfungsi dengan baik bagi saya ketika saya membutuhkan teks yang dapat dipilih, dan setiap Paragraf dan Run dapat ditata secara terpisah.
BrainSlugs83
Setelah mencoba beberapa solusi di bawah ini, FlowDocumentScrollViewer adalah jalan ke depan. Tampaknya menempati jalan tengah yang berguna antara RichTextBox dan TextBlock.
Tom Makin
memilih untuk menerima jawaban yang tidak sesuai dengan kebutuhan Anda.
Blechdose

Jawaban:

218
<TextBox Background="Transparent"
         BorderThickness="0"
         Text="{Binding Text, Mode=OneWay}"
         IsReadOnly="True"
         TextWrapping="Wrap" />
MSB
sumber
6
Saya memiliki proyek yang berisi banyak TextBlocks / Label, saya tidak bisa mengubahnya menjadi TextBox. Yang ingin saya lakukan adalah, tambahkan sulap yang berlaku untuk semua Gaya ke sumber daya tingkat aplikasi sehingga harus memengaruhi semua Label / TextBlock, dan menjadikan penyaji teks internal mereka sebagai TextBox yang bisa dibaca, apakah Anda tahu cara apa pun untuk melakukannya?
Shimmy Weitzhandler
5
Anda mungkin ingin menambahkan IsTabStop = "Salah" tergantung pada situasi Anda
Karsten
1
+1 Solusi yang sangat bagus! Saya menambahkan Padding = "0", karena dalam proyek saya bagian bawah teks terpotong ... Mungkin karena gaya di tempat lain.
reSPAWNed
123
-1 Pertanyaan secara khusus menanyakan cara membuat blokir teks dapat dipilih. Karena dia tidak ingin kehilangan properti "Inlines" (yang tidak dimiliki kotak teks). 'Jawaban' ini hanya menyarankan untuk membuat kotak teks terlihat seperti blok teks.
00jt
19
@AlanLe Mengapa Anda menerima jawaban ini ketika itu yang secara eksplisit Anda katakan tidak Anda inginkan? Dan mengapa 147 orang yang tidak mengerti membenarkan hal itu?
Jim Balter
66

Semua jawaban di sini hanya menggunakan TextBoxatau mencoba menerapkan pemilihan teks secara manual, yang mengarah pada kinerja yang buruk atau perilaku non-pribumi (tanda sisipan berkedip TextBox, tidak ada dukungan keyboard dalam implementasi manual, dll.)

Setelah berjam-jam menggali dan membaca kode sumber WPF , saya malah menemukan cara mengaktifkan pemilihan teks WPF asli untuk TextBlockkontrol (atau benar-benar kontrol lain). Sebagian besar fungsi di sekitar pemilihan teks diimplementasikan dalam System.Windows.Documents.TextEditorkelas sistem.

Untuk mengaktifkan pemilihan teks untuk kontrol Anda, Anda perlu melakukan dua hal:

  1. Panggil TextEditor.RegisterCommandHandlers()sekali untuk mendaftarkan penangan acara kelas

  2. Buat instance TextEditoruntuk setiap instance dari kelas Anda dan berikan instance Anda System.Windows.Documents.ITextContaineruntuknya

Ada juga persyaratan yang mengatur Focusableproperti kontrol Anda True.

Ini dia! Kedengarannya mudah, tetapi sayangnya TextEditorkelas ditandai sebagai internal. Jadi saya harus menulis pembungkus refleksi di sekitarnya:

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

Saya juga membuat SelectableTextBlockturunan dari TextBlockyang mengambil langkah-langkah yang disebutkan di atas:

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

Pilihan lain adalah membuat properti terlampir untuk TextBlockmemungkinkan pemilihan teks sesuai permintaan. Dalam hal ini, untuk menonaktifkan seleksi lagi, kita perlu melepaskan a TextEditordengan menggunakan refleksi setara dari kode ini:

_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;
Torvin
sumber
1
bagaimana Anda menggunakan kelas SelectableTextBlock dalam xaml lain yang seharusnya berisi itu?
Yoav Feuerstein
1
cara yang sama Anda akan menggunakan kontrol kustom lainnya lihat stackoverflow.com/a/3768178/332528 misalnya
torvin
3
@BillyWilloughby solusi Anda hanya meniru seleksi. Ini tidak memiliki banyak fitur pemilihan asli: dukungan keyboard, menu konteks dll. Solusi saya memungkinkan fitur pemilihan asli
torvin
3
Tampaknya solusi ini berfungsi ketika TextBlocksudah tertanam Hyperlinkselama Hyperlinkbukan inline terakhir di dalamnya. Menambahkan trailing blank Runke perbaikan konten apa pun masalah yang mendasarinya adalah hasil ExecutionEngineExceptionpelemparan.
Anton Tykhyy
2
Ini bagus! Kecuali jika Anda memiliki TextTrimming="CharacterEllipsis"di TextBlockdan lebar yang tersedia tidak mencukupi, jika Anda memindahkan pointer mouse di atas ..., itu crash dengan System.ArgumentException "jarak Diminta berada di luar isi dokumen terkait." di System.Windows.Documents.TextPointer.InitializeOffset (posisi TextPointer, jarak Int32, arah LogicalDirection) :( Tidak tahu apakah ada solusi selain meninggalkan TextTrimming diatur ke Tidak ada.
Dave Huang
32

Saya tidak dapat menemukan contoh untuk benar-benar menjawab pertanyaan itu. Semua jawaban menggunakan Textbox atau RichTextbox. Saya membutuhkan solusi yang memungkinkan saya untuk menggunakan TextBlock, dan ini adalah solusi yang saya buat.

Saya percaya cara yang benar untuk melakukan ini adalah memperluas kelas TextBlock. Ini adalah kode yang saya gunakan untuk memperluas kelas TextBlock untuk memungkinkan saya memilih teks dan menyalinnya ke clipboard. "sdo" adalah referensi namespace yang saya gunakan di WPF.

WPF Menggunakan Extended Class:

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>

Kode di Belakang untuk Kelas Lanjutan:

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

Contoh Jendela Kode:

    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);
    }
Billy Willoughby
sumber
1
Ini harus menjadi jawaban yang diterima! Tidak ada peretasan refleksi, tidak menggunakan TextBox ... Dan itu bisa dengan mudah di refactored menjadi perilaku yang dapat digunakan kembali. Bagus sekali, terima kasih!
Thomas Levesque
19

Terapkan gaya ini ke TextBox Anda dan hanya itu (terinspirasi dari artikel ini ):

<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>
sakito
sumber
1
BTW pada hari ini, tautan ke artikel tampaknya mati
superjos
2
Tambahan lain: Padding harus -2,0, -2,0. Di dalam TextBox, kontrol TextBoxView dibuat yang memiliki Margin default 2,0,2,0. Sayangnya, Anda tidak dapat mendefinisikan ulang Gaya karena ditandai internal.
fdub
11
Sepertinya tidak ada yang bisa membaca. OP membutuhkan TextBlock, bukan TextBox yang ditata seperti TextBlock.
Jim Balter
18

Buat ControlTemplate untuk TextBlock dan letakkan TextBox di dalamnya dengan set properti readonly. Atau cukup gunakan TextBox dan buat hanya dibaca, maka Anda dapat mengubah TextBox. Gaya untuk membuatnya tampak seperti TextBlock.

Jobi Joy
sumber
11
Bagaimana Anda mengatur ControlTemplate untuk TextBlock? Saya tidak dapat menemukan properti?
HaxElit
18
Pendekatan ini tidak akan berfungsi jika TextBlock Anda memiliki elemen sebaris di dalamnya. Bagaimana jika Anda memiliki hyperlink atau teks tebal atau miring? TextBox tidak mendukung ini.
dthrasher
1
Tidak berfungsi jika Anda menggunakan inline run, dan seperti yang diminta HaxElit, saya tidak yakin apa yang Anda maksud dengan template kontrol.
Ritch Melton
7
-1 TextBlock tidak memiliki ControlTemplate karena ini adalah subclass langsung dari FrameworkElement. TextBox di sisi lain adalah subkelas Kontrol.
reSPAWNed
5
Mengapa tidak ada yang bisa membaca? OP secara eksplisit mengatakan TextBlock diperlukan, bukan TextBox, karena TextBlock mendukung format inline dan TextBox tidak. Mengapa jawaban sampah yang salah seperti ini mendapat banyak upvotes?
Jim Balter
10

Saya tidak yakin apakah Anda dapat membuat TextBlock dapat dipilih, tetapi opsi lain adalah menggunakan RichTextBox - ini seperti TextBox seperti yang Anda sarankan, tetapi mendukung pemformatan yang Anda inginkan.

Bruce
sumber
1
Saya mencoba melakukan ini, dan dalam proses harus membuat RichTextBox terikat dengan properti dependensi. Sayangnya dokumen aliran lama tidak dibuang dengan benar dan memori bocor seperti orang gila. Alan, saya ingin tahu apakah Anda menemukan jalan keluarnya?
John Noonan
@AlanLe Dari semua respons di sini, ini hanya satu dari dua yang benar-benar menjawab pertanyaan yang diajukan ... semua yang lain berbicara tentang menata TextBox agar terlihat seperti TextBlock, sementara mengabaikan kebutuhan untuk memformat. Aneh, dan sangat disayangkan, OP menerima salah satu dari jawaban itu, bukan jawaban yang benar untuk menggunakan RichTextBox daripada TextBox.
Jim Balter
9

Menurut Windows Dev Center :

Properti TextBlock.IsTextSelectionEnabled

[Diperbarui untuk aplikasi UWP pada Windows 10. Untuk artikel Windows 8.x, lihat arsip ]

Mendapat atau menetapkan nilai yang menunjukkan apakah pemilihan teks diaktifkan di TextBlock , baik melalui aksi pengguna atau memanggil API terkait pemilihan.

Jack Pines
sumber
5
Sayangnya, tidak kompatibel dengan Win7 (kadang-kadang ini merupakan keharusan)
Yury Schkatula
24
Amswer tampak salah. IsTextSelectionEnabled hanya untuk UWP, bukan WPF - pertanyaan awal memang menentukan WPF.
Puffin
6

Sementara pertanyaannya memang mengatakan 'Dapat Dipilih' Saya percaya hasil yang disengaja adalah untuk mendapatkan teks ke clipboard. Ini dapat dengan mudah dan elegan dicapai dengan menambahkan Menu Konteks dan item menu yang disebut salinan yang menempatkan nilai properti Textblock Text di clipboard. Hanya sebuah ide.

Sederhana
sumber
4

TextBlock tidak memiliki templat. Jadi untuk mencapai ini, kita perlu menggunakan TextBox yang gayanya diubah untuk berperilaku sebagai 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>
Saraf Talukder
sumber
Apa kelebihan yang ditawarkan pendekatan ini dibandingkan dengan jawaban lain? Saya tidak melihat apa pun.
Berselancar
Saya mencoba gaya ini: TextBoxBorder tidak didefinisikan. Jika Anda berkomentar, itu berfungsi dengan baik
sthiers
Contoh kode ini sangat bagus, ini menunjukkan cara mendapatkan warna default untuk TextBlock.
Contango
1
Ini agak membingungkan. Pertama, x: Key, "TextBlockUsingTextBoxStyle", mundur; seharusnya "TextBoxUsingTextBlockStyle". Kedua, OP sudah tahu cara mendesain TextBox seperti TextBlock, tetapi berulang kali mengatakan bahwa dia tidak bisa menggunakannya karena dia membutuhkan inline untuk pemformatan.
Jim Balter
2

Ada solusi alternatif yang mungkin dapat disesuaikan dengan RichTextBox yang disediakan dalam posting blog ini - ini menggunakan pemicu untuk menukar templat kontrol saat penggunaan melayang di atas kontrol - akan membantu kinerja

Richard
sumber
1
Tautan Anda mati. Harap sertakan semua informasi yang relevan dalam jawaban dan gunakan tautan hanya sebagai kutipan.
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
         }
};

Lu55
sumber
1
Ini tidak membantu. Baca pertanyaan untuk melihat apa yang sebenarnya diinginkan OP.
Jim Balter
1

Menambahkan ke jawaban @ torvin dan sebagai @ David Huang disebutkan dalam komentar jika Anda telah TextTrimming="CharacterEllipsis"mengaktifkan aplikasi crash ketika Anda mengarahkan kursor ke elipsis.

Saya mencoba opsi lain yang disebutkan di utas tentang menggunakan TextBox tapi itu benar-benar tampaknya tidak menjadi solusi baik karena tidak menunjukkan 'ellipsis' dan juga jika teks terlalu panjang untuk muat wadah memilih konten dari kotak teks 'gulir' secara internal yang bukan merupakan perilaku TextBlock.

Saya pikir solusi terbaik adalah jawaban @ torvin tetapi memiliki crash jahat ketika melayang di atas ellipsis.

Saya tahu ini tidak cantik, tetapi berlangganan / berhenti berlangganan secara internal untuk pengecualian yang tidak ditangani dan menangani pengecualian adalah satu-satunya cara yang saya temukan untuk menyelesaikan masalah ini, silakan bagikan jika seseorang memiliki solusi yang lebih baik :)

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;
            }
        }
    }
}
Rauland
sumber
0

Saya telah mengimplementasikan SelectableTextBlock di pustaka kontrol opensource saya. Anda bisa menggunakannya seperti ini:

<jc:SelectableTextBlock Text="Some text" />
Robert Važan
sumber
4
Ini hanya menggunakan TextBox, seperti banyak jawaban lain dari bertahun-tahun sebelumnya.
Chris
0
public MainPage()
{
    this.InitializeComponent();
    ...
    ...
    ...
    //Make Start result text copiable
    TextBlockStatusStart.IsTextSelectionEnabled = true;
}
Malaikat T
sumber
-1
Really nice and easy solution, exactly what I wanted !

Saya membawa beberapa modifikasi kecil

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;
    }
}
Titwan
sumber
1
Anda perlu menjelaskan apa yang telah Anda ubah dari jawaban di bawah ini. -1
Alex Hope O'Connor
Baris 51 memberi: System.ArgumentNullException: 'Nilai tidak boleh nol. Nama parameter: position1 '
rolls