Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 使用数据模板(WPF)在列表框中内联编辑文本块_C#_Wpf_Xaml_Listbox_Datatemplate - Fatal编程技术网

C# 使用数据模板(WPF)在列表框中内联编辑文本块

C# 使用数据模板(WPF)在列表框中内联编辑文本块,c#,wpf,xaml,listbox,datatemplate,C#,Wpf,Xaml,Listbox,Datatemplate,使用WPF,我有一个ListBox控件,里面有一个DataTemplate。相关XAML代码如下所示: <ListBox Name="_todoList" Grid.Row="1" BorderThickness="2" Drop="todoList_Drop" AllowDrop="True" HorizontalContentAlignment="Stretch" ScrollViewer.HorizontalScrollBarVisibility="Di

使用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
。然后,用户可以编辑描述,然后按return或change focus进行更改

我尝试在与TextBlock相同的位置添加
TextBox
元素,并使其可见性
折叠
,但当用户单击
TextBlock
时,我不知道如何导航到右侧
TextBox
。也就是说,我知道用户单击了某个
TextBlock
,现在我要显示哪个
TextBox

任何帮助都将不胜感激


-Ko9执行此操作的理想方法是创建一个
ClickEditableTextBlock
控件,默认情况下该控件呈现为TextBlock,但当用户单击它时会显示一个文本框。因为任何给定的ClickEditableTextBlock只有一个TextBlock和一个TextBox,所以没有匹配问题。然后在数据模板中使用ClickEditableTextBlock,而不是单独的文本块和文本框

这样做的另一个好处是将功能封装在控件中,这样您就不会因为编辑行为而污染主窗口代码,而且您还可以轻松地在其他模板中重用它


如果这听起来太费劲,您可以使用标记或附加属性将每个TextBlock与TextBox关联:

<DataTemplate>
  <StackPanel>
    <TextBlock Text="whatever"
               MouseDown="TextBlock_MouseDown"
               Tag="{Binding ElementName=tb}" />
    <TextBox Name="tb" />
  </StackPanel>
</DataTemplate>

(为了避免使用讨厌的标记属性,您可以定义一个自定义的附加属性来携带TextBox绑定,但为了简洁起见,我没有显示它。)

我在这些情况下所做的是使用XAML层次结构来确定要显示/隐藏的元素。大致如下:

<Grid>
  <TextBlock MouseDown="txtblk_MouseDown" />
  <TextBox LostFocus="txtbox_LostFocus" Visibility="Collapsed" />
</Grid>
我总是将这样的东西转换成一个
UserControl
,我可以在其中添加额外的错误处理,并保证
Grid
只包含两个项,并且它们的顺序永远不会改变


编辑:此外,将其转换为用户控件允许您为每个实例化创建一个
Text
属性,这样您就可以命名每个实例并直接引用文本,而无需通过
((TextBox)myGrid.Children[1])。Text
转换来查找当前值。这将使您的代码更加高效和干净。如果你把它变成一个用户控件,你也可以命名
TextBlock
TextBox
元素,因此根本不需要强制转换。

参考Nathan Wheeler的代码片段,下面的代码是我昨天编写的完整的用户控件源代码。 特别是解决了绑定问题。 Nathan的代码很容易理解,但需要一些帮助才能处理数据绑定文本

单击编辑文本框control.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);
        }
    }
}
单击ToEditTextBoxControl.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" />


请注意,设置了模式=TwoWay,UpdateSourceTrigger=PropertyChanged。它允许更改每种类型的绑定值。

如果我可以补充,为了涵盖原始问题的(双重)部分,在Youngjae的回复中,您在xaml文件中进行以下替换:

<TextBlock Name="textBlockName" Text="{Binding ElementName=root, Path=Text}" VerticalAlignment="Center" MouseDown="textBlockName_MouseDown" />
被替换为

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);
    }

如果有些人想让左双击作为输入手势,就像我做的那样…

作为提示,而不是使用
pre
标记和显式转义尖括号,您可以直接将XAML粘贴到编辑器中,并使用101010按钮将其格式化为代码。这可能听起来很奇怪,您是否可以编辑您的答案。。。我过早地点击,然后取消了投票,因为我不确定这是否是我想要的。然后我又试着发了一个追加投票,因为这是我需要的,Stack Overflow说我不能在这篇文章上投票,除非它被编辑。因此提出要求。干杯,非常有用的帖子。感谢这个解决方案,我通过
DataTemplate
为我的
ListBox
使用它,但是新值不会在源代码中更新。
ItemsSource
的类型为
ObservableCollection
。有什么想法吗?
<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 x:Key="cmdEditTextblock"/>
</UserControl.Resources>
<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);
    }