Thomas Lebrun

All you need about WPF, Silverlight & LINQ !

[WPF] How to develop and editable Textblock ?

Here is another request that a friend of mine asked me recently. To achieve this, I’ve just create a custom control that contains a TextBlock and a TextBox (which is hidden) controls.

When user double clic on the TextBlock, the Textbox appears.

So here is my proposition: in the file generic.xaml, put this:

 

<Style TargetType="{x:Type local:EditableTextBlock}">

    <Setter Property="Template">

        <Setter.Value>

            <ControlTemplate TargetType="{x:Type local:EditableTextBlock}">

                <Grid x:Name="PART_GridContainer"

                      Background="{TemplateBinding Background}"

                      Width="{TemplateBinding Width}"

                      Height="{TemplateBinding Height}">

                    <TextBlock x:Name="PART_TbDisplayText"

                               Visibility="Visible"

                               Background="{Binding Mode=TwoWay, Path=TextBlockBackgroundColor, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}"

                               Foreground="{Binding Mode=TwoWay, Path=TextBlockForegroundColor, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}"

                               Text="{Binding Mode=TwoWay, Path=Text, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}" />

                    <TextBox x:Name="PART_TbEditText"

                             Visibility="Hidden"

                             Background="{Binding Mode=TwoWay, Path=TextBoxBackgroundColor, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}"

                             Foreground="{Binding Mode=TwoWay, Path=TextBoxForegroundColor, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}"

                             Text="{Binding Mode=TwoWay, Path=Text, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}" />

                </Grid>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>

 

Then, here is the content that should go in the behind file:

 

[TemplatePart(Type = typeof(Grid), Name = EditableTextBlock.GRID_NAME)]

[TemplatePart(Type = typeof(TextBlock), Name = EditableTextBlock.TEXTBLOCK_DISPLAYTEXT_NAME)]

[TemplatePart(Type = typeof(TextBox), Name = EditableTextBlock.TEXTBOX_EDITTEXT_NAME)]

public class EditableTextBlock : Control

{

    #region Constants

    private const string GRID_NAME = "PART_GridContainer";

    private const string TEXTBLOCK_DISPLAYTEXT_NAME = "PART_TbDisplayText";

    private const string TEXTBOX_EDITTEXT_NAME = "PART_TbEditText";

    #endregion

    #region Member Fields

    private Grid m_GridContainer;

    private TextBlock m_TextBlockDisplayText;

    private TextBox m_TextBoxEditText;

    #endregion

    #region Dependency Properties

    public string Text

    {

        get { return (string)GetValue(TextProperty); }

        set { SetValue(TextProperty, value); }

    }

    public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(EditableTextBlock), new UIPropertyMetadata(string.Empty));

    public Brush TextBlockForegroundColor

    {

        get { return (Brush)GetValue(TextBlockForegroundColorProperty); }

        set { SetValue(TextBlockForegroundColorProperty, value); }

    }

    public static readonly DependencyProperty TextBlockForegroundColorProperty = DependencyProperty.Register("TextBlockForegroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

    public Brush TextBlockBackgroundColor

    {

        get { return (Brush)GetValue(TextBlockBackgroundColorProperty); }

        set { SetValue(TextBlockBackgroundColorProperty, value); }

    }

    public static readonly DependencyProperty TextBlockBackgroundColorProperty = DependencyProperty.Register("TextBlockBackgroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

    public Brush TextBoxForegroundColor

    {

        get { return (Brush)GetValue(TextBoxForegroundColorProperty); }

        set { SetValue(TextBoxForegroundColorProperty, value); }

    }

    public static readonly DependencyProperty TextBoxForegroundColorProperty = DependencyProperty.Register("TextBoxForegroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

    public Brush TextBoxBackgroundColor

    {

        get { return (Brush)GetValue(TextBoxBackgroundColorProperty); }

        set { SetValue(TextBoxBackgroundColorProperty, value); }

    }

    public static readonly DependencyProperty TextBoxBackgroundColorProperty = DependencyProperty.Register("TextBoxBackgroundColor", typeof(Brush), typeof(EditableTextBlock), new UIPropertyMetadata(null));

    #endregion

    #region Constructor

    static EditableTextBlock()

    {

        DefaultStyleKeyProperty.OverrideMetadata(typeof(EditableTextBlock), new FrameworkPropertyMetadata(typeof(EditableTextBlock)));

    }

    #endregion

    #region Overrides Methods

    public override void OnApplyTemplate()

    {

        base.OnApplyTemplate();

        this.m_GridContainer = this.Template.FindName(GRID_NAME, this) as Grid;

        if(this.m_GridContainer != null)

        {

            this.m_TextBlockDisplayText = this.m_GridContainer.Children[0] as TextBlock;

            this.m_TextBoxEditText = this.m_GridContainer.Children[1] as TextBox;

            this.m_TextBoxEditText.LostFocus += this.OnTextBoxLostFocus;

        }

    }

    protected override void OnMouseDoubleClick(MouseButtonEventArgs e)

    {

        base.OnMouseDoubleClick(e);

        this.m_TextBlockDisplayText.Visibility = Visibility.Hidden;

        this.m_TextBoxEditText.Visibility = Visibility.Visible;

    }

    #endregion

    #region Event Handlers

    private void OnTextBoxLostFocus(object sender, RoutedEventArgs e)

    {

        this.m_TextBlockDisplayText.Visibility = Visibility.Visible;

        this.m_TextBoxEditText.Visibility = Visibility.Hidden;

    }

    #endregion

}

 

As you can see, it’s pretty simple but very useful :)

Happy coding !

Bye.

Posted: Mar 24 2009, 08:16 AM by Thomas Lebrun | with 19 comment(s)
Filed under: ,

Comments

Simon said:

Hey Thomas,

A better (and non so intrusive) way, would be to make a style for the TextBox without any border / background when it has no-focus.

# March 24, 2009 5:08 AM

Koistya `Navin said:

Looks complicated for me..

# March 24, 2009 5:09 AM

Thomas Lebrun said:

@Koistya `Navin: Why complicated ? It's just a control composed by a TextBox and a TextBlock and, when user double clic on the Textblock, I simple change the visibility of the Textbox: all the rest is just for the style...

# March 24, 2009 5:19 AM

commenter said:

{Binding Mode=TwoWay, Path=TextBoxBackgroundColor, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}

I think I love XAML most of all for its simplicity.

# March 24, 2009 9:11 AM

Koistya `Navin said:

@Thomas Lebrun: I simply add this functionality on the client side with jQuery. Here is an example:

http://obedov.riaguy.com/ - login with Windows Live

Then click on any text for a simple editing or double-click for advanced editing.

# March 24, 2009 5:34 PM

Koistya `Navin said:

Here is the correct link:

http://obedov.riaguy.com

On the server-side there is just something like this

<a href="./" rel="editable"><%= Html.Encode(Model.SomeLink) %></a>

+ one global web service method for updates

the rest is done on a client side with jquery.

# March 24, 2009 7:16 PM

Koistya `Navin said:

Oups, I wasn't observant enaough. Yep, your solutions looks good. I'am just too much into ASP.NET MVC and sometimes misunderstand others :) LOL

# March 24, 2009 7:28 PM

Thomas Lebrun said:

@Koistya `Navin: I now understand better why you were talking about JQuery :)

