【问题标题】:Inline text box labels with WPF带有 WPF 的内联文本框标签
【发布时间】:2011-02-01 09:59:07
【问题描述】:

我正在尝试在 WPF 应用程序中重现一些纸质表单的布局。文本框的标签与文本框的内容“内联”,而不是像普通 Windows 窗体那样“在外面”。所以,带有 Xxxxxx 标签:

+-----------------------------+
| Xxxxxx: some text written   |
| in the multiline input.     |
|                             |
| another paragraph continues |
| without indentation.        |
|                             |
|                             |
+-----------------------------+

xxxxxx不能编辑,如果用户选择了文本框的所有内容,标签必须保持未选中状态,我需要能够单独设置标签的文本颜色/格式,当没有文本时文本框,但它有焦点,插入符号应该在标签之后闪烁,我需要文本框中文本的基线和标签对齐。

我尝试的一个解决方案是将文本块部分放在输入上,然后使用文本缩进来缩进可编辑的文本,但这会导致以下段落出现问题,因为它们也被缩进了。我不知道如何缩进第一段。它需要一些摆弄才能使文本对齐 - 更可靠的设置将是理想的。

那么,有什么关于如何设置的建议吗?

谢谢

【问题讨论】:

    标签: wpf user-interface textbox richtextbox


    【解决方案1】:

    好吧,我可以建议一种有点老套的方法。

    首先,请注意您可以将 UI 元素放入 FlowDocument。所以这使得这样的事情成为可能:

    <RichTextBox>
      <FlowDocument>
        <Paragraph>
          <InlineUIContainer>
            <TextBlock>This is your label: </TextBlock>
          </InlineUIContainer>
          <Run>And this is the editable text.</Run>
        </Paragraph>
      </FlowDocument>
    </RichTextBox>
    

    现在问题变成了阻止用户编辑InlineUIContainer。这确实是两个问题。

    第一个问题是阻止用户选择它。为此,您必须处理SelectionChanged 事件。在事件中,找到RTB的文档中的第一个InlineUIContainer,如果Selection.Start在那个之前,则更改它。

    private void RichTextBox_SelectionChanged(object sender, RoutedEventArgs e)
    {
        RichTextBox rtb = (RichTextBox) sender;
        if (rtb == null) return;
    
        InlineUIContainer c = rtb.Document
            .Blocks
            .Where(x => x is Paragraph)
            .Cast<Paragraph>()
            .SelectMany(x => x.Inlines)
            .Where(x => x is InlineUIContainer)
            .Cast<InlineUIContainer>()
            .FirstOrDefault();
    
        if (c == null) return;
    
        if (rtb.Selection.Start.CompareTo(c.ElementEnd) < 0)
        {
            rtb.Selection.Select(c.ElementEnd, rtb.Selection.End);
        }
    }
    

    可能有一种更简单的方法来制定 LINQ 查询,但我有点喜欢它。这不是 100% 完美的。如果您在文本内选择并向左拖动TextBlock,它将失去选择。我确信这可以修复。但它工作得很好。它甚至可以处理用户使用箭头键导航的情况。

    就这么多,您几乎可以一路走到那里。不过,另一件可能会让您感到困惑的事情是,如果用户将光标放在文本的最开头并按 BACKSPACE。

    需要类似的处理:将插入符号的位置与第一个 InlineUIElement 的末尾进行比较,如果插入符号位于该位置,则取消 BACKSPACE(通过将事件标记为已处理):

    private void RichTextBox_PreviewKeyDown(object sender, KeyEventArgs e)
    {
        if (e.Key != Key.Back)
        {
            return;
        }
    
        RichTextBox rtb = (RichTextBox)sender;
        if (rtb == null) return;
    
        InlineUIContainer c = rtb.Document
            .Blocks
            .Where(x => x is Paragraph)
            .Cast<Paragraph>()
            .SelectMany(x => x.Inlines)
            .Where(x => x is InlineUIContainer)
            .Cast<InlineUIContainer>()
            .FirstOrDefault();
    
        if (c == null) return;
    
        if (rtb.CaretPosition.CompareTo(c.ElementEnd.GetInsertionPosition(LogicalDirection.Forward)) <= 0)
        {
            e.Handled = true;
        }            
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-13
      • 1970-01-01
      • 1970-01-01
      • 2022-12-12
      • 2021-06-10
      相关资源
      最近更新 更多