Detect if a RichTextBox is empty

后端 未结 5 2711
时光取名叫无心
时光取名叫无心 2021-02-20 01:15

What is the best way to detect if a WPF RichTextBox/FlowDocument is empty?

The following works if only text is present in the document. Not if it contains UIElement\'s

相关标签:
5条回答
  • 2021-02-20 01:55

    H.B.'s answer isn't useful if you need to distinguish between images and whitespace. You can use something like this answer to check for images.

    bool IsEmpty(Document document)
    {
        string text = new TextRange(Document.ContentStart, Document.ContentEnd).Text;
        if (string.IsNullOrWhiteSpace(text) == false)
            return false;
        else
        {
            if (document.Blocks.OfType<BlockUIContainer>()
                .Select(c => c.Child).OfType<Image>()
                .Any())
            return false;
        }
        return true;
    }
    

    This seems laborious, and still probably isn't correct for all scenarios. But I couldn't find any better way.

    0 讨论(0)
  • 2021-02-20 02:14

    The answer above works if you don't put anything into the RTB. However, if you simply delete the contents, the RTB tends to return a single, empty paragraph, not a completely empty string. So, this is more reliable in such cases:

    string text = new TextRange(Document.ContentStart, Document.ContentEnd).Text;
    return !String.IsNullOrWhiteSpace(text);
    

    This only applies to textual contents, of course.

    0 讨论(0)
  • 2021-02-20 02:15

    Here's an extension of H.B.'s idea that works with both text and images.

    I found that difference is always >4 whenever the RTB has text. However, if you only paste an image it is 3. To combat this i look at the string length of the raw rtf string.

    var start = Document.ContentStart;
    var end = Document.ContentEnd;
    var difference = start.GetOffsetToPosition(end);
    
    HasText = difference > 4 || GetRtfText().Length > 350;
    
    
    public string GetRtfText()
    {
      var tr = new TextRange(Document.ContentStart, Document.ContentEnd);
      using (var ms = new MemoryStream())
      {
        tr.Save(ms, DataFormats.Rtf);
        return Encoding.Default.GetString(ms.ToArray());
      }
    }
    

    Through my testing i found that an empty box with no chars has a length of 270. If i even paste in an image that's only 1 pixel in size it balloons to 406.

    I played with toggling on various formatting options without typing any letters and haven't gotten close to 300, so I went with 350 for the baseline.

    The length check could be expensive if there are no textual characters, but they pasted in a massive image.

    0 讨论(0)
  • 2021-02-20 02:17

    First - thank you to McGarnagle - their answer got me going in the right direction. However for whatever reason their image check didn't work for me. This is what I ended up doing:

        Private Function RichTextBoxIsEmpty(BYVAL rtb As RichTextBox) As Boolean
    
        Dim ReturnCode As Boolean = True
    
        Dim text As String = New TextRange(rtb.Document.ContentStart, rtb.Document.ContentEnd).Text
    
        If String.IsNullOrWhiteSpace(text) Then
    
            For Each block As Block In rtb.Document.Blocks
    
                'check for an image
                If TypeOf block Is Paragraph Then
                    Dim paragraph As Paragraph = DirectCast(block, Paragraph)
                    For Each inline As Inline In paragraph.Inlines
                        If TypeOf inline Is InlineUIContainer Then
                            Dim uiContainer As InlineUIContainer = DirectCast(inline, InlineUIContainer)
                            If TypeOf uiContainer.Child Is Image Then
                                ReturnCode = False
                                Exit For
                            End If
                        End If
                    Next
                End If
    
                ' Check for a table
                If TypeOf block Is Table Then
                    ReturnCode = False
                    Exit For
                End If
    
            Next
    
        Else
    
            ReturnCode = False
    
        End If
    
        Return ReturnCode
    
    End Function
    

    there may be other checks to do, but this at least covers text, images and tables.

    0 讨论(0)
  • 2021-02-20 02:20

    You could compare the pointers, which is not all too reliable:

    var start = rtb.Document.ContentStart;
    var end = rtb.Document.ContentEnd;
    int difference = start.GetOffsetToPosition(end);
    

    This evaluates to 2 if the RTB is loaded, and 4 if content has been entered and removed again.
    If the RTB is completely cleared out e.g. via select all -> delete the value will be 0.


    In the Silverlight reference on MSDN another method is found which can be adapted and improved to:

    public bool IsRichTextBoxEmpty(RichTextBox rtb)
    {
        if (rtb.Document.Blocks.Count == 0) return true;
        TextPointer startPointer = rtb.Document.ContentStart.GetNextInsertionPosition(LogicalDirection.Forward);
        TextPointer endPointer = rtb.Document.ContentEnd.GetNextInsertionPosition(LogicalDirection.Backward);
        return startPointer.CompareTo(endPointer) == 0;
    }
    
    0 讨论(0)
提交回复
热议问题