将DataGrid的ItemsSource绑定到一个List上。

5
我试图创建一个在ListDataGrid之间的绑定。我在网上没找到可用的解决方案,这很奇怪。
在我的小例子中,我创建了一个对象列表,其中包含两个public属性:AgeName
public class Person
{
    public string Name { get; set; }

    public int Age { get; set; }
}

public ObservableCollection<Person> Collection { get; set; } 

public List<Person> Persons { get; set; }

private void WindowLoaded(object sender, RoutedEventArgs e)
{

    this.Persons = new List<Person>();

    for (int i = 0; i != 35; i++)
    {
        this.Persons.Add(new Person() {Age = i, Name = i.ToString()});
    }

    this.Collection = new ObservableCollection<Person>(this.Persons);
}

XAML代码如下所示:
<Grid DataContext="{Binding ElementName=TestWindow, Path=.}">
    <DataGrid x:Name="DataGrid" ItemsSource="{Binding Collection}" />
</Grid>

或者这个(两个都不起作用):
<Grid DataContext="{Binding ElementName=TestWindow, Path=.}">
        <DataGrid x:Name="DataGrid" ItemsSource="{Binding Persons}" />
</Grid>

如果我使用this.DataGrid.ItemsSource = this.Persons;,我至少可以看到列表中的所有项目,但每次源List更改时都必须执行this.DataGrid.Items.Refresh(),这就是我提出问题的原因:
我做错了什么?我需要实现INotifyPropertyChanged吗?
这个问题很容易回答,但了解机制也很棒。
3个回答

5

好的,你遇到问题的原因是窗口加载时发生了什么以及数据绑定的设置。

DataGrid的ItemsSource在Window加载之后才会发生(在Window加载事件中进行设置)。因此,DataGrid不知道它的ItemsSource已经改变了。你可以通过为列表本身添加INotiftyProperty changed来解决这个问题,或者在窗口加载完成时先创建DataGrid列表,然后再填充数据。

例如:

xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        Collection = new ObservableCollection<Person>();
        InitializeComponent();
    }

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

        public int Age { get; set; }
    }

    public ObservableCollection<Person> Collection { get; set; }

    public List<Person> Persons { get; set; }

    private void WindowLoaded(object sender, RoutedEventArgs e)
    {

        this.Persons = new List<Person>();

        for (int i = 0; i != 35; i++)
        {
            this.Persons.Add(new Person() { Age = i, Name = i.ToString() });
        }

        foreach (var p in Persons)
        {
            Collection.Add(p);
        }
    }
}

xaml:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525"
        x:Name="TestWindow"
        Loaded="WindowLoaded">
    <Grid DataContext="{Binding ElementName=TestWindow, Path=.}">
        <DataGrid x:Name="DataGrid" ItemsSource="{Binding Collection}" />
    </Grid>
</Window>

1
这是一个很棒的解决方案,但有一个小问题。当您通过按钮单击更改例如第三个元素的值时,您将不会在“DataGrid”视图中看到任何更改。当您向下滚动并再次向上滚动时,您将看到更改。但如果您不触摸滚动条,则不会看到更改。 - Jens
@JensHorstmann,没错,这实际上是一个不同于你所述问题的问题。根据你最初的问题,你在DataGrid中显示项目时遇到了问题,但现在看起来你在显示项目内更新后的值时遇到了问题。 - d.moncada

2

在一整天的编码之后,我感到非常紧张和疲劳。解决方法很简单:

Person类实现INotifyPropertyChanged接口:

public class Person: INotifyPropertyChanged
{
    private string name;

    private int age;

    public string Name
    {
        get
        {
            return this.name;
        }
        set
        {
            this.name = value;
            this.OnPropertyChanged("Name");
        }
    }

    public int Age
    {
        get
        {
            return this.age;
        }
        set
        {
            this.age = value;
            this.OnPropertyChanged("Age");
        }
    }

    protected void OnPropertyChanged(string name)
    {
        if (this.PropertyChanged != null)
        {
            this.PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

然后在代码后台将数据与这些代码绑定:

this.DataGrid.DataContext = this.Persons;

要成功进行绑定,您还需要以下XAML代码:

<DataGrid x:Name="DataGrid" ItemsSource="{Binding}" />
< p > 当< code > Person 实例中的数据更改时,< code > DataGrid 中的值将刷新。 < /p >

你说得没错。但是当我通过按钮点击更改值时,视图并没有发生变化,因此我需要使用INotifyPropertyChanged。但是我真的希望能够找到一种不需要实现它的解决方案!那将会很棒。 - Jens
我添加了一个解决方案,但根据您最后的评论,也许我误解了您的问题...因为看起来您除了“将DataGrid的ItemsSource绑定到List”之外还有其他问题。 - d.moncada
如果您想在运行时更改Person属性并使其自动反映在UI上,您需要像您所做的那样实现INotifyPropertyChanged(这是正确的方法)。 - d.moncada
是的,它运行得非常好。但是当我想要向此列表添加项目时,我遇到了下一个问题...因为那时我会收到错误消息,即ItemsControl与元素源不再一致...哦天啊。 - Jens
让我们在聊天中继续这个讨论 - d.moncada
显示剩余2条评论

0

我在 Windows Forms 应用程序中经常使用数据网格视图来完成类似的事情。也许这可以指引你朝着正确的方向前进... 我对 wpf 没有太多经验。

List<Connection> connList = new List<Connection>();
//populate list somehow
BindingSource bs = new BindingSource();
bs.DataSource = connList;
DataGrid.DataSource = bs;           



    public class Connection
    {
        public string Name {get; set;}
        public string Connect {get; set;}

        public Connection(string n, string c)
        {
            Name = n;
            Connect = c;
        }
    }

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