Click here to Skip to main content
Click here to Skip to main content

Editable TextBlock in WPF for In-place Editing

By , 10 Dec 2008
 
Sample Image

Introduction

When renaming folders in the Windows Explorer folder tree, the TextBlock containing the name of the folder changes to a TextBox which allows for editing of the folder name inside of the tree. I couldn't find any complete examples, so I decided to make one myself. The EditableTextBlock control is based on the Annotating an Image in WPF article by Josh Smith.

Using the Code

Basically, the control is made of a TextBlock for displaying the text and a TextBox for editing. The IsInEditMode property described below determines which one is currently shown.

The EditableTextBlock control exposes four properties:

  • string Text - The editable text displayed to the user (note TextFormat below).
  • bool IsEditable - Whether or not the control is editable. If not, it behaves just as a regular TextBlock.
  • bool IsInEditMode - Whether or not the control is currently being edited.
  • string TextFormat - Used if the editable text should be surrounded by more text, like the root node in the screenshot above.

The item labeled 'Item 1.1' in the screenshot is defined in XAML as follows:

<TreeViewItem>
    <TreeViewItem.Header>
        <local:EditableTextBlock Text="Item 1.1" />
    </TreeViewItem.Header>
</TreeViewItem>

In order to let the user edit the contents of the control, you have to set the IsInEditMode property to true. For example, the demo application lets the user edit the selected item in the TreeView when the F2 key is pressed, by using the KeyDown event of the TreeView:

private void treeView1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.F2)
        SetCurrentItemInEditMode(true);
}

private void SetCurrentItemInEditMode(bool EditMode)
{
    // Make sure that the SelectedItem is actually a TreeViewItem
    // and not null or something else
    if (treeView1.SelectedItem is TreeViewItem)
    {
        TreeViewItem tvi = treeView1.SelectedItem as TreeViewItem;

        // Also make sure that the TreeViewItem
        // uses an EditableTextBlock as its header
        if (tvi.Header is EditableTextBlock)
        {
            EditableTextBlock etb = tvi.Header as EditableTextBlock;

            // Finally make sure that we are
            // allowed to edit the TextBlock
            if (etb.IsEditable)
                etb.IsInEditMode = EditMode;
        }
    }
}

The control leaves edit mode when one of four things happen:

  • The control loses focus, e.g., when the user clicks on another control.
  • The user hits the Enter key, in which case the edited text is saved in the Text property.
  • The user hits the Escape key, in which case the original text, from before the editing started, is restored.
  • The IsInEditMode property is manually set to false.

The TextFormat Property

The TextFormat property uses the String.Format function to format the text, which means that the editable text is referenced by {0} inside a string. For example, the root node in the demo application is defined in XAML as follows:

<TreeViewItem>
    <TreeViewItem.Header>
        <local:EditableTextBlock Text="Root" TextFormat="Root Item '{0}'" />
    </TreeViewItem.Header>
</TreeViewItem>

If the TextFormat property is set to either the empty string (""), the string containing only {0} ("{0}"), or is not set at all, the control simply shows the string from the Text property.

History

  • December 8, 2008 - Created the article
  • December 8, 2008 - Updated source code

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
AnswerProject Sample not Compiling - SOLUTION !memberMember 799428912-Mar-13 9:31 
Simply change the EditableTextBlock.cs namespace from Borgstrup.DocBase.Client.Controls to Borgstrup.EditableTextBlock.
 
See ya !
GeneralMy vote of 4memberanna.novikova19-Mar-12 7:58 
Helpful solution but not 100% perfect.
GeneralIn order to build the samplememberrencels17-Apr-11 6:12 
Namespace for EditableTextBlock.xaml has to be changed into Borgstrup.EditableTextBlock.
QuestionEvents lost??memberjamluke19-Nov-10 3:40 
I have a treeview populated by custom elements (CDir and CFile) are showed correctly (the label text i mean) and when i press on F2 the event on tree is ok and I arrive to set the property EditMode to true.
But the events lied to TextBox (TextBox_KeyDown, TextBox_Loaded, TextBox_LostFocus) doesn't trigger...I don't know to solve itSigh | :sigh:
 
This is my code xaml:
<Grid>
        <Grid.Resources></Grid.Resources>
        <TreeView Name="m_treeView" KeyDown="m_treeView_KeyDown" SelectedItemChanged="m_treeView_SelectedItemChanged">
            
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=ListElements}">
                    <StackPanel Orientation="Horizontal" Margin="2" Background="Transparent">
                        <Image Margin="2" Source="{Binding Converter={StaticResource CustomImageConverter}}"/>
                        <local:EditableTextBlock  Text="{Binding Path=LabelName}" Margin="2"/>
                     </StackPanel>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Grid>
 
It seems that the <Style.Triggers> doesn't switch... Do you have an idea??
 
P.s.Your example is Ok on VS2008 and VS2010.
GeneralPressing F2 to editmembercmmello10-Nov-10 5:38 
Hi there!
 
