Элемент управления Data Grid не отображает данные ObservableCollection - PullRequest
0 голосов
/ 16 мая 2018

Я довольно новичок в WPF и C # в целом.Я поиграюсь с этим и столкнулся с проблемой, которая, как мне кажется, могла бы стать для специалиста чем-то вроде пирога, но я понятия не имею, что я делаю неправильно.Я пытаюсь создать простой элемент управления DataGrid (внутри TabControl) и связать его с объектом ObservableCollection.Я использую демонстрацию привязки данных Microsoft , предоставленную в их обзоре привязки данных, в качестве основы для моего кода.

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>

Code-Behind:

    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>

code-behind:

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 голосов
/ 16 мая 2018

Прежде всего, я предлагаю вам прочитать о принципах MVVM, а затем, возможно, выбрать среду MVVM для использования с WPF. Например, MVVM light toolkit - хороший выбор для начала и понимания MVVM.

Для вашего примера, вот несколько замечаний о вашем коде:

  • Я предлагаю вам сгруппировать все ваши «бизнес» данные в класс viewModel (см. Практики MVVM по всему Интернету) - ничего в классе App ...
  • Эта модель представления будет реализовывать интерфейс INotifyPropertyChanged
  • Таким образом, свойство Dogs будет находиться в этой ViewModel и вызовет событие 'PropertyChanged' в его установщике (что в настоящее время не относится к вашему примеру)
  • Существует несколько инфраструктур MVVM, которые автоматически «привязывают» ваши представления к вашей модели представления, но, чтобы понять, основная цель - установить Window.DataContext с соответствующей ViewModel.
  • Вот почему вы можете восстановить в 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:

>

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

0 голосов
/ 16 мая 2018

Вы не можете привязать к приватным полям. Вы можете привязать только к публичным свойствам. Что касается 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));
            }
        }
    }

Я ставлю префиксы для ваших приватных полей, потому что это стандартная практика. Это стандартная практика, потому что наличие двух идентификаторов, которые отличаются только регистром, является путаницей и ошибками.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...