首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ListBox中的TextBox、按钮和ListBox

ListBox中的TextBox、按钮和ListBox
EN

Stack Overflow用户
提问于 2009-03-10 23:38:51
回答 3查看 18.9K关注 0票数 1

我有一个列表框,在每个列表项中都有一堆控件。

代码语言:javascript
复制
<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>

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

这是我的单击事件

代码语言:javascript
复制
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"));
}

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-03-11 19:41:06

可以说,这个解决方案对手头的任务起到了作用。

代码语言:javascript
复制
    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();
    }
票数 0
EN

Stack Overflow用户

发布于 2009-03-11 00:13:57

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

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

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

您的Project类应该有两个属性:

代码语言:javascript
复制
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

代码语言:javascript
复制
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的新类。如下所示:

代码语言:javascript
复制
class Model
{
    private ObservableCollection<ProjectView> projects =
        new ObservableCollection<ProjectView>();
    public IList<ProjectView> Projects
    {
        get { return this.projects; }
    }
}

在后台代码中,将对象的DataContext设置为上述类的实例:

代码语言:javascript
复制
public class Window1
{
    public Window1()
    {
        this.InitializeComponent();

        this.DataContext = this.model;
    }

    private Model model = new Model();
}

在XAML中,应该修改绑定以绑定到上面的属性:

代码语言:javascript
复制
<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>

最后,在按钮的单击处理程序中,创建任务。ButtonDataContext将是该项目的ProjectView

代码语言:javascript
复制
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的一个实例,以便与UI一起使用。这对你更有效吗?

票数 7
EN

Stack Overflow用户

发布于 2009-03-11 03:14:10

我假设您的项目ListBox是用项目对象的集合填充的。我将在AddNewTask类中添加一个项目ICommand,并通过一个属性公开它。然后将Add New Task按钮绑定到新的AddNewTask ICommand。对于CommandParameter,放入TaskName,它将被传递到命令中。

尝试阅读一些MVVM (模型视图ViewModel)来了解它是如何工作的。它非常干净,效果很好。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/632713

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档