使用WPF,我有一个ListBox
控件,里面有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
回复(双)点击,将其变为TextBox
。然后,用户可以编辑描述,然后按返回或更改焦点进行更改。
我尝试在与TextBlock相同的位置添加TextBox
元素并使其可见性Collapsed
,但我不知道如何导航到右侧TextBox
用户点击了TextBlock
。也就是说,我知道用户点击了某个TextBlock
,现在 TextBox
我是否会显示?
非常感谢任何帮助,
-Ko9
答案 0 :(得分:15)
我在这些情况下所做的是使用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
只包含两个项目,并且它们的顺序永远不会改变。
编辑:此外,将其转换为UserControl允许您为每个实例创建一个Text
属性,因此您可以命名每个实例并直接引用文本,而无需通过{{1}捕获当前值铸造。这将使您的代码更加高效和干净。如果您将其设置为UserControl,您还可以命名((TextBox)myGrid.Children[1]).Text
和TextBlock
元素,因此根本不需要强制转换。
答案 1 :(得分:13)
请参阅Nathan Wheeler的代码片段,以下代码是我昨天编写的完整UserControl源代码。 特别是,解决了绑定问题。 Nathan的代码很容易理解,但需要一些帮助才能使用数据绑定文本。
ClickToEditTextboxControl.xaml.cs
public partial class ClickToEditTextboxControl : UserControl
{
public ClickToEditTextboxControl()
{
InitializeComponent();
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ClickToEditTextboxControl), new UIPropertyMetadata());
private void textBoxName_LostFocus(object sender, RoutedEventArgs e)
{
var txtBlock = (TextBlock)((Grid)((TextBox)sender).Parent).Children[0];
txtBlock.Visibility = Visibility.Visible;
((TextBox)sender).Visibility = Visibility.Collapsed;
}
private void textBlockName_MouseDown(object sender, MouseButtonEventArgs e)
{
var grid = ((Grid) ((TextBlock) sender).Parent);
var tbx = (TextBox)grid.Children[1];
((TextBlock)sender).Visibility = Visibility.Collapsed;
tbx.Visibility = Visibility.Visible;
this.Dispatcher.BeginInvoke((Action)(() => Keyboard.Focus(tbx)), DispatcherPriority.Render);
}
private void TextBoxKeyDown(object sender, KeyEventArgs e)
{
if (e == null)
return;
if (e.Key == Key.Return)
{
textBoxName_LostFocus(sender, null);
}
}
}
ClickToEditTextboxControl.xaml
<UserControl x:Class="Template.ClickToEditTextboxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
Name="root"
d:DesignHeight="30" d:DesignWidth="100">
<Grid>
<TextBlock Name="textBlockName" Text="{Binding ElementName=root, Path=Text}" VerticalAlignment="Center" MouseDown="textBlockName_MouseDown" />
<TextBox Name="textBoxName" Text="{Binding ElementName=root, Path=Text, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed" LostFocus="textBoxName_LostFocus" KeyDown ="TextBoxKeyDown"/>
</Grid>
</UserControl>
最后,您可以在XAML中使用此控件,如下所示:
<Template1:ClickToEditTextboxControl Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" MinWidth="40" Height="23" />
请注意 Mode = TwoWay,UpdateSourceTrigger = PropertyChanged 已设置。它可以更改每种类型的绑定值。
答案 2 :(得分:4)
执行此操作的理想方法是创建一个ClickEditableTextBlock
控件,默认情况下将其呈现为TextBlock,但在用户单击时显示TextBox。因为任何给定的ClickEditableTextBlock只有一个TextBlock和一个TextBox,所以没有匹配的问题。然后在DataTemplate中使用ClickEditableTextBlock而不是单独的TextBlocks和TextBoxes。
这样可以将功能封装在控件中,这样您就不会因编辑行为而污染主窗口代码隐藏,而且您可以轻松地在其他模板中重复使用它。
如果这听起来太费劲,您可以使用Tag或附加属性将每个TextBlock与TextBox相关联:
<DataTemplate>
<StackPanel>
<TextBlock Text="whatever"
MouseDown="TextBlock_MouseDown"
Tag="{Binding ElementName=tb}" />
<TextBox Name="tb" />
</StackPanel>
</DataTemplate>
请注意在标记上使用{Binding ElementName=tb}
来引用名为tb
的TextBox。
在您的代码隐藏中:
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绑定,但为了简洁起见,我没有显示它。)
答案 3 :(得分:1)
如果我可以补充一下,为了覆盖原始问题的(双精度)部分,请在Youngjae的答复中在xaml文件中进行以下替换:
<TextBlock Name="textBlockName" Text="{Binding ElementName=root, Path=Text}" VerticalAlignment="Center" MouseDown="textBlockName_MouseDown" />
被替换为
<TextBlock Name="textBlockName" Text="{Binding ElementName=root, Path=Text}" VerticalAlignment="Center" >
<TextBlock.InputBindings>
<MouseBinding Gesture="LeftDoubleCLick" Command="{StaticResource cmdEditTextblock}"/>
</TextBlock.InputBindings>
</TextBlock>
还在UserControl.Resources中添加适当的RoutedCommand
<UserControl.Resources>
<RoutedCommand x:Key="cmdEditTextblock"/>
</UserControl.Resources>
和UserControl.CommandBindings中的CommandBinding
<UserControl.CommandBindings>
<CommandBinding Command="{StaticResource cmdEditTextblock}"
Executed="CmdEditTextblock_Executed"/>
</UserControl.CommandBindings>
也在文件后面的代码中:
private void textBlockName_MouseDown(object sender, MouseButtonEventArgs e)
{
var grid = ((Grid) ((TextBlock) sender).Parent);
var tbx = (TextBox)grid.Children[1];
((TextBlock)sender).Visibility = Visibility.Collapsed;
tbx.Visibility = Visibility.Visible;
this.Dispatcher.BeginInvoke((Action)(() => Keyboard.Focus(tbx)), DispatcherPriority.Render);
}
替换为
private void CmdEditTextblock_Executed(object sender, ExecutedRoutedEventArgs e)
{
var grid = ((Grid)((TextBlock)e.OriginalSource).Parent);
var tbx = (TextBox)grid.Children[1];
((TextBlock)e.OriginalSource).Visibility = Visibility.Collapsed;
tbx.Visibility = Visibility.Visible;
this.Dispatcher.BeginInvoke((Action)(() => Keyboard.Focus(tbx)), DispatcherPriority.Render);
}
万一像我一样,某些人想留下双击作为输入手势...