当前位置:  开发笔记 > Android > 正文

有没有什么方法可以选择WPF文本块?

如何解决《有没有什么方法可以选择WPF文本块?》经验,为你挑选了7个好方法。

我想让文本显示在Witty中,这是一个开源的Twitter客户端,可以选择.它目前使用自定义文本块显示.我需要使用TextBlock,因为我正在使用textblock的内联来显示和格式化@username和链接作为超链接.经常请求是能够复制粘贴文本.为了做到这一点,我需要使TextBlock可选.

我试图通过使用只读TextBox来显示文本,使其看起来像文本块,但这在我的情况下不起作用,因为TextBox没有内联.换句话说,我不能单独设置或格式化TextBox中的文本,就像我可以使用TextBlock一样.

有任何想法吗?



1> 小智..:


-1该问题专门询问如何使文本块可选.因为他不想丢失"Inlines"属性(textBoxes没有).这个"答案"只是建议让文本框看起来像文本块.
@AlanLe为什么你接受这个答案时,你明确表示你不想要的?为什么147个无能为力的人投票呢?
我有一个包含许多TextBlocks/Labels的项目,我无法真正将它们变成TextBoxes.我想要做的是,为应用级资源添加一个魔术应用于所有样式,这样它应该影响所有的Label/TextBlock,并使其内部文本呈现器作为一个只读的TextBox,你知道吗?去做吧?
您可能需要根据您的具体情况添加IsTabStop ="False"

2> torvin..:

这里的所有答案都只是使用TextBox或尝试手动实现文本选择,这会导致性能不佳或非本机行为(闪烁插入符号TextBox,手动实现中没有键盘支持等)

经过几个小时的挖掘和阅读WPF源代码后,我发现了一种为TextBlock控件(或任何其他控件)启用本机WPF文本选择的方法.文本选择的大多数功能都是在System.Windows.Documents.TextEditor系统类中实现的.

要为控件启用文本选择,您需要做两件事:

    调用TextEditor.RegisterCommandHandlers()一次以注册类事件处理程序

    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使用与此代码等效的反射来分离a :

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


最后一个使用TextBlock的真正答案!我只需要等待近10年.这需要被投票.
@BillyWilloughby您的解决方案只是模拟选择。它缺少许多本机选择功能:键盘支持,上下文菜单等。我的解决方案启用了本机选择功能
只要“文本块”已嵌入“超级链接”,只要“超级链接”不是其中的最后一个内联,似乎此解决方案就可以工作。在内容中添加尾随的空白“运行”可以解决导致“ ExecutionEngineException”抛出的潜在问题。

3> 小智..:

我一直无法找到真正回答这个问题的任何例子.所有答案都使用了Textbox或RichTextbox.我需要一个允许我使用TextBlock的解决方案,这就是我创建的解决方案.

我相信正确的方法是扩展TextBlock类.这是我用来扩展TextBlock类的代码,允许我选择文本并将其复制到剪贴板."sdo"是我在WPF中使用的命名空间引用.

WPF使用扩展类:

xmlns:sdo="clr-namespace:iFaceCaseMain"


扩展类的代码:

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



4> juanjo.arana..:

将此样式应用于TextBox,就是这样(受本文启发):



似乎没有人能够阅读.OP需要一个TextBlock,而不是像TextBlock一样的TextBox.
另外一个补充:填充应该是-2,0,-2,0.在TextBox内部,创建一个TextBoxView控件,其默认边距为2,0,2,0.不幸的是,你无法重新定义它的风格,因为它标记为内部.

5> Jobi Joy..:

为TextBlock创建ControlTemplate并将TextBox放在readonly属性集中.或者只使用TextBox并使其只读,然后您可以更改TextBox.Style以使其看起来像TextBlock.


如果TextBlock中包含内联元素,则此方法将不起作用.如果您有超链接或粗体或斜体文本,该怎么办?TextBox不支持这些.
如何为TextBlock设置ControlTemplate?我找不到房产?
-1 TextBlock没有ControlTemplate,因为它是FrameworkElement的直接子类.另一方面,TextBox是Control的子类.
为什么不能读人?OP明确表示需要TextBlock,而不是TextBox,因为TextBlock支持内联格式而TextBox不支持.为什么像这样完全错误的垃圾答案得到了无数的赞成?

6> Bruce..:

我不确定你是否可以选择TextBlock,但另一种选择是使用RichTextBox - 它就像你建议的TextBox,但支持你想要的格式.



7> Jack Pines..:

根据Windows开发中心:

TextBlock.IsTextSelectionEnabled属性

[针对Windows 10上的UWP应用程序进行了更新.对于Windows 8.x文章,请参阅存档 ]

获取或设置一个值,该值指示是否通过用户操作或调用与选择相关的API 在TextBlock中启用文本选择.


Amswer似乎不正确.IsTextSelectionEnabled仅适用于UWP,而不是WPF - 原始问题确实指定了WPF.
不幸的是,与Win7不兼容(有时这是必须的)
推荐阅读
大大炮
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有