I'm trying to implement in place editing of treenodes. I'm fairly close but no cigar. All bindings seem correct. The application runs fine, no output messages, the treeview gets populated. I'm able to select a node, press F2, I can edit the node but as soon as I hit enter the text reverts to what it was before, as if I didn't make an edit. If I make an edit of the Name property somewhere else in the application that change gets reflected in the EditableTextBlock, both in the TextBlock and in the TextBox. Why can't I make the change persistent? It's as if the binding works in one way only.
This is the user control's xaml:
<UserControl x:Class="WPFApplication.EditableTextBlock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WPFApplication"
x:Name="MyUserControl">
<UserControl.Resources>
<DataTemplate x:Key="EditModeTemplate">
<TextBox KeyDown="TextBox_KeyDown" Loaded="TextBox_Loaded" LostFocus="TextBox_LostFocus"
Text="{Binding Path=Text, ElementName=MyUserControl, Mode=TwoWay}"
Margin="0" BorderThickness="1" />
</DataTemplate>
<DataTemplate x:Key="DisplayModeTemplate">
<TextBlock Text="{Binding ElementName=MyUserControl, Path=Text, Mode=TwoWay}"/>
</DataTemplate>
<Style TargetType="{x:Type local:EditableTextBlock}">
<Style.Triggers>
<Trigger Property="IsInEditMode" Value="True">
<Setter Property="ContentTemplate" Value="{StaticResource EditModeTemplate}" />
</Trigger>
<Trigger Property="IsInEditMode" Value="False">
<Setter Property="ContentTemplate" Value="{StaticResource DisplayModeTemplate}" />
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
and the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WPFApplication
{
public partial class EditableTextBlock : UserControl
{
#region Constructor
public EditableTextBlock()
{
InitializeComponent();
base.Focusable = true;
base.FocusVisualStyle = null;
}
#endregion Constructor
#region Member Variables
// We keep the old text when we go into editmode
// in case the user aborts with the escape key
private string oldText;
#endregion Member Variables
#region 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 PropertyMetadata(""));
public bool IsEditable
{
get { return (bool)GetValue(IsEditableProperty); }
set { SetValue(IsEditableProperty, value); }
}
public static readonly DependencyProperty IsEditableProperty =
DependencyProperty.Register(
"IsEditable",
typeof(bool),
typeof(EditableTextBlock),
new PropertyMetadata(true));
public bool IsInEditMode
{
get
{
if (IsEditable)
return (bool)GetValue(IsInEditModeProperty);
else
return false;
}
set
{
if (IsEditable)
{
if (value) oldText = Text;
SetValue(IsInEditModeProperty, value);
}
}
}
public static readonly DependencyProperty IsInEditModeProperty =
DependencyProperty.Register(
"IsInEditMode",
typeof(bool),
typeof(EditableTextBlock),
new PropertyMetadata(false));
public string TextFormat
{
get { return (string)GetValue(TextFormatProperty); }
set
{
if (value == "") value = "{0}";
SetValue(TextFormatProperty, value);
}
}
public static readonly DependencyProperty TextFormatProperty =
DependencyProperty.Register(
"TextFormat",
typeof(string),
typeof(EditableTextBlock),
new PropertyMetadata("{0}"));
public string FormattedText
{
get { return String.Format(TextFormat, Text); }
}
#endregion Properties
#region Event Handlers
// Invoked when we enter edit mode.
void TextBox_Loaded(object sender, RoutedEventArgs e)
{
TextBox txt = sender as TextBox;
// Give the TextBox input focus
txt.Focus();
txt.SelectAll();
}
// Invoked when we exit edit mode.
void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
this.IsInEditMode = false;
}
// Invoked when the user edits the annotation.
void TextBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
this.IsInEditMode = false;
e.Handled = true;
}
else if (e.Key == Key.Escape)
{
this.IsInEditMode = false;
Text = oldText;
e.Handled = true;
}
}
#endregion Event Handlers
}
}
The treeview then uses this datatemplate:
<HierarchicalDataTemplate DataType="{x:Type localvm:TreeViewItemViewModel}" ItemsSource="{Binding Children}">
<StackPanel>
<local:EditableTextBlock Text="{Binding Name}"/>
</StackPanel>
EditableTextBlock
XAML other than theResources
. Could you please update your answer with those as well? – Szabolcs Dézsi