<

WPF: Comparing methods for clearing "TextBox" content.

Published on
13,019 Points
6,119 Views
4 Endorsements
Last Modified:
Approved
What is better between TextBox.Text = String.Empty and TextBox.Clear()?

From an aesthetic view, I would choose the TextBox.Clear() method, because it is logically better to clear a value, rather than re-assigning it with another value. But I wanted to do a little test...

I am working with WPF and c#, in a .NET 4 environment:
Stopwatch sw = new Stopwatch();
sw.Start();
for (Int32 i = 0; i < 1000000; i++)
    textBox_UserName.Text = String.Empty;
sw.Stop();
Int64 elapsed_StringEmpty = sw.ElapsedMilliseconds;

sw.Reset();
sw.Start();
for (Int32 i = 0; i < 1000000; i++)
    textBox_UserName.Clear();
sw.Stop();
Int64 elapsed_Clear = sw.ElapsedMilliseconds;

Open in new window

The two tests produced very different results:
1) Assign the value String.Empty to the Text property: 240 ms
2) Call the Clear() method: 10198 ms
This led me to avoid using the Clear() method which is 42 times (!!!) slower than assigning String.Empty value to the Text property.

The problem can be in part mitigated by surrounding the “Clear()” operation by a “BeginChange” / “EndChange”:
sw.Reset();
sw.Start();
 textBox_UserName.BeginChange();
 for (Int32 i = 0; i < 1000000; i++)
    textBox_UserName.Clear();
 textBox_UserName.EndChange();
 sw.Stop();
 Int64 elapsed_Clear_Change = sw.ElapsedMilliseconds;

Open in new window

In fact the same operation took now 6030 ms. It is still far from than the String.Empty assignment, but just a bit more than half the time of the previous execution.

The "Clear()" method implementation of the System.Windows.Controls.TextBox resides in the PresentationFramework.dll. If we take a look at it, then we can understand why it takes longer than the simple ".Text" assignment:
/// <summary> 
/// Clear all the content in the TextBox control.
 /// </summary> 
 public void Clear()
 {
    using (this.TextSelectionInternal.DeclareChangeBlock())
     { 
        this.TextContainer.DeleteContentInternal((TextPointer)this.TextContainer.Start, (TextPointer)this.TextContainer.End);
         TextSelectionInternal.Select(this.TextContainer.Start, this.TextContainer.Start); 
    } 
}

Open in new window

This code declares a "ChangeBlock" and then deletes the content. A ChangeBlock is defined as:
private class ChangeBlock : IDisposable 
{
    internal ChangeBlock(ITextRange range, bool disableScroll) 
    {
        _range = range;
        _disableScroll = disableScroll;
        _range.BeginChange(); 
    }
 
    void IDisposable.Dispose() 
    {
        _range.EndChange(_disableScroll, false /* skipEvents */); 
        GC.SuppressFinalize(this);
    }

    private readonly ITextRange _range; 
    private readonly bool _disableScroll;
}  

Open in new window