BTW, your solution looks good too !

# March 25, 2009 3:38 AM

tungleh said:

Hello,

Where do you route the MouseDoubleClick event onto the control? I can see the += LostFocus event, but not the MouseDoubleClick.

# April 12, 2009 5:08 AM

Thomas Lebrun said:

Hi,

If you check at the source code, you can see that I override the method OnMouseDoubleClick ;)

Bye.

# April 12, 2009 6:00 AM

kevin Mocha said:

# April 29, 2009 3:05 PM

kevin Mocha - Inline Editable TextBlock for WPF said:

Pingback from  kevin Mocha - Inline Editable TextBlock for WPF

# April 29, 2009 3:05 PM

vahid said:

thank for your code,but when i bind the text of that dont show anything

this is my usage code:

<GridViewColumn Header="myheader" >

           <GridViewColumn.CellTemplate>

               <DataTemplate>

                   <l:EditableTextBlock   Text="{Binding Path=AccountNo}" />

               </DataTemplate>

           </GridViewColumn.CellTemplate>

       </GridViewColumn>

please help me.

# March 8, 2010 4:38 AM

Sadek said:

I have the same issue.

# October 21, 2010 11:13 AM

bubeligsundi said:

I didn't try it but perhaps use Text="{TemplateBinding Text}" instead of Text="{Binding Mode=TwoWay, Path=Text, RelativeSource={RelativeSource AncestorType={x:Type local:EditableTextBlock}}}"

binding to Text is by default TwoWay if i remember correct...

# December 13, 2010 10:19 PM

Jason said:

I am using this control, but if you place the control in a LISTBOX, the double click event doesn't flip to edit mode. Any idea why this would work. Note: works fine if you place the control in a ItemsControl.

ex:

<ListBox SnapsToDevicePixels="True">

  <x:EditableTextBlock Text="Jason" />

  <x:EditableTextBlock Text="Jason" />

</ListBox>

vs.

<ItemsControl>

  <x:EditableTextBlock Text="Jason" />

  <x:EditableTextBlock Text="Jason" />

</ItemsControl>

# March 21, 2011 5:30 PM

Giber said:

How can I bind the Text of the TextBlock to one property of a ViewModel and the Text of the TextBox to another property on the same ViewModel??

Tnx

# September 23, 2011 3:57 PM

MarryGunish said:

Great post  at least I thing so. Keep posting this way!

Marry Gunish

<a href="escort-brazil.com/">escort pagina brasil</a>

# October 31, 2011 5:26 PM

Textblock wpf | Jilleppe said:

Pingback from  Textblock wpf | Jilleppe

# December 26, 2011 10:25 PM
Leave a Comment

(required) 

(required) 

(optional)

(required)