Используя WPF, у меня есть a ListBox
управление с a DataTemplate
в нем. Соответствующий код XAML показывают ниже:
<ListBox Name="_todoList" Grid.Row="1" BorderThickness="2"
Drop="todoList_Drop" AllowDrop="True"
HorizontalContentAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
AlternationCount="2">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Margin="4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" Checked="CheckBox_Check" />
<TextBlock Name="descriptionBlock"
Grid.Column="1"
Text="{Binding Description}"
Cursor="Hand" FontSize="14"
ToolTip="{Binding Description}"
MouseDown="TextBlock_MouseDown" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
То, что я пытаюсь сделать, делают TextBlock
ответьте на (двойной) щелчок, который превращает его в a TextBox
. Пользователь может затем отредактировать описание, и нажать возврат или изменить фокус для внесения изменения.
Я попытался добавить a TextBox
элемент в той же позиции TextBlock и создания его видимости Collapsed
, но я не знаю, как перейти направо TextBox
когда пользователь нажал на a TextBlock
. Таким образом, я знаю, что пользователь нажал на определенное TextBlock
, теперь, который TextBox
я показываю?
Любая справка ценилась бы значительно,
- Ko9
То, что я сделал в этих ситуациях, используется иерархия XAML для определения того, какой элемент показывать/скрывать. Что-то вроде:
<Grid>
<TextBlock MouseDown="txtblk_MouseDown" />
<TextBox LostFocus="txtbox_LostFocus" Visibility="Collapsed" />
</Grid>
с кодом:
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;
}
Я всегда превращаю такие вещи, которые собираюсь использовать повторно, в UserControl
, к которому я могу добавить дополнительную обработку ошибок, и гарантировать, что Grid
будет содержать только два элемента, и их порядок никогда не изменится.
EDIT: Дополнительно, превращая это в UserControl, вы можете создать свойство Text
для каждого инстанцирования, так что вы можете назвать каждое из них и напрямую ссылаться на текст, не подбирая текущее значение с помощью кастинга ((TextBox)myGrid.Children[1]).Text
. Это сделает Ваш код намного более эффективным и чистым. Если вы сделаете его в UserControl, вы также можете назвать элементы TextBlock
и TextBox
, так что кастинг вообще не нужен.
Идеальным способом сделать это было бы создание элемента управления ClickEditableTextBlock
, который по умолчанию отображается как TextBlock, но показывает TextBox, когда пользователь на него нажимает. Поскольку любой данный элемент управления ClickEditableTextBlock имеет только один TextBlock и один TextBox, у вас нет проблемы с совпадением. Тогда вы используете ClickEditableTextBlock вместо отдельных TextBlock и TextBox в DataTemplate.
Это имеет дополнительное преимущество, заключающееся в инкапсуляции функциональности в элемент управления, чтобы вы не загрязняли код главного окна - за поведением редактора, плюс вы можете легко повторно использовать его в других шаблонах.
Если это звучит как слишком много усилий, вы можете использовать Tag или прикрепленное свойство для ассоциирования каждого TextBlock с TextBox:
<DataTemplate>
<StackPanel>
<TextBlock Text="whatever"
MouseDown="TextBlock_MouseDown"
Tag="{Binding ElementName=tb}" />
<TextBox Name="tb" />
</StackPanel>
</DataTemplate>
Обратите внимание на использование {Binding ElementName=tb}
на Tag для ссылки на TextBox с именем tb
.
А в вашем коде позади:
private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e)
{
FrameworkElement textBlock = (FrameworkElement)sender;
TextBox editBox = (TextBox)(textBlock.Tag);
editBox.Text = "Wow!"; // or set visible or whatever
}
(Чтобы избежать использования неприятного свойства Tag, вы могли бы определить пользовательское прикрепленное свойство для переноса привязки TextBox, но для краткости я этого не показываю)
.