Wpf 列表框中的文本框、按钮和列表框

Wpf 列表框中的文本框、按钮和列表框,wpf,listbox,Wpf,Listbox,我有一个列表框,每个列表项中都有一组控件 <ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel> <TextBlock Text="{Binding Name}" />

我有一个列表框,每个列表项中都有一组控件

<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Name}" />
                <ListBox x:Name="taskList" ItemsSource="{Binding Tasks}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Name}" />
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
                <TextBox x:Name="textBoxTask" />
                <Button
                    x:Name="ButtonAddNewTask"
                    Content="Test"
                    CommandParameter="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataContext}"
                    Click="ButtonAddNewTask_Click"
                    />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

当我单击列表框中的按钮时,我想向列表框中的列表框添加一个新项目。我已经走了这么远。所以我的问题是我如何获得文本框以及如何更新列表框

这是我的点击事件

private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e)
{
    Button button = (Button)sender;
    Project proj = button.DataContext as Project;
    if(proj.Tasks == null)
        proj.Tasks = new List<Task>();

    proj.Tasks.Add(new Task("Added Task"));
}
private void按钮dnewtask\u单击(对象发送方,路由目标)
{
按钮=(按钮)发送器;
Project proj=button.DataContext作为项目;
if(proj.Tasks==null)
项目任务=新列表();
项目任务添加(新任务(“添加的任务”);
}

Thanx

最简单的解决方案可能是让一个对象代表外部列表框中的每个项目。然后,它将具有表示项中每个控件的属性—文本框中的文本和列表框中的项(我认为是基于单击处理程序的任务列表)

在单击处理程序中,可以获取按钮的DataContext(应该是外部列表集合中的一个项),并将新任务添加到该对象的任务列表中。由于内部ListBox绑定到该列表,因此应该使用新项更新它(假设它在添加项时发送事件,例如使用ObservableCollection)

更新:根据您的评论,以下内容应该有效

您的
项目
类应具有两个属性:

class Project
{
    public string Name { get; set; }

    private ObservableCollection<Task> tasks =
        new ObservableCollection<Task>();
    public IList<Task> Tasks
    {
        get { return this.tasks; }
    }
}
<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True"
    ItemsSource="{Binding Path=Projects}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Project.Name}" />
                <ListBox x:Name="taskList"
                    ItemsSource="{Binding Project.Tasks}"
                    DisplayMemberPath="Name" />
                <TextBox x:Name="textBoxTask"
                    Text="{Binding Path=NewTaskName, UpdateSourceTrigger=PropertyChanged}"/>
                <Button x:Name="ButtonAddNewTask" Content="Test"
                    Click="ButtonAddNewTask_Click" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
您需要一个新类,该类将用作
DataContext
。大概是这样的:

class Model
{
    private ObservableCollection<ProjectView> projects =
        new ObservableCollection<ProjectView>();
    public IList<ProjectView> Projects
    {
        get { return this.projects; }
    }
}
在XAML中,应修改绑定以绑定到上述属性:

class Project
{
    public string Name { get; set; }

    private ObservableCollection<Task> tasks =
        new ObservableCollection<Task>();
    public IList<Task> Tasks
    {
        get { return this.tasks; }
    }
}
<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True"
    ItemsSource="{Binding Path=Projects}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Project.Name}" />
                <ListBox x:Name="taskList"
                    ItemsSource="{Binding Project.Tasks}"
                    DisplayMemberPath="Name" />
                <TextBox x:Name="textBoxTask"
                    Text="{Binding Path=NewTaskName, UpdateSourceTrigger=PropertyChanged}"/>
                <Button x:Name="ButtonAddNewTask" Content="Test"
                    Click="ButtonAddNewTask_Click" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
由于所有控件都是通过绑定获取其值的,因此不需要访问控件本身来获取数据,只需使用已经提供控件的数据结构即可

将创建任务的代码移动到另一个类(可能是
Project
)可能会更好,但我只是将其留在事件处理程序中,以便于键入


更新2:修改上述代码,将
NewTaskName
属性移动到一个单独的类中,该类封装了
Project
的实例,以便与UI一起使用。这对您更有效吗?

最简单的解决方案可能是让一个对象代表外部列表框中的每个项目。然后,它将具有表示项中每个控件的属性—文本框中的文本和列表框中的项(我认为是基于单击处理程序的任务列表)

在单击处理程序中,可以获取按钮的DataContext(应该是外部列表集合中的一个项),并将新任务添加到该对象的任务列表中。由于内部ListBox绑定到该列表,因此应该使用新项更新它(假设它在添加项时发送事件,例如使用ObservableCollection)

更新:根据您的评论,以下内容应该有效

您的
项目
类应具有两个属性:

class Project
{
    public string Name { get; set; }

    private ObservableCollection<Task> tasks =
        new ObservableCollection<Task>();
    public IList<Task> Tasks
    {
        get { return this.tasks; }
    }
}
<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True"
    ItemsSource="{Binding Path=Projects}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Project.Name}" />
                <ListBox x:Name="taskList"
                    ItemsSource="{Binding Project.Tasks}"
                    DisplayMemberPath="Name" />
                <TextBox x:Name="textBoxTask"
                    Text="{Binding Path=NewTaskName, UpdateSourceTrigger=PropertyChanged}"/>
                <Button x:Name="ButtonAddNewTask" Content="Test"
                    Click="ButtonAddNewTask_Click" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
您需要一个新类,该类将用作
DataContext
。大概是这样的:

class Model
{
    private ObservableCollection<ProjectView> projects =
        new ObservableCollection<ProjectView>();
    public IList<ProjectView> Projects
    {
        get { return this.projects; }
    }
}
在XAML中,应修改绑定以绑定到上述属性:

class Project
{
    public string Name { get; set; }

    private ObservableCollection<Task> tasks =
        new ObservableCollection<Task>();
    public IList<Task> Tasks
    {
        get { return this.tasks; }
    }
}
<ListBox x:Name="projectList" IsSynchronizedWithCurrentItem="True"
    ItemsSource="{Binding Path=Projects}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Text="{Binding Project.Name}" />
                <ListBox x:Name="taskList"
                    ItemsSource="{Binding Project.Tasks}"
                    DisplayMemberPath="Name" />
                <TextBox x:Name="textBoxTask"
                    Text="{Binding Path=NewTaskName, UpdateSourceTrigger=PropertyChanged}"/>
                <Button x:Name="ButtonAddNewTask" Content="Test"
                    Click="ButtonAddNewTask_Click" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>
由于所有控件都是通过绑定获取其值的,因此不需要访问控件本身来获取数据,只需使用已经提供控件的数据结构即可

将创建任务的代码移动到另一个类(可能是
Project
)可能会更好,但我只是将其留在事件处理程序中,以便于键入


更新2:修改上述代码,将
NewTaskName
属性移动到一个单独的类中,该类封装了
Project
的实例,以便与UI一起使用。这对您更有效吗?

我假设您的项目列表框中填充了一组项目对象。我将向项目类添加AddNewTask ICommand,并通过属性公开它。然后将添加新任务按钮绑定到新的AddNewTask ICommand。对于CommandParameter,输入TaskName,它将被传递到命令中


尝试阅读一些MVVM(模型-视图-视图-模型)以了解其工作原理的一些示例。它非常干净,效果非常好

我假设您的项目列表框中填充了一组项目对象。我将向项目类添加AddNewTask ICommand,并通过属性公开它。然后将添加新任务按钮绑定到新的AddNewTask ICommand。对于CommandParameter,输入TaskName,它将被传递到命令中


尝试阅读一些MVVM(模型-视图-视图-模型)以了解其工作原理的一些示例。它非常干净,效果非常好

可以说,这个解决方案对手头的任务有效

    private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e)
    {
        Button button = (Button)sender;
        DependencyObject obj = LogicalTreeHelper.GetParent(button);
        StackPanel item = obj as StackPanel;
        TextBox textBox = item.FindName("textBoxTask") as TextBox;
        ListBox listBox = item.FindName("taskList") as ListBox;

        Project proj = button.DataContext as Project;
        if(proj.Tasks == null)
            proj.Tasks = new List<Task>();

        listBox.ItemsSource = proj.Tasks;
        listBox.Items.Refresh();
    }
private void按钮dnewtask\u单击(对象发送方,路由目标)
{
按钮=(按钮)发送器;
DependencyObject obj=LogicalTreeHelper.GetParent(按钮);
StackPanel项目=作为StackPanel的obj;
TextBox TextBox=item.FindName(“textBoxTask”)作为TextBox;
ListBox ListBox=item.FindName(“任务列表”)作为ListBox;
Project proj=button.DataContext作为项目;
if(proj.Tasks==null)
项目任务=新列表();
listBox.ItemsSource=项目任务;
listBox.Items.Refresh();
}

可以说,这个解决方案适用于手头的任务

    private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e)
    {
        Button button = (Button)sender;
        DependencyObject obj = LogicalTreeHelper.GetParent(button);
        StackPanel item = obj as StackPanel;
        TextBox textBox = item.FindName("textBoxTask") as TextBox;
        ListBox listBox = item.FindName("taskList") as ListBox;

        Project proj = button.DataContext as Project;
        if(proj.Tasks == null)
            proj.Tasks = new List<Task>();

        listBox.ItemsSource = proj.Tasks;
        listBox.Items.Refresh();
    }
private void按钮dnewtask\u单击(对象发送方,路由目标)
{
按钮=(按钮)发送器;
DependencyObject obj=LogicalTreeHelper.GetPare