La solution la plus simple serait susceptible d'avoir un objet représentent chaque élément dans la zone de liste externe. Il aurait alors des propriétés qui représenteraient chaque contrôle dans l'élément - le texte dans le TextBox, et les éléments dans le ListBox (une liste de tâches, je pense, basée sur votre gestionnaire de clic).
Dans votre gestionnaire de clic, vous pouvez obtenir le DataContext de Button (qui devrait être un élément de la collection de la liste externe) et ajouter une nouvelle tâche à la liste des tâches de cet objet. Puisque le ListBox interne est lié à cette liste, il doit être mis à jour avec le nouvel élément (en supposant qu'il envoie des événements lorsque des éléments sont ajoutés, comme avec ObservableCollection).
Mise à jour: D'après vos commentaires, ce qui suit devrait fonctionner.
Votre classe Project
doit avoir deux propriétés:
class Project
{
public string Name { get; set; }
private ObservableCollection<Task> tasks =
new ObservableCollection<Task>();
public IList<Task> Tasks
{
get { return this.tasks; }
}
}
La classe Task
a juste une propriété - le nom de la tâche.
La classe ProjectView
est un wrapper autour de la classe Project
(j'ai trouvé cette idée dans la réponse de @ timothymcgrath). Il garde la trace du nom d'une nouvelle tâche, et la Project
actuelle:
class ProjectView : INotifyPropertyChanged
{
public Project Project { get; set; }
private string newTaskName = string.Empty;
public string NewTaskName
{
get { return this.newTaskName; }
set
{
this.newTaskName = value;
this.OnPropertyChanged("NewTaskName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propName)
{
PropertyChangedEventHandler eh = this.PropertyChanged;
if(null != eh)
{
eh(this, new PropertyChangedEventArgs(propName));
}
}
}
Vous aurez besoin d'une nouvelle classe qui sera utilisée comme DataContext
. Quelque chose comme ceci:
class Model
{
private ObservableCollection<ProjectView> projects =
new ObservableCollection<ProjectView>();
public IList<ProjectView> Projects
{
get { return this.projects; }
}
}
Dans le code derrière, définissez l'DataContext
de l'objet à une instance de la classe ci-dessus:
public class Window1
{
public Window1()
{
this.InitializeComponent();
this.DataContext = this.model;
}
private Model model = new Model();
}
Dans le XAML, les liaisons devrait être modifiée pour se lier à la propriétés ci-dessus:
<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>
Enfin, dans le gestionnaire de clic pour le bouton, créez la tâche. Le DataContext
du Button
sera le ProjectView
pour cet article.
private void ButtonAddNewTask_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
ProjectView curProject = btn.DataContext as Project;
if(null != curProject)
{
curProject.Project.Tasks.Add(new Task()
{
Name = curProject.NewTaskName
});
}
}
Étant donné que tous les contrôles obtiennent leurs valeurs par liaison, vous n'avez pas besoin d'accéder au contrôle lui-même pour obtenir les données - il suffit d'utiliser les structures de données qui approvisionnent les contrôles déjà.
Il serait probablement préférable de déplacer le code qui crée la tâche dans une autre classe (éventuellement Project
), mais je l'ai simplement laissé dans le gestionnaire d'événements pour faciliter la frappe de ma part.
Update 2: modifié le code ci-dessus pour déplacer la propriété NewTaskName
dans une catégorie distincte qui enveloppe une instance de Project
pour une utilisation avec l'interface utilisateur. Est-ce que cela fonctionne mieux pour vous?
Qu'est-ce que vous entendez par «mettre en place la zone de texte»? – Joey
Le but était de créer la tâche avec le texte de la zone de texte. TextBox newTaskTextBox = quelque chose ici; proj.Tasks.Add (nouvelle tâche (newTaskTextBox.Text)); –