数据网格控件未显示ObservableCollection数据

时间:2018-05-16 15:08:00

标签: c# wpf data-binding

我对WPF和C#很新。我正在玩它并遇到一个问题,我觉得这对专家来说是一块蛋糕,但我不知道我做错了什么。 我正在尝试创建一个简单的DataGrid控件(在TabControl中)并将其绑定到ObservableCollection对象。 我使用他们的数据绑定概述中提供的microsoft Data Binding Demo作为我的代码的基础。

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">
    <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"]);
            }
        }
    }

App 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));
        }
    }
}

我很感激帮助理解为什么没有填充DataGrid。 此外,任何有关不良编码习惯或代码改进的建议都会非常受欢迎,因为我处于一个非常初步的经验学习阶段。 谢谢!

2 个答案:

答案 0 :(得分:1)

您无法绑定到私人字段。您只能绑定到公共属性。就DataGrid而言,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));
            }
        }
    }

我在您的私人字段前加上下划线,因为这是标准做法。它的标准做法是因为只有两个不同的标识符才是混淆和错误的处方。

答案 1 :(得分:1)

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

对于您的示例,以下是您的代码的一些评论:

  • 我建议您将所有商家&#39;数据到一个viewModel类(参见网络上的MVVM实践) - App类......
  • 此ViewModel将实施&#39; INotifyPropertyChanged&#39;接口
  • 因此 Dogs属性将位于此ViewModel中,并且会引发&#39; PropertyChanged&#39;事件在其设置器中(样本中目前不是这种情况)
  • 有几个MVVM框架会绑定&#39;自动将视图添加到视图模型中,但要理解,主要目标是使用适当的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;
            }
        }
    
  • 您的ViewModel看起来应该是这样的:

    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:

&GT;

<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 ......