This control works great but I could not get it to work with the F2 key to begin editing. I tried to handle KeyDown and PreviewKeyDown but they don't seem to be routed to the control. Any help please?
 
Thank you very much!!!
 
Best regards
Mello
GeneralMy vote of 1membercodddddd5-Nov-10 7:11 
sample code doesn't work
GeneralMy vote of 1memberPJBadenhorst3-May-10 0:06 
The sample code does not work
GeneralMy vote of 4memberChristian Rodemeyer31-Jan-10 23:40 
I would have voted 5 because this little demo solves exactly my problem, but
 
- you need to manually change the namespace of "EditableTextBlock.xaml.cs" to Borgstrup.EditableTextBlock before the project compiles
- the usual "slow double click" to begin editing is not implemented
- and the usage in a databound context could be better (documented)
 
Nevertheless is saved me time and therefore I vote 4Cool | :cool:
 
Christian
---
Always expect the unexpected!

GeneralRe: My vote of 4memberbscaer14-Oct-10 7:32 
Christian,
 
It sounds like you were able to fix the problems. Do you have any code that you can post?
 
Beth
QuestionMultiline ?memberpbisiac27-Jan-10 0:58 
Hi, I need to edit the TextBlock in multiline mode, eg. if I push CTRL+ENTER the cursor goes on another line, ENTER confirms editing and exits. Is it possible ?
GeneralMy vote of 1memberDeni8415-Jan-10 3:07 
assembly missing
GeneralUsing HierarchicalDataTemplate Problemmemberarchmisha8-Dec-09 12:33 
Suppose i got the following code to define the tree view nodes:

<TreeView Name="FoldersTree" Width="200" DockPanel.Dock="Left" HorizontalAlignment="Left"
KeyDown="FoldersTree_KeyDown">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=Items}">
<StackPanel Orientation="Horizontal" >
<Image Source="{Binding Path=Icon}" />
<TextBlock xml:space="preserve"> </TextBlock>
<local:EditableTextBlock Text="{Binding Path=Name}" ToolTip="{Binding Path=Name}"/>
</StackPanel >
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>

 
How can i get the EditableTextBlock in the FoldersTree_KeyDown() function in order to set the IsInEditMode = true property?
When i do FodlersTree.SelectedItem i am not getting TreeViewItem, but rather my data bound objects...
GeneralRe: Using HierarchicalDataTemplate Problemmemberboetor14-Dec-09 21:58 
I got the same problem? Did anyone find a solution for this?
QuestionRe: Using HierarchicalDataTemplate Problemmemberpiotri8530-Dec-09 6:20 
Hi, I have the same problem too. How do I get the item if using the tree with HierachicalDataTemplate?
Is there any hint to resolve this?
AnswerRe: Using HierarchicalDataTemplate Problemmemberjamluke19-Nov-10 3:16 
On event KeyDown
 
private void m_treeView_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.F2)
            {
                EditableTextBlock etb = null;
                DataTemplate dt = m_treeView.ItemTemplate;
                StackPanel sp = dt.LoadContent() as StackPanel; --> To test null....
                UIElementCollection cool = sp.Children;
                for (int i = 0; i < cool.Count; i++)
                {
                    object o = cool[i];
                    if (o as EditableTextBlock != null)
                    { etb = o as EditableTextBlock; break; }
                }
 
                if (etb != null)
                {
                    if (etb.IsEditable)
                    { 
                        etb.EditMode = true
                    }
                }
            }
        }

GeneralRe: Using HierarchicalDataTemplate Problemmembercohoman18-Mar-11 4:16 
This doesn't work for me. The "DataTemplate dt = m_treeView.ItemTemplate" line just returns an empty representation of the item template. Consequently, the next line (StackPanel sp = dt.LoadContent() as StackPanel) returns null.
 
So, how can I access the EditableTextBlock control for the selected item in the TreeView so I can set the IsInEditMode variable?
 
Thanks.
AnswerRe: Using HierarchicalDataTemplate ProblemmemberMember 809702021-Jul-11 7:23 
Try this:
 

if (e.Key == Key.F2)
{
EditableTextBlock etb = null;
TreeViewItem tvi = m_treeView.SelectedItem as TreeViewItem;
DataTemplate dt = tvi.HeaderTemplate;
StackPanel sp = dt.LoadContent() as StackPanel;
UIElementCollection cool = sp.Children;
for (int i = 0; i < cool.Count; i++)
{
object o = cool[i];
if (o as EditableTextBlock != null)
{ etb = o as EditableTextBlock; break; }
}

if (etb != null)
{
if (etb.IsEditable)
{
etb.IsInEditMode = true;
}
}
}

AnswerRe: Using HierarchicalDataTemplate Problem [modified]memberandhome222-Jun-12 11:15 
<TreeView TreeViewItem.Selected="OnItemSelected" ... />
...
<local:EditableTextBlock Name="myEditableTextBlock" ... />
private void treeView1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Key == Key.F2)
    {
        TreeViewItem tvi = tree.Tag as TreeViewItem;
        EditableTextBlock etb = getEditableTextBlock(tvi);
        if (etb != null)
        {
            if (etb.IsEditable)
            {
                etb.IsInEditMode = true;
            }
        }
    }
}
 
private childItem FindVisualChild<childItem>(DependencyObject obj)
    where childItem : DependencyObject
{
    for (int i = 0; i < System.Windows.Media.VisualTreeHelper.GetChildrenCount(obj); i++)
    {
        DependencyObject child = System.Windows.Media.VisualTreeHelper.GetChild(obj, i);
        if (child != null && child is childItem)
            return (childItem)child;
        else
        {
            childItem childOfChild = FindVisualChild<childItem>(child);
            if (childOfChild != null)
                return childOfChild;
        }
    }
    return null;
}
 
protected EditableTextBlock getEditableTextBlock(TreeViewItem selectedTVI)
{
    // Getting the ContentPresenter of TreeViewItem
    ContentPresenter myContentPresenter = FindVisualChild<ContentPresenter>(selectedTVI);
    if (myContentPresenter == null)
        return null;
    // Finding EditableTextBlock from the DataTemplate that is set on that ContentPresenter
    DataTemplate myDataTemplate = myContentPresenter.ContentTemplate;
    EditableTextBlock editBox = myDataTemplate.FindName("myEditableTextBlock", myContentPresenter) as EditableTextBlock;
    return editBox;
}
 
private void OnItemSelected(object sender, RoutedEventArgs e)
{
    tree.Tag = e.OriginalSource;
}
 


modified 22-Jun-12 18:29pm.

GeneralRe: Using HierarchicalDataTemplate ProblemmemberSam Bomb4-Jul-12 1:15 
Oh, it works! thanks a lot~Thumbs Up | :thumbsup:
very hard work with the visual controls... so, any other easier solution?
GeneralBinding IsInEditModememberPatrick Goergen29-Sep-09 6:34 
Hi,
 
I was wondering if anyone has had success binding the IsInEditMode property?
 
I am using TwoWay binding and IsInEditMode seems to be getting updated when I change my bound member (which uses INotifyPropertyChanged) but the EditableTextBlock does not become editable, though the IsInEditMode dependency shows true.
 
Any help would be awesome.
 
Thanks,
Patrick
GeneralRe: Binding IsInEditModemembereliprand28-Jan-10 7:09 
Patrick,
 
I was wondering if you ever figured it out? I am using the control too and I would like to trigger the Edit Mode programmatically via the the ViewModel. But, like you, just setting it is not enough.
Looking at the code, yes, it seems that it is not designed to work that way. Only user events (mouse, keyboard) currently trigger the switch between Edit and Display mode.
 
If I find a clean way, I'll let you know.
 
Regards,
 
Eric.
Generalmy vote is 5memberKunalChowdhury4-Aug-09 1:24 
it's a cool one... Smile | :)
 
Regards,
- Kunal Chowdhury (My Blog)
 

QuestionBinding to collection lost after edit itemmemberJeff4331-Jul-09 14:17 
My application creates a hierarchical ObservableCollection<object> which is bound to my TreeView. The TreeViewItems are styled and arranged as follows:
 
<HierarchicalDataTemplate DataType="{x:Type Folder}"
 ItemsSource="{Binding Path=Items}">
   <uc:EditableTextBlock Text="{Binding Path=Name}" FontSize="12" Foreground="Blue"/>
</HierarchicalDataTemplate>

 
What works:
- Display TreeViewItems
- Drag and Drop TreeViewItems
- Edit TreeViewItems
- Modify my ObservableCollection and TreeViewItems reflect the change automatically.
 
What isn't working:
- After Editing a TreeViewItem, the change is not propagated up to the ObservableCollection.
- At this point, if the Collection is modified, it skips the TreeViewItem that was modified.
 
Its like the binding was lost when the TreeViewItem was edited which would explain both problems. Could this be what is happening?
 
Any thoughts on what might be the problem and/or solution?
 
Thanks,
AnswerRe: Binding to collection lost after edit itemmemberJeff439-Aug-09 8:18 
Link to solution:
http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/a596a708-53a3-4498-9469-c146a79439c4[^] Window">^]
GeneralDep. Propertiesmembermscholz17-Jun-09 20:21 
Hello,
 
When I look at your code I saw some .NET Property wrappers for your Dependency Properties.
In some of them you do more than the simple GetValue/SetValue. This is clearly not recommended.
 
From MSDN: In all but exceptional circumstances, your wrapper implementations should perform only the GetValue and SetValue actions, respectively.
 
see http://msdn.microsoft.com/en-us/library/ms753358.aspx[^]
 
Beside of this nice work.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130617.1 | Last Updated 10 Dec 2008
Article Copyright 2008 by Jesper Borgstrup
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid