字体不支持符号时如何在WPF文本框中插入版权、商标、服务标记等
Posted
技术标签:
【中文标题】字体不支持符号时如何在WPF文本框中插入版权、商标、服务标记等【英文标题】:How to insert copyright, trademark, service mark, etc. into WPF textbox when font doesn't support symbols 【发布时间】:2011-01-10 12:32:47 【问题描述】:我们有一个 WPF 应用程序,它显示包含各种公司符号的文本;例如商标、注册商标、版权和服务标志。
数据库有一些包含标准公司符号的字段。最初,数据标记如下:
Example Corp(TM) or Example Plan (SM)
我们可以轻松地将占位符更改为它们各自的 Unicode 等价物;并且实际上在大多数情况下都有。
我们遇到的问题是应用程序使用的字体不支持服务标记符号(它只是一个上标SM)。我们可能无法替换字体或对其进行编辑。
这些字段可以是一个简单的产品名称,末尾带有符号,也可以是一个包含 0 次或多次符号的长描述。我们将 TextBoxes 或 Labels 直接绑定到 ViewModel 和/或业务对象(通常通过 DataTemplates)。应用程序中的所有数据都是只读的。
那么,假设我们必须通过代码(在 C# 和 WPF 中)解决这个问题,我的选择是什么?
【问题讨论】:
你能告诉我们更多关于这种字体(名称?内部还是商业?)以及为什么你不能使用不同的字体? 这是一种自定义的内部字体;不能使用其他的,因为它必须经过漫长的审批过程。客户非常大,我认为我们甚至无法追踪是谁创建的。 【参考方案1】:编辑:我在另一个答案中发现TextBlock
也有一个Inlines
集合,可以添加Run
s。 Anvaka's answer 巧妙地将附加属性用作一种转换器。
我对如何解决这个问题有几个想法。只有一个人会正确处理自动换行并处理不同字体的字符运行。
使用FlowDocumentScrollViewer
并使用ValueConverter
将字符串绑定到它,该ValueConverter
将字符串转换为FlowDocument
。
<FlowDocumentScrollViewer
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
Document="Binding MyString, Converter=StaticResource MyConverter" />
您可以在转换器上创建属性来设置常规字体属性,这些属性不能在FlowDocumentScrollViewer
上设置,而必须在转换器创建的FlowDocument
上设置。对于需要不同字体(可能还有不同大小)的异常子字符串,您可能还需要一些字体属性。另一种选择是在 FlowDocument
上为其中一些属性 (RelativeSource
) 创建 Binding
s。
下面是在代码中创建FlowDocument
的方法:
FlowDocument doc = new FlowDocument();
doc.FontFamily = new FontFamily( "Our Own Font" );
Paragraph par = new Paragraph();
doc.Blocks.Add( par );
然后您需要在特殊子字符串上拆分传入字符串,同时保持这些子字符串完整。您必须滚动自己的拆分器,并在转换器中拥有一组子字符串或提供给转换器。
在段落中添加一个普通的子字符串:
Run r = new Run( substring );
par.Inlines.Add( r );
为段落添加一个特殊的子字符串,使用不同的字体:
Run r = new Run( substring );
r.FontFamily = new FontFamily( "Arial" );
par.Inlines.Add( r );
以上只是小sn-ps。我不知道您想如何拆分字符串或迭代子字符串,因为我不熟悉数据,所以我没有提供我拼凑的方法只是为了看看我的想法是否可行。您还可以使用Dictionary
来检测一个子字符串并在输出中使用替换,例如检测"(SM)"
并将其替换为"℠"
。
如果您有任何问题或有什么我可以详细说明的,请告诉我。
(您说它是只读的很好。RichTextBox
不起作用,因为它的Document
属性不是DependencyProperty
,因此不能成为Binding
的目标。虽然,也许可以使用Mode=OneWayToSource
来反转它,实现ConvertBack
而不是Convert
。)
“我认为您遗漏的部分(迭代字符串并创建这些运行)是棘手的部分。”
关于在特殊子字符串上拆分字符串,我确实非常简短。当我说“我不知道你将如何拆分字符串”时,我并不是说我根本不知道该怎么做(我重新措辞了),而是说我不知道你会想要什么来处理它。我认为你不难弄清楚那部分,因为这是我会让潜在员工弄清楚的那种字符串操作问题。这样,您可能会在数据中发现需要更改处理方式的边缘情况。
我会用IndexOf()
和Substring()
向你描述一个相对粗略的版本。
这就是问题中的问题:您有许多包含 0 个或多个特殊子字符串的字符串(例如,"Company Name(R), makers of Product(TM)"
)。这些子字符串很少且已知,输入字符串需要拆分成几个字符串,其中特殊子字符串和非特殊子字符串相互隔离(例如,"Company Name", "(R)", ", makers of Product", "(TM)"
)。
特殊子字符串很少且已知,因此您需要一个数组。您可以通过.IndexOf()
的返回值知道它是否找到了子字符串。循环遍历已知的特殊子字符串,您可以通过索引比较找到其中任何一个的第一个实例,同时保留子字符串的长度。
每次您在字符串 S
(如果有)中找到最早的特殊子字符串时,都会生成派生字符串 A
、B
和 C
。 B
是特殊子串,A
和 C
是前后。将A
和B
附加到List
和C
成为新的S
,然后你再做一次。除非您在 S
中找不到特殊的子字符串并且它不为空,在这种情况下您只需将其全部附加。
现在List
中的每个奇数索引字符串都是一个特殊的子字符串。当您找到的子字符串为"(SM)"
时,您可能想参考我在此答案的前一部分中提到的Dictionary
用作查找以添加"℠"
的Run
。
【讨论】:
将文本分成 Run 元素可能是要走的路;然而,这只是解决方案的一部分。我认为你遗漏的部分(迭代字符串并创建那些运行)是棘手的部分。 我将把它标记为正确答案,尽管我希望有更优雅的东西。实际上,这是 Anvaka 的答案和我最终实施的暴力字符串操作的结合。 听起来不错。在我看来,把琴弦分开总是不雅的。唯一可以整理它的方法 - 只需将复杂性从一个地方转移到另一个地方 - 就是用正则表达式分离字符串。【参考方案2】:如果您的显示元素支持多种字体,例如 RichTextbox 控件,那么您可以在 (TM) 和 (SM) 符号周围使用适当的字体来格式化字符串。
【讨论】:
我想你只是重申了这个问题。【参考方案3】:这样做有点难看,但一种选择可能是将包含预渲染符号的小图像放置在适当的位置。由于数据不是静态的(如果我理解正确的话),您需要动态计算图像的位置,除非字体是固定宽度,否则这将很困难。
【讨论】:
以上是关于字体不支持符号时如何在WPF文本框中插入版权、商标、服务标记等的主要内容,如果未能解决你的问题,请参考以下文章
MS UIAutomation 对文本无用吗?如何设置字体粗细、获取插入符号位置、插入文本等?
从 Windows 10 虚拟键盘输入到 WPF 文本框中的快乐表情符号未在文本框的 PreviewTextInput 事件中捕获