DataGrid привязан к списку, не позволяя пользователю добавлять новую строку - PullRequest
0 голосов
/ 05 августа 2020

Я знаю, что этот вопрос дублирует несколько других, потому что я изучал эти «несколько других». И я не смог понять, где я напортачил.

Этот пост конкретно о:

  • C#
  • WPF
  • DataGrid
  • List <>
  • Привязка DataGrid к списку <>

Когда я запускаю свой код, DataGrid позволяет мне изменять и удалять строки. DataGrid не позволяет мне добавлять строку. Почему?

Xaml:

<Window
    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:myNamespace"
    xmlns:Schema="clr-namespace:System.Xml.Schema;assembly=System.Xml.ReaderWriter" x:Class="myNamespace.MainWindow"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="600">
<Grid>
    <DataGrid x:Name="dataGrid" AutoGenerateColumns="False"   >
        <DataGrid.Columns>
            <DataGridTextColumn x:Name="col_id" Width="200" Header="Col ID"  Binding="{Binding value_id}" />
            <DataGridTextColumn x:Name="col_1" Width="200" Header="Col One"  Binding="{Binding value_1}" />
            <DataGridTextColumn x:Name="col_2" Width="200" Header="Col Two"  Binding="{Binding value_2}" />
        </DataGrid.Columns>
    </DataGrid>

</Grid>

Код позади:

using System.Collections.Generic;
using System.Windows;

namespace myNamespace
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            init_item_list();
            dataGrid.ItemsSource = ItemList;
        }


        public List<DataItem> ItemList = new List<DataItem>();

        public void init_item_list()
        {
            ItemList.Add(new DataItem(1, "one", "i"));
            ItemList.Add(new DataItem(2, "two", "ii"));
            ItemList.Add(new DataItem(3, "three", "ii"));
        }
        public class DataItem
        {
            public DataItem(int id, string val_1, string val_2)
            {
                value_id = id;
                value_1 = val_1;
                value_2 = val_2;
            }
            private int _value_id;
            public int value_id
            {
                get { return _value_id; }
                set { _value_id = value; }
            }

            private string _value_1;
            public string value_1
            {
                get { return _value_1; }
                set { _value_1 = value; }
            }

            private string _value_2;
            public string value_2
            {
                get { return _value_2; }
                set { _value_2 = value; }
            }


        }

    }
}

Мне кажется, я видел строки, добавленные из пользовательского интерфейса, когда DataGrid привязан к списку. Однако я не вижу, чтобы он работал с моим кодом здесь.

Эфраим Ньюман прокомментировал, что проблема может заключаться в использовании List. В других сообщениях я видел упоминание о том, что ObservableCollection работает лучше, чем List for DataGrid.

В коде позади я изменил

            public List<DataItem> ItemList = new List<DataItem>();

на

public ObservableCollection<DataItem> ItemList = new ObservableCollection<DataItem>();

раньше изменение (с помощью List), работающая DataGrid выглядела так:

Before

After the change (using ObservableCollection), the running DataGrid looked like this:

введите описание изображения здесь

В любом случае нет пустой строки для добавления новой записи.

Я не вижу никакой разницы при использовании ObservableCollection вместо List. DataGrid по-прежнему не позволяет мне добавить запись.

Я думаю, что преимущество использования ObservableCollection заключается в том, что ObservableCollection уведомляет (вызывает DataGrid) для обновления всякий раз, когда в ObservableCollection есть изменения. Кажется, это не проблема.

Здесь проблема в том, что DataGrid не принимает никаких новых записей.

В Xaml я попытался явно установить для CanUserAddRows значение True и даже False.

    <DataGrid x:Name="dataGrid" AutoGenerateColumns="False" CanUserAddRows="True"   >

Ответ

@ mm8 обнаружил мою проблему: мне нужно было добавить конструктор по умолчанию без параметров. Я добавил:

            public DataItem() { }

Xaml остается таким, каким был изначально. Обратите внимание, что теперь я привязываюсь к List .

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;

namespace myNamespace
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
    InitializeComponent();

    init_item_list();
    dataGrid.ItemsSource = _itemList;
    }


    private List<DataItem> _itemList = new List<DataItem>();
    public List<DataItem> ItemList
    {
    get { return _itemList; }
    set { _itemList = value; }
    }

    public void init_item_list()
    {
    _itemList.Add(new DataItem(1, "one", "i"));
    _itemList.Add(new DataItem(2, "two", "ii"));
    _itemList.Add(new DataItem(3, "three", "ii"));
    }
    public class DataItem
    {
    public DataItem() { }
    public DataItem(int id, string val_1, string val_2)
    {
        value_id = id;
        value_1 = val_1;
        value_2 = val_2;
    }
    private int _value_id;
    public int value_id
    {
        get { return _value_id; }
        set { _value_id = value; }
    }

    private string _value_1;
    public string value_1
    {
        get { return _value_1; }
        set { _value_1 = value; }
    }

    private string _value_2;
    public string value_2
    {
        get { return _value_2; }
        set { _value_2 = value; }
    }

}

Я думаю, что в примере, где вы не можете использовать List, вы измените List напрямую и вам понадобится DataGrid для отображения изменения.

Я тестировал этот код, используя как List, так и ObservableCollection. Теперь он работает с добавлением конструктора по умолчанию без параметров.

Ответы [ 2 ]

3 голосов
/ 05 августа 2020

A List<T> не реализует интерфейс INotifyCollectionChanged, который необходим для того, чтобы представление могло подписаться на добавляемые или удаляемые элементы и автоматически обновлять sh элемент управления.

Единственный встроенный класс, реализующий этот интерфейс, - ObservableCollection<T>. Если вы измените тип ItemList, он должен работать должным образом:

public ObservableCollection<DataItem> ItemList = new ObservableCollection<DataItem>();

Вам также следует подумать о создании ItemList свойства publi c или переименовать его в _itemList и сделайте его частным полем:

private readonly ObservableCollection<DataItem> _itemList = new ObservableCollection<DataItem>();

Чтобы DataGrid отображала пустую строку, которая позволяет вам добавить элемент в исходную коллекцию, ваш DataItem класс должен определять значение по умолчанию без параметров конструктор:

public DataItem() { }
1 голос
/ 05 августа 2020

Кажется, проблема в том, что вы используете List, который не сообщает WPF, когда он обновляется. вместо этого следует использовать ObservableCollection.

...