Ko9 Ko9 - 2 months ago 16
C# Question

Inline editing TextBlock in a ListBox with Data Template (WPF)

Using WPF, I have a

control with a
inside it. The relevant XAML code is shown below:

<ListBox Name="_todoList" Grid.Row="1" BorderThickness="2"
Drop="todoList_Drop" AllowDrop="True"
<Grid Margin="4">
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<CheckBox Grid.Column="0" Checked="CheckBox_Check" />
<TextBlock Name="descriptionBlock"
Text="{Binding Description}"
Cursor="Hand" FontSize="14"
ToolTip="{Binding Description}"
MouseDown="TextBlock_MouseDown" />

What I am trying to do is make the
respond to a (double)click which turns it into a
. The user can then edit the description, and press return or change focus to make the change.

I have tried adding a
element in the same position as the TextBlock and making its visiblity
, but I don't know how to navigate to the right
when the user has clicked on a
. That is, I know the user has clicked on a certain
, now which
do I show?

Any help would be appreciated greatly,



What I've done in these situations is used the XAML hierarchy to determine which element to show/hide. Something along the lines of:

  <TextBlock MouseDown="txtblk_MouseDown" />
  <TextBox LostFocus="txtbox_LostFocus" Visibility="Collapsed" />

with the code:

protected void txtblk_MouseDown(object sender, MouseButtonEventArgs e)
    TextBox txt = (TextBox)((Grid)((TextBlock)sender).Parent).Children[1];
    txt.Visibility = Visibility.Visible;
    ((TextBlock)sender).Visibility = Visibility.Collapsed;

protected void txtbox_LostFocus(object sender, RoutedEventArgs e)
    TextBlock tb = (TextBlock)((Grid)((TextBox)sender).Parent).Children[0];
    tb.Text = ((TextBox)sender).Text;
    tb.Visibility = Visibility.Visible;
    ((TextBox)sender).Visibility = Visibility.Collapsed;

I always turn stuff like this that I'm going to reuse into a UserControl, which I can add additional error handling to, and guarantee that the Grid will only contain two items, and the order of them will never change.

EDIT: Additionally, turning this into a UserControl allows you to create a Text property for each instantiation, so you can name each one and reference the text directly without fishing for the current value through the ((TextBox)myGrid.Children[1]).Text casting. This will make your code much more efficient and clean. If you make it into a UserControl, you can also name the TextBlock and TextBox elements, so no casting is needed at all.