【问题标题】:Bind the ItemsSource of a DataGrid to a List将 DataGrid 的 ItemsSource 绑定到列表
【发布时间】:2015-11-22 07:58:31
【问题描述】:

我正在尝试在 ListDataGrid 之间创建绑定。我还没有在网上找到一个很奇怪的有效解决方案。

在我的小例子中,我使用两个 public 属性 AgeName 创建了一个 List 对象:

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吗?

这个问题一定很容易回答,但如果能理解其中的机制也很棒。

【问题讨论】:

    标签: c# wpf binding datagrid


    【解决方案1】:

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

    DataGrid 的 ItemsSource 直到 Window 已经加载(它在您的 Window 加载事件中设置)才会发生。因此,DataGrid 现在并没有改变它的 ItemsSource。您可以通过将 INotiftyProperty 更改添加到列表本身来解决此问题,或者,您可以先创建 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>
    

    【讨论】:

    • 这是一个很酷的解决方案,但有一个小问题。当您更改例如的值时单击按钮上的第三个元素,那么您将不会在 DataGrid 视图中看到任何更改。当您再次向下和向上滚动时,您将看到更改。但如果您不触摸滚动条,则不会。
    • @JensHorstmann 对,这实际上是与您所说的不同的问题。根据您最初的问题,您在 DataGrid 中显示项目时遇到了问题,但现在看起来您在显示项目中的更新值时遇到了问题。
    【解决方案2】:

    在漫长的一天编码之后,我太紧张太累了。解决方法很简单:

    Person 类实现INotifyPropertyChanged Interface

    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;
    

    对于成功的Binding,您还需要这些XAML 代码:

    <DataGrid x:Name="DataGrid" ItemsSource="{Binding}" />
    

    现在,只要 Person 实例之一中的数据发生更改,DataGrid 中的值就会刷新。

    【讨论】:

    • 您不需要实现 INotiftyPropertyChanged。您的示例之所以有效,是因为您正在进行延迟绑定,并且为了更新数据上下文,您需要 INotifyPropertyChanged。你可以做到。生病在下面发布答案
    • 你是对的。但是当我用例如改变值时一个按钮单击视图不会改变,因为我需要 INotifyPropertyChanged。但我真的很想看到一个不实施的解决方案!那太好了。
    • 我添加了一个解决方案,但根据您的最后评论,我可能误解了您的问题.. 因为看起来您除了“将 DataGrid 的 ItemsSource 绑定到列表”之外还有另一个问题
    • 我同意!这不是线程的主题。我会接受你的回答,但也许我们可以讨论如何解决这个问题。我现在应该实施 INotifyPropertyChanged 吗?还是有更好的方法?
    • 如果您想在运行时更改 Person 属性并让它自动反映 UI,您将需要像您所做的那样实现 INotiftyPropertyChangted(这是正确的方法)。
    【解决方案3】:

    我在带有数据网格视图的 Windows 窗体应用程序中做了很多类似的事情。所以也许这可以为你指明正确的方向......我对 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;
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-30
      • 2011-10-25
      • 2013-01-14
      • 1970-01-01
      • 2023-03-07
      • 2013-12-12
      • 2013-08-06
      • 2014-08-13
      相关资源
      最近更新 更多