Ala*_* Le 214 wpf xaml textbox textblock
我想让文本显示在Witty中,这是一个开源的Twitter客户端,可以选择.它目前使用自定义文本块显示.我需要使用TextBlock,因为我正在使用textblock的内联来显示和格式化@username和链接作为超链接.经常请求是能够复制粘贴文本.为了做到这一点,我需要使TextBlock可选.
我试图通过使用只读TextBox来显示文本,使其看起来像文本块,但这在我的情况下不起作用,因为TextBox没有内联.换句话说,我不能单独设置或格式化TextBox中的文本,就像我可以使用TextBlock一样.
有任何想法吗?
小智 211
<TextBox Background="Transparent"
BorderThickness="0"
Text="{Binding Text, Mode=OneWay}"
IsReadOnly="True"
TextWrapping="Wrap" />
Run Code Online (Sandbox Code Playgroud)
tor*_*vin 56
这里的所有答案都只是使用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);
}
}
Run Code Online (Sandbox Code Playgroud)
我还创建了一个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);
}
}
Run Code Online (Sandbox Code Playgroud)
另一种选择是创建附加属性以便TextBlock按需启用文本选择.在这种情况下,要再次禁用选择,需要TextEditor使用与此代码等效的反射来分离a :
_editor.TextContainer.TextView = null;
_editor.OnDetach();
_editor = null;
Run Code Online (Sandbox Code Playgroud)
Bil*_*hby 28
我一直无法找到真正回答这个问题的任何例子.所有答案都使用了Textbox或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>
Run Code Online (Sandbox Code Playgroud)
扩展类的代码:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
示例窗口代码:
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);
}
Run Code Online (Sandbox Code Playgroud)
jua*_*ana 19
将此样式应用于TextBox,就是这样(受本文启发):
<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>
Run Code Online (Sandbox Code Playgroud)
Job*_*Joy 18
为TextBlock创建ControlTemplate并将TextBox放在readonly属性集中.或者只使用TextBox并使其只读,然后您可以更改TextBox.Style以使其看起来像TextBlock.
根据Windows开发中心:
TextBlock.IsTextSelectionEnabled属性
[针对Windows 10上的UWP应用程序进行了更新.对于Windows 8.x文章,请参阅存档 ]
获取或设置一个值,该值指示是否通过用户操作或调用与选择相关的API 在TextBlock中启用文本选择.
虽然问题确实说“可选择”,但我相信有意的结果是将文本放入剪贴板。这可以通过添加上下文菜单和名为 copy 的菜单项轻松优雅地实现,该菜单项将 Textblock Text 属性值放入剪贴板。反正只是一个想法。
| 归档时间: |
|
| 查看次数: |
102961 次 |
| 最近记录: |