TextBox, Button и ListBox в ListBox - PullRequest
       8

TextBox, Button и ListBox в ListBox

1 голос
/ 11 марта 2009

У меня есть список с кучей контролей в каждом элементе списка.

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

Thanx

Ответы [ 3 ]

7 голосов
/ 11 марта 2009

Самое простое решение, вероятно, состоит в том, чтобы один объект представлял каждый элемент во внешнем ListBox. Тогда он будет иметь свойства, которые будут представлять каждый элемент управления в элементе - текст в TextBox и элементы в ListBox (я думаю, что это список задач на основе вашего обработчика Click).

В обработчике Click вы можете получить DataContext Button (который должен быть элементом в коллекции внешнего списка) и добавить новую задачу в список задач этого объекта. Поскольку внутренний ListBox связан с этим списком, он должен быть обновлен новым элементом (при условии, что он отправляет события при добавлении элементов, например, с помощью ObservableCollection).

Обновление : Исходя из ваших комментариев, должно работать следующее.

Ваш Project класс должен иметь два свойства:

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

    private ObservableCollection<Task> tasks =
        new ObservableCollection<Task>();
    public IList<Task> Tasks
    {
        get { return this.tasks; }
    }
}

У класса Task есть только одно свойство - имя задачи.

Класс ProjectView является оберткой для класса Project (я понял эту идею из ответа @ timothymcgrath). Он отслеживает название новой задачи и текущую Project:

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

Вам понадобится новый класс, который будет использоваться как DataContext. Примерно так:

class Model
{
    private ObservableCollection<ProjectView> projects =
        new ObservableCollection<ProjectView>();
    public IList<ProjectView> Projects
    {
        get { return this.projects; }
    }
}

В приведенном ниже коде установите DataContext объекта для экземпляра вышеуказанного класса:

public class Window1
{
    public Window1()
    {
        this.InitializeComponent();

        this.DataContext = this.model;
    }

    private Model model = new Model();
}

В XAML привязки должны быть изменены для привязки к указанным выше свойствам:

<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 из Button будет ProjectView для этого элемента.

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

Поскольку все элементы управления получают свои значения посредством привязки, вам не требуется доступ к самому элементу управления для получения данных - просто используйте структуры данных, которые уже предоставляют элементы управления.

Возможно, было бы лучше переместить код, который создает задачу, в другой класс (возможно, Project), но я просто оставил его в обработчике событий для простоты ввода с моей стороны.

Обновление 2 : изменил приведенный выше код, чтобы переместить свойство NewTaskName в отдельный класс, который упаковывает экземпляр Project для использования с пользовательским интерфейсом. Это работает для вас лучше?

3 голосов
/ 11 марта 2009

Я предполагаю, что ваш Project ListBox заполнен коллекцией объектов Project. Я бы добавил AddNewTask ICommand в класс Project и выставил бы его через свойство. Затем привяжите кнопку «Добавить новую задачу» к новой команде AddNewTask ICommand. Для CommandParameter введите имя задачи, и оно будет передано в команду.

Попробуйте прочитать некоторые MVVM (Model View ViewModel), чтобы узнать, как это работает Это очень чисто и прекрасно работает.

0 голосов
/ 11 марта 2009

Это решение работало для задачи, так сказать, под рукой.

    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();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...