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