如何允许TextBlock的文本是可选的?

我试图让它通过显示文本使用只读文本框样式看起来像一个文本块,但这不会在我的情况下工作,因为一个文本框没有内联。换句话说,如何使它具有可选性?


当前回答

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

其他回答

应用这种风格到你的文本框,这就是它(灵感来自这篇文章):

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

使用带有这些设置的TextBox来使其只读,看起来像一个TextBlock控件。

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

创建控件模板的TextBlock,并把一个文本框内readonly属性设置。 或者只是使用文本框,使其只读,然后你可以改变文本框。样式,使它看起来像TextBlock。

我找不到任何能真正回答这个问题的例子。所有的答案都使用了一个文本框或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);
    }

为torvin的代码添加了Selection & SelectionChanged事件

public class SelectableTextBlock : TextBlock
{

    static readonly Type TextEditorType
    = Type.GetType("System.Windows.Documents.TextEditor, PresentationFramework, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

    static readonly PropertyInfo IsReadOnlyProp
        = TextEditorType.GetProperty("IsReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);

    static readonly PropertyInfo TextViewProp
        = TextEditorType.GetProperty("TextView", BindingFlags.Instance | BindingFlags.NonPublic);

    static readonly MethodInfo RegisterMethod
        = TextEditorType.GetMethod("RegisterCommandHandlers",
        BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(Type), typeof(bool), typeof(bool), typeof(bool) }, null);

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

    static readonly PropertyInfo TextContainerTextSelectionProp
        = TextContainerType.GetProperty("TextSelection");

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

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

    static SelectableTextBlock()
    {
        FocusableProperty.OverrideMetadata(typeof(SelectableTextBlock), new FrameworkPropertyMetadata(true));
        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;
    object? textContainer;
    object? editor;
    public TextSelection TextSelection { get; private set; }

    public SelectableTextBlock()
    {
        textContainer = TextContainerProp.GetValue(this);

        editor = Activator.CreateInstance(TextEditorType, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.CreateInstance,
            null, new[] { textContainer, this, false }, null);


        IsReadOnlyProp.SetValue(editor, true);
        TextViewProp.SetValue(editor, TextContainerTextViewProp.GetValue(textContainer));

        TextSelection = (TextSelection)TextContainerTextSelectionProp.GetValue(textContainer);
        TextSelection.Changed += (s, e) => OnSelectionChanged?.Invoke(this, e);
    }

    public event EventHandler OnSelectionChanged;
}