数据网格控件不显示可观察集合数据



总的来说,我对WPF和C#相当陌生。我正在玩弄它,遇到了一个问题,我觉得这对专家来说是小菜一碟,但我不知道我做错了什么。 我正在尝试创建一个简单的 DataGrid 控件(在 TabControl 中)并将其绑定到 ObservableCollection 对象。 我使用 Microsoft 的数据绑定概述中提供的数据绑定演示作为代码的基础。

主窗口 XAML:

<Window x:Class="PetProject.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"
xmlns:local="clr-namespace:PetProject"
mc:Ignorable="d"
Title="PetProject" Height="350" Width="525">
<Window.Resources>
<CollectionViewSource 
Source="{Binding Source={x:Static Application.Current}, Path=Dogs}"   
x:Key="DogsDataView" />
</Window.Resources>

<Grid Margin="8,8,8,8">
<TabControl>
<TabItem Header="Dogs">
<DataGrid ItemsSource="{Binding Source={StaticResource DogsDataView}}">
</DataGrid>
</TabItem>
</TabControl>
</Grid>
</Window>

代码隐藏:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace PetProject
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
/// 

public partial class MainWindow : Window
{
CollectionViewSource DogsDataView;
public MainWindow()
{
InitializeComponent();
DogsDataView = (CollectionViewSource)(this.Resources["DogsDataView"]);
}
}
}

应用 XAML 是

<Application x:Class="PetProject.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PetProject"
Startup="AppStartup">
<!--StartupUri="MainWindow.xaml"-->
</Application>

代码隐藏:

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.ComponentModel;
namespace PetProject
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
private ObservableCollection<Dog> dogs = new ObservableCollection<Dog>();
void AppStartup(object sender, StartupEventArgs args)
{
LoadData();
MainWindow mainWindow = new MainWindow();
mainWindow.Show();
}
public ObservableCollection<Dog> Dogs
{
get { return this.dogs; }
set { this.dogs = value; }
}
private void LoadData() {
Dog Johnny = new Dog("Johnny",1325);
Dog Diamond = new Dog("Diamond",1327);
this.Dogs.Add(Johnny);
this.Dogs.Add(Diamond);
}

}
}

Dog 只是一个实现 INotifyPropertyChanged 接口的类(目前不做任何事情):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace PetProject
{
public class Dog : INotifyPropertyChanged
{
private string name;
private string number;
public event PropertyChangedEventHandler PropertyChanged;
public Dog(string name, int number)
{
this.name = name;
this.number = number.ToString("D4");
}

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

我将不胜感激任何帮助,以了解为什么没有填充数据网格。 此外,任何关于不良编码习惯或改进代码的建议都将非常受欢迎,因为我正处于非常初始的经验学习阶段。 谢谢!

不能绑定到私有字段。只能绑定到公共属性。就数据网格而言,Dog没有要显示的信息。

public class Dog : INotifyPropertyChanged
{
private string _name;
private string _number;
public Dog(string name, int number)
{
Name = name;
Number = number.ToString("D4");
}
public String Name
{
get { return _name; }
set
{
if (value != _name)
{
_name = value;
NotifyPropertyChanged(nameof(Name));
}
}
}
public String Number
{
get { return _number; }
set
{
if (value != _number)
{
_number = value;
NotifyPropertyChanged(nameof(Number));
}
}
}

我在您的私人字段前面加上下划线,因为这是标准做法。这是标准做法,因为有两个仅大小写不同的标识符会导致混淆和错误。

首先,我建议您阅读MVVM原则,然后选择一个MVVM框架与WPF一起使用。例如,MVVM 轻量级工具包是启动和理解 MVVM 的不错选择。

对于您的示例,下面仅提供有关代码的一些注释:

  • 我建议你把所有的"业务"数据分组到一个视图模型类中(参见网络上的 MVVM 实践) -App类中没有任何内容......
  • 此视图模型将实现"INotifyPropertyChanged"接口
  • 因此,Dogs属性将位于此 ViewModel 中,并将在其资源库中引发"属性已更改">事件(示例中当前未出现的情况)
  • 有几个 MVVM 框架会自动将您的视图"绑定"到您的视图模型,但要理解,主要目标是使用适当的 ViewModel 设置您的Window.DataContext
  • 这就是为什么您可以在 App.xaml 中还原:StartupUri="MainWindow.xaml"
  • 然后,要加载您的 ViewModel,您可以执行类似操作来加载您的 Dogs 集合:

    public partial class MainWindow : Window
    {
    public MainWindow()
    {
    InitializeComponent();
    Loaded += MainWindow_Loaded;
    }
    private void MainWindow_Loaded(object sender, RoutedEventArgs e)
    {
    // For test: LOAD & SET your DataContext here
    //
    var myDogViewmodel = new DogViewModel();
    myDogViewModel.LoadData();
    this.DataContext = myDogViewmodel;
    }
    }
    
  • 您的视图模型应如下所示:

    public class DogViewModel : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;
    private ObservableCollection<Dog> _dogs;
    public ObservableCollection<Dog> Dogs
    {
    get { return _dogs; }
    set
    {
    _dogs = value;
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Dogs"));
    }
    }
    public void LoadData()
    {
    // ....
    }
    }
    
  • 然后你的Dog类还必须实现 INotifuPropertyChanged 接口:

    public class Dog : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;
    private string _name;
    private int _number;     
    public string Name
    {
    get => _name;
    set
    {
    if (_name != value)
    { 
    _name = value;
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Name"));
    }
    }
    }
    public int Number
    {
    get => _number;
    set
    {
    if (_number != value)
    {
    _number = value;
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Number"));
    }
    }
    }
    }
    
  • 最后,在你的MainWindow.xaml中:

>

<Window x:Class="PetProject.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"
xmlns:local="clr-namespace:PetProject"
mc:Ignorable="d"
Title="PetProject" Height="350" Width="525">
<Grid Margin="8,8,8,8">
<TabControl>
<TabItem Header="Dogs">
<DataGrid ItemsSource="{Binding Dogs}" />
</TabItem>
</TabControl>
</Grid>

它现在应该可以工作;)告诉我是否清楚。熟悉 MVVM...

最新更新