如何在WPF/WP7中将字符串列表数据绑定到ListBox?

81

我想将一组字符串值绑定到列表框中,使它们的值逐行列出。目前我正在使用以下代码:

<ListBox Margin="20" ItemsSource="{Binding Path=PersonNames}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=Id}"></TextBlock>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

但是我不知道应该在文本块中放置什么,而不是Id,因为它们都是字符串值,而不是自定义类。

同时,当我将其放在MainPage中时,它会抱怨找不到PersonNames,即MainPage.PersonNames。

我将数据上下文设置为:

DataContext="{Binding RelativeSource={RelativeSource Self}}"

我做错了吗?

4个回答

170
如果简单地说,您的 ItemsSource 绑定方式如下:
YourListBox.ItemsSource = new List<String> { "One", "Two", "Three" };
你的XAML应该长这样:
<ListBox Margin="20" Name="YourListBox">
    <ListBox.ItemTemplate> 
        <DataTemplate> 
            <StackPanel Orientation="Horizontal"> 
                <TextBlock Text="{Binding}" /> 
            </StackPanel> 
        </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

更新:

当使用DataContext时,下面的代码是解决方案。以下是您将传递给页面DataContext的视图模型和设置DataContext的内容:

public class MyViewModel
{
    public List<String> Items
    {
        get { return new List<String> { "One", "Two", "Three" }; }
    }
}

//This can be done in the Loaded event of the page:
DataContext = new MyViewModel();

你的XAML现在看起来像这样:

<ListBox Margin="20" ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

这种方法的优点在于您可以将更多属性或复杂对象放入MyViewModel类中,并在XAML中提取它们。例如,要传递一个Person对象列表:

public class ViewModel
{
    public List<Person> Items
    {
        get
        {
            return new List<Person>
            {
                new Person { Name = "P1", Age = 1 },
                new Person { Name = "P2", Age = 2 }
            };
        }
    }
}

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

以下是 XAML 代码:

<ListBox Margin="20" ItemsSource="{Binding Items}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding Path=Name}" />
                <TextBlock Text="{Binding Path=Age}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

1
谢谢,我对YourListBox感到困惑。它是控件的名称吗?您必须在XAML代码中有第一行才能工作吗? - Joan Venge
1
那是一个打字错误,确实应该是控件的名称。你也可以通过页面上的DataContext或资源进行绑定项目。我给出的绑定仅用于演示目的。 :) - Abbas
谢谢,你能给我一个DataContext的例子吗?我很难理解它。 - Joan Venge
有帮助的答案 :) 但据我观察,如果您仅使用字符串而不是复杂类,则根本不需要使用 ListBox.ItemTemplate。默认行为只是打印它。 - pt12lol
@pt12lol 你说得对,但是考虑到扩展性(比如使用复杂对象),我使用了模板。 - Abbas
它不直观,也无法在设计时选择。我还没有使用XAML开发任何东西,而不必上Stack Overflow查找为什么它不起作用。 - Paul McCarthy

22
你应该给我们展示PersonNames的代码,我不确定我理解你的问题,但也许你想这样绑定它:
<TextBlock Text="{Binding Path=.}"/>
<TextBlock Text="{Binding}"/>

这将绑定到列表中的当前元素(假设PersonNames是一个字符串列表)。否则,您会在列表中看到类名。


5
需要双向绑定时必须使用Path=. - Dani

9
如果项目源作为字符串条目可枚举,请使用以下内容:
<TextBlock Text="{Binding}"></TextBlock> 

您可以在任何对象上使用此语法。通常,将调用ToString()方法以获取值。在许多情况下,这非常方便。但要注意,不会发生任何更改通知。


谢谢,我会尝试这个方法,但是我仍然在绑定部分遇到问题,在XAML中它抱怨找不到PersonNames。 - Joan Venge
@Joan Venge:绑定问题是另一个问题,不能在评论中迅速解释清楚。我假设您的UserControl或Window的DataContext未设置为公开PersonNames的实例。如果它声明在Window或UserControl中,您可以将以下内容添加到绑定中以获得快速解决方案{Binding PersonNames,RelativeSource={RelativeSource Mode=FindAncestor,AncestorType=Window}}其中您必须通过“UserControl”替换“Window”,如果您的ListBox位于UserControl中,请注意一些关于DataContext和MVVM的帖子,这将帮助您理解DataContext。 - HCL

6

您可以在不显式定义TextBlock控件作为ListBox的一部分的情况下完成此操作(除非您需要更好的格式化)。让绑定触发的诀窍是使用ObservableCollection<string>而不是List<string>

Window1.xaml

<ListView Width="250" Height="50" ItemsSource="{Binding MyListViewBinding}"/>

Window1.xaml.cs

public Window1()
{
   InitializeComponent();
   DataContext = this;

   // Need to initialize this, otherwise you get a null exception
   MyListViewBinding = new ObservableCollection<string>();
}

public ObservableCollection<string> MyListViewBinding { get; set; }

// Add an item to the list        
private void Button_Click_Add(object sender, RoutedEventArgs e)
{
   // Custom control for entering a single string
   SingleEntryDialog _Dlg = new SingleEntryDialog();

   // OutputBox is a string property of the custom control
   if ((bool)_Dlg.ShowDialog())
      MyListViewBinding.Add(_Dlg.OutputBox.Trim());
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接