The "DeleteContentInternal" method is:
// DeleteContent worker.  Removes content from the tree.
internal void DeleteContentInternal(TextPointer startPosition, TextPointer endPosition) 
{
    TextTreeNode containingNode;
    int symbolCount;
    int charCount; 
    TextTreeUndoUnit undoUnit;
    TextPointer deletePosition; 
 
    startPosition.SyncToTreeGeneration();
    endPosition.SyncToTreeGeneration(); 

    if (startPosition.CompareTo(endPosition) == 0)
        return;
 
    BeforeAddChange();
 
    undoUnit = TextTreeUndo.CreateDeleteContentUndoUnit(this, startPosition, endPosition); 

    containingNode = startPosition.GetScopingNode(); 

    // Invalidate any TextElementCollection that depends on the parent.
    // Make sure we do that before raising any public events.
    TextElementCollectionHelper.MarkDirty(containingNode.GetLogicalTreeNode()); 

    int nextIMEVisibleNodeCharDelta = 0; 
    TextTreeTextElementNode nextIMEVisibleNode = GetNextIMEVisibleNode(startPosition, endPosition); 
    if (nextIMEVisibleNode != null)
    { 
        // The node following the delete just became the first sibling.
        // This might affect its ime char count.
        nextIMEVisibleNodeCharDelta = -nextIMEVisibleNode.IMELeftEdgeCharCount;
        nextIMEVisibleNode.IMECharCount += nextIMEVisibleNodeCharDelta; 
    }
 
    // First cut: remove all top-level TextElements and their chilren. 
    // We need to put each TextElement in its own tree, so that any outside
    // references can still play with the TextElements safely. 
    symbolCount = CutTopLevelLogicalNodes(containingNode, startPosition, endPosition, out charCount);

    // Cut what's left.
    int remainingCharCount; 
    symbolCount += DeleteContentFromSiblingTree(containingNode, startPosition, endPosition, nextIMEVisibleNodeCharDelta != 0, out remainingCharCount);
    charCount += remainingCharCount; 
 
    Invariant.Assert(symbolCount > 0);
 
    if (undoUnit != null)
    {
        undoUnit.SetTreeHashCode();
    } 

    // Public tree event. 
    deletePosition = new TextPointer(startPosition, LogicalDirection.Forward); 
    AddChange(deletePosition, symbolCount, charCount, PrecursorTextChangeType.ContentRemoved);
 
    if (nextIMEVisibleNodeCharDelta != 0)
    {
        RaiseEventForNewFirstIMEVisibleNode(nextIMEVisibleNode);
    } 
}

Open in new window

This is the core of the method and lets us understand why it is taking so much time.
The method calls "CreateDeleteContentUndoUnit" and then removes all the TextBox' children.

THIS IS THE REAL DIFFERENCE between "Clear()" and ".Text = "...
The Clear() method not only clears the text value, but removes all the content of the TextBox, which is what we really expect from it.

But what about ClearValue and SetValue methods?
DependencyProperty dp = System.Windows.Controls.TextBox.TextProperty;

sw.Reset();
sw.Start();
for (Int32 i = 0; i < 1000000; i++)
    textBox_UserName.ClearValue(dp);
sw.Stop();
Int64 elapsed_ClearValue = sw.ElapsedMilliseconds;

sw.Reset();
sw.Start();
for (Int32 i = 0; i < 1000000; i++)
    textBox_UserName.SetValue(dp, null);
sw.Stop();
Int64 elapsed_SetValue = sw.ElapsedMilliseconds;

Open in new window

The ClearValue method took 448 ms to execute 1 million times, while the SetValue method took 393 ms: closer to, but still about 1.5 times slower than the simple textBox_UserName.Text = String.Empty assignment.

If a simple "text clearing" is needed, then I would simply set "String.Empty" to the .Text property of my textbox. Otherwise, if the TextBox contains other objects, calling "Clear()" method would be best.
4
Comment
Author:jonnidip
5 Comments
 
 

Administrative Comment

by:Eric AKA Netminder
jonnidip,

Congratulations! Your article has now been published. A very nice article -- it takes a simple, clear issue and presents the alternatives with demonstrable data. Good work!

ericpete
Page Editor
0
 
LVL 54

Expert Comment

by:Mark Wills
Good Article, enjoyed reading it and looking at the differences...

Thanks for writing it - voted Yes.
0
 
LVL 13

Author Comment

by:jonnidip
@mark_willis: I am happy to know that you liked it.
Thank you!
0
 
LVL 38

Expert Comment

by:younghv
Very nicely done.
You have a nice way of presenting technical information in an easily read format.

"Yes" vote above.
0
 
LVL 13

Author Comment

by:jonnidip
Thank you for reading!
0

Featured Post

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Join & Write a Comment

This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Learn the basics of Skype For Business in office 365

Keep in touch with Experts Exchange

Tech news and trends delivered to your inbox every month