【问题标题】:DataGrid adds rows but text is not visibleDataGrid 添加行但文本不可见
【发布时间】:2019-02-20 14:25:56
【问题描述】:

我正在尝试在具有两列的 DataGrid 上显示一个 DataTable。

当我更新 DataTable 时,DataGrid 会显示新行,但单元格是空的。我已经为此查看了许多不同的可能解决方案,但仍然无法显示结果。

这是我的 DataGrid 的 xaml 代码:

<DataGrid x:Name="SubjectsList" Height="500" ScrollViewer.CanContentScroll="True" AutoGenerateColumns="False" CanUserAddRows="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Subject" Width="2*"/>
        <DataGridTextColumn Header="Weekly" Width="*"/>
    </DataGrid.Columns>
</DataGrid>

以下是我用于更新表格的 C# 代码:

public void AddSubject(object sender, RoutedEventArgs e)
{
    Subject temp = new Subject(SubjectName.Text, Convert.ToInt32(PerWeek.Text));

    subjects.Add(temp);
    MessageBox.Show(temp.Name + " has been added");

    for(int i = 0; i < subjectsTable.Rows.Count; i++)
    {
        subjectsTable.Rows.RemoveAt(i);
    }

    foreach (Subject subject in subjects)
    {
        DataRow dataRow = subjectsTable.NewRow();
        dataRow[0] = subject.Name;
        dataRow[1] = subject.ClassesPerWeek;
        subjectsTable.Rows.Add(dataRow);
        MessageBox.Show(subject.Name);
    }

    SubjectsList.ItemsSource = subjectsTable.DefaultView;
}

在上面的代码中,SubjectsList 是我的 DataGrid,subjectsTable 是我的 DataTable。

我尝试了以下方法:

  1. 使用DataGrid.DataContext 而不是DataGrid.ItemSource
  2. 在我的 xaml 代码中添加了 ItemSource = "{Binding Path=subjectsTable}"
  3. 尝试使用DataGrid.Items.Add(dataRow) 将行添加为项目
  4. 为我的用户定义类Subject的每个数据成员添加了gettersetter方法
  5. 我所有的变量、数据成员和数据结构都是公开的。

如果有人知道如何使数据可见,请帮助我。谢谢。

这是我添加两个主题后发生的情况:

【问题讨论】:

    标签: c# wpf xaml datatable datagrid


    【解决方案1】:

    如果您想考虑使用 MVVM 模式 (https://intellitect.com/getting-started-model-view-viewmodel-mvvm-pattern-using-windows-presentation-framework-wpf/),这里有一个基本实现:

    创建您的 ViewModel:

           public class ViewModel : INotifyPropertyChanged
           {
            public ViewModel()
            {
                CreateTestData();
                AddSubjectCommand = new Command(AddSubject);
            }
    
            public ICommand AddSubjectCommand { get; }
    
            private ObservableCollection<Subject> _subjects;
            public ObservableCollection<Subject> Subjects
            {
                get => _subjects;
                set
                {
                    _subjects = value;
                    OnPropertyChanged();
                }
            }
    
            public void AddSubject()
            {
                Subjects = new ObservableCollection<Subject>();
                DataTable subjectsTable = new DataTable();
    
                foreach (Subject subject in subjects)
                {
                    //DataRow dataRow = subjectsTable.NewRow();
                    //dataRow[0] = subject.Name;
                    //dataRow[1] = subject.ClassesPerWeek;
                    //subjectsTable.Rows.Add(dataRow);
    
                    Subjects.Add(new Subject
                    {
                        Name = subject.Name,
                        ClassesPerWeek = subject.ClassesPerWeek
                    });
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
            }
    
            #region Test data
    
            public IList<Subject> subjects { get; set; }
    
            private void CreateTestData()
            {
                subjects = new List<Subject>();
                subjects.Add(new Subject { Name = "Subject 1", ClassesPerWeek = 5 });
                subjects.Add(new Subject { Name = "Subject 2", ClassesPerWeek = 10 });
            }
    
            #endregion
            }
    

    这里你需要了解的东西:

    1. 可观察集合:https://www.c-sharpcorner.com/UploadFile/e06010/observablecollection-in-wpf/
    2. INotifyPropertyChanged:https://www.c-sharpcorner.com/article/use-inotifypropertychanged-interface-in-wpf-mvvm/
    3. ICommand:https://www.c-sharpcorner.com/UploadFile/e06010/wpf-icommand-in-mvvm/

    创建实现 ICommand 的命令:

    public class Command : ICommand
        {
            private readonly Action _action;
            private readonly bool _canExecute;
    
            public Command(Action action, bool canExecute = true)
            {
                _action = action;
                _canExecute = canExecute;
            }
    
            public bool CanExecute(object parameter)
            {
                return _canExecute;
            }
    
            public void Execute(object parameter)
            {
                _action();
            }
    
            public event EventHandler CanExecuteChanged;
        }
    

    代码隐藏(不是很干净吗?):

     public partial class MainWindow
        {
            public MainWindow()
            {
                this.InitializeComponent();
            }
        }
    

    Xaml:

    <Window.DataContext>
            <local:ViewModel />
        </Window.DataContext>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Button Content="Add Subject" Command="{Binding AddSubjectCommand}" Width="100" Height="30" HorizontalAlignment="Left" />
            <DataGrid Grid.Row="1" x:Name="SubjectsList" ItemsSource="{Binding Subjects}" Height="500" ScrollViewer.CanContentScroll="True" AutoGenerateColumns="False" CanUserAddRows="False">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Subject" Width="100">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding Name}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="Weekly" Width="100">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding ClassesPerWeek}" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    

    请参阅以下内容:

    1. DataContext 是 ViewModel
    2. Grid itemsource 是我的 ObservableCollection
    3. Button 命令绑定到 ViewModel 中的 AddSubjectCommand

    样本输出

    【讨论】:

    • 这是我必须做出的巨大改变,但我的选择已经不多了,是的,这看起来确实更干净。我会试一试,让你知道它是否适合我。谢谢。
    【解决方案2】:

    您需要为 DataGrid 中的每一列指定绑定。

    绑定路径将是 DataTable 中列的名称。

    假设你的 DataTable 列是这样定义的(你没有展示这个,所以我只能举个例子):

    subjectsTable.Columns.Add("NameColumn", typeof(string));
    subjectsTable.Columns.Add("ClassesColumn", typeof(int));
    

    XAML 中的 DataGrid 列定义应如下所示:

    <DataGridTextColumn Header="Subject" Width="2*" Binding="{Binding NameColumn}"/>
    <DataGridTextColumn Header="Weekly" Width="*" Binding="{Binding ClassesColumn}"/>
    

    替代方法是将 DataGrid 的 AutoGenerateColumns 属性设置为 true 并省略 XAML 中的列定义。但是你对网格没有太多的控制权。

    【讨论】:

    • 非常感谢。这工作得很好。尽管@Mac 提供的解决方案似乎是一种更好的设计方法,但我现在将使用它来完成我的项目。完成后,我很可能会使用 MVVM 模式重构整个项目。谢谢两位的回答。
    猜你喜欢
    • 1970-01-01
    • 2012-04-15
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多