[英]Inline editing TextBlock in a ListBox with Data Template (WPF)
使用 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
,但是當用戶單擊TextBlock
時,我不知道如何導航到正確的TextBox
。 也就是說,我知道用戶點擊了某個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
將只包含兩個項目,並且它們的順序永遠不會改變。
編輯:此外,將其轉換為 UserControl 允許您為每個實例創建一個Text
屬性,因此您可以為每個實例命名並直接引用文本,而無需通過((TextBox)myGrid.Children[1]).Text
獲取當前值((TextBox)myGrid.Children[1]).Text
轉換。 這將使您的代碼更加高效和干凈。 如果你把它變成一個用戶控件,你也可以命名TextBlock
和TextBox
元素,所以根本不需要轉換。
參考 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 。 它可以更改每種類型的綁定值。
理想的方法是創建一個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>
請注意在 Tag 上使用{Binding ElementName=tb}
來引用名為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 綁定,但為簡潔起見,我沒有顯示。)
如果我可以補充,為了涵蓋原始問題的(雙重)部分,在 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);
}
萬一有些人想左鍵雙擊作為輸入手勢,就像我一樣。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.