Search code examples
c#uwpdatagridobservablecollectionwindows-community-toolkit

UWP Community Toolkit DataGrid not displaying data


I'm trying to load a DataGrid in UWP (from the Community Toolkit package) with data from an ObservableCollection. The headers from the CSV file that the data is read from are displayed, but for some reason none of the data rows are showing up. I've read through and attempted at least 5 or 6 questions on SO, so while I know this has been asked before, those answers don't seem to be working.

I'm at such a loss at this point as to what I'm doing wrong. I know there's some mistake in my code (obviously or it would work), but I just can't seem to track it down. Can somebody please take a look at the code below and see if they can spot anything wrong?

Note: I know the data is being read correctly, because a) the headers are showing up, and b) I've hit breakpoints and looked at the data in SpellBook, and it contains 408 items.

Thanks in advance to anyone that can assist!

C#

public sealed partial class SpellPageBase : Page
{
    public ObservableCollection<Spell> SpellBook { get; set; }
    public List<Spell> spellData { get; set; }

    public static readonly DependencyProperty ComponentsProperty =
        DependencyProperty.Register("Components", typeof(string), typeof(SpellPageBase), new PropertyMetadata("Components"));

    public static readonly DependencyProperty DescriptionProperty =
        DependencyProperty.Register("Description", typeof(string), typeof(SpellPageBase), new PropertyMetadata("Description"));

    public static readonly DependencyProperty HighChangesProperty =
        DependencyProperty.Register("HighChanges", typeof(string), typeof(SpellPageBase), new PropertyMetadata("HighLevelChanges"));

    public static readonly DependencyProperty HighDescriptionProperty =
        DependencyProperty.Register("HighDescription", typeof(string), typeof(SpellPageBase), new PropertyMetadata("HighLevelDescription"));

    public static readonly DependencyProperty SchoolLevelProperty =
        DependencyProperty.Register("SpellLevel", typeof(int), typeof(SpellPageBase), new PropertyMetadata(0));

    public static readonly DependencyProperty IsRitualProperty =
        DependencyProperty.Register("IsRitual", typeof(bool), typeof(SpellPageBase), new PropertyMetadata(false));

    public static readonly DependencyProperty SchoolProperty =
        DependencyProperty.Register("School", typeof(string), typeof(SpellPageBase), new PropertyMetadata("School"));

    public static readonly DependencyProperty SpellNameProperty =
        DependencyProperty.Register("SpellName", typeof(string), typeof(SpellPageBase), new PropertyMetadata("Name"));

    public string Components
    {
        get { return (string)GetValue(ComponentsProperty); }
        set { SetValue(ComponentsProperty, value); }
    }

    public string Description
    {
        get { return (string)GetValue(DescriptionProperty); }
        set { SetValue(DescriptionProperty, value); }
    }

    public string HighChanges
    {
        get { return (string)GetValue(HighChangesProperty); }
        set { SetValue(HighChangesProperty, value); }
    }

    public string HighDescription
    {
        get { return (string)GetValue(HighDescriptionProperty); }
        set { SetValue(HighDescriptionProperty, value); }
    }

    public bool IsRitual
    {
        get { return (bool)GetValue(IsRitualProperty); }
        set { SetValue(IsRitualProperty, value); }
    }

    public string School
    {
        get { return (string)GetValue(SchoolProperty); }
        set { SetValue(SchoolProperty, value); }
    }

    public int SchoolLevel
    {
        get { return (int)GetValue(SchoolLevelProperty); }
        set { SetValue(SchoolLevelProperty, value); }
    }

    public string SpellName
    {
        get { return (string)GetValue(SpellNameProperty); }
        set { SetValue(SpellNameProperty, value); }
    }




    public SpellPageBase()
    {
        SpellBook = new ObservableCollection<Spell>();
        this.InitializeComponent();
        DataContext = this;

        //Load();
        //ReadFile();
    }

    public void ReadFile()
    {
        using (CsvReader csv = new CsvReader(new StreamReader("Assets\\Spells5thEdition.csv"), true))
        {
            int fieldCount = csv.FieldCount;
            string[] headers = csv.GetFieldHeaders();

            while(csv.ReadNextRecord())
            {
                string key = csv[0];
                string name = csv[1];
                bool isRitual = csv[2] == "1" ? true : false;
                string ritualName = csv[3];
                int level = int.Parse(csv[4]);
                Enum.TryParse(csv[5], out School school);
                //int school = new School(int.Parse(csv[5]));
                string schoolLevel = csv[6];
                string castingTime = csv[7];
                string range = csv[8];
                string duration = csv[9];
                string components = csv[10];
                string materials = csv[11];
                string description = csv[12];
                string higherLevelMods = csv[13];
                string higherLevelDescription = csv[14];
                string save = csv[15];
                string classes = csv[16];
                string sourceBook = csv[17];
                string page = csv[18];
                string bookPage = csv[19];

                spellData.Add(new Spell(key, name, isRitual, ritualName, level, school, schoolLevel, castingTime, range, duration, components, materials, description, higherLevelMods, higherLevelDescription, save, classes, sourceBook, page, bookPage));
            }
        }
        ObservableCollection<Spell> spellBook = new ObservableCollection<Spell>(spellData);
    }

    private void Page_Loaded(object sender, RoutedEventArgs e)
    {
        this.spellData = new List<Spell>();
        ReadFile();

        //foreach(Spell s in spellData)
        //{
        //    SpellBook.Add(s);
        //}
        this.spellsList.DataContext = this.SpellBook;
        spellsList.ItemsSource = SpellBook;
        spellsList.UpdateLayout();
    }

}

XAML

<Page
x:Class="DungeoneerKit.SpellPageBase"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:DungeoneerKit"
xmlns:tk="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Loaded="Page_Loaded"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
    <Grid.Resources>
        <DataTemplate x:Key="RowDetailsTemplate">
            <StackPanel>
                <TextBlock Text="Spell Details:" Margin="10" />
                <Grid Margin="20, 10" Padding="5">
                    <Grid.RowDefinitions>
                        <RowDefinition />
                        <RowDefinition />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition />
                        <ColumnDefinition />
                        <ColumnDefinition />
                    </Grid.ColumnDefinitions>
                    <TextBlock Grid.Row="0" Grid.Column="0" Text="Description: " FontWeight="SemiBold" FontSize="13" />
                    <TextBlock Grid.Row="1" Grid.Column="0" Text="At High-Levels: " FontWeight="SemiBold" FontSize="13" />
                    <TextBlock Grid.Row="2" Grid.Column="0" Text="High-Level Description: " FontWeight="SemiBold" FontSize="13" />
                    <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Description}" FontSize="13" />
                    <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding HighDescription}" FontSize="13" />
                    <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding HighChanges}" FontSize="13" />
                </Grid>
            </StackPanel>
        </DataTemplate>
    </Grid.Resources>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <tk:DataGrid x:Name="spellsList"
                 Height="900"
                 Foreground="White"
                 DataContext="{Binding SpellBook}"
                 ItemsSource="{Binding SpellBook}"
                 Grid.Row="1"
                 Margin="12"
                 VerticalAlignment="Stretch"
                 HorizontalAlignment="Stretch"
                 HorizontalScrollBarVisibility="Visible"
                 VerticalScrollBarVisibility="Visible"
                 AlternatingRowBackground="Transparent"
                 AlternatingRowForeground="Gray"
                 AreRowDetailsFrozen="False"                     
                 AutoGenerateColumns="True"
                 CanUserSortColumns="True"
                 CanUserResizeColumns="True"
                 CanUserReorderColumns="True"
                 ColumnHeaderHeight="32"
                 MaxColumnWidth="400"
                 IsReadOnly="False"
                 RowDetailsTemplate="{StaticResource RowDetailsTemplate}"
                 RowDetailsVisibilityMode="VisibleWhenSelected"
                 SelectionMode="Extended">
        <!--<tk:DataGrid.Columns>
            <tk:DataGridTextColumn Header="Spell Name" Binding="{Binding SpellName}" />
            <tk:DataGridCheckBoxColumn Header="Ritual" Binding="{Binding IsRitual}" />
            <tk:DataGridTextColumn Header="Level-School" Binding="{Binding SchoolLevel}" />
            <tk:DataGridTextColumn Header="Components" Binding="{Binding Components}" />
        </tk:DataGrid.Columns>-->
    </tk:DataGrid>
</Grid>


Solution

  • Base on your requirement, I simplify the binding steps. Please check the following code.

    Xaml Code

    <controls:DataGrid
        x:Name="MyDataGrid"
        HorizontalAlignment="Stretch"
        VerticalAlignment="Stretch"
        AlternatingRowBackground="Transparent"
        AlternatingRowForeground="Gray"
        AreRowDetailsFrozen="False"
        AreRowGroupHeadersFrozen="True"
        AutoGenerateColumns="False"
        CanUserReorderColumns="True"
        CanUserResizeColumns="True"
        CanUserSortColumns="False"
        ColumnHeaderHeight="32"
        FrozenColumnCount="0"
        GridLinesVisibility="None"
        HeadersVisibility="Column"
        HorizontalScrollBarVisibility="Visible"
        IsReadOnly="False"
        Loaded="DataGrid_Loaded"
        MaxColumnWidth="400"
        RowDetailsVisibilityMode="Collapsed"
        RowGroupHeaderPropertyNameAlternative="Range"
        SelectionMode="Extended"
        VerticalScrollBarVisibility="Visible"
        >
        <controls:DataGrid.RowGroupHeaderStyles>
            <Style TargetType="controls:DataGridRowGroupHeader">
                <Setter Property="Background" Value="LightGray" />
            </Style>
        </controls:DataGrid.RowGroupHeaderStyles>
    
        <controls:DataGrid.Columns>
            <controls:DataGridTextColumn
                Binding="{Binding Id}"
                Header="Id"
                Tag="Id"
                />
            <controls:DataGridTextColumn
                Binding="{Binding Title}"
                Header="Title"
                Tag="Title"
                />
            <controls:DataGridComboBoxColumn
                Binding="{Binding Link}"
                Header="Link"
                Tag="Link"
                />
            <controls:DataGridTextColumn
                Binding="{Binding Type}"
                Header="Type"
                Tag="Type"
                />
            <controls:DataGridTextColumn
                Binding="{Binding Remark}"
                Header="Remark"
                Tag="Remark"
                />
            <controls:DataGridTextColumn
                Binding="{Binding Time}"
                Header="Time"
                Tag="Time"
                />
        </controls:DataGrid.Columns>
    </controls:DataGrid>
    

    Model class

    public class Item
    {
        public string Id { get; set; }
        public string Title { get; set; }
        public string Link { get; set; }
        public string Type { get; set; }
        public string Remark { get; set; }
        public string Time { get; set; }
    }
    

    Data Process

    private ObservableCollection<Item> Items;
    private void DataGrid_Loaded(object sender, RoutedEventArgs e)
    {
        using (var reader = new StreamReader("Assets\\Archive.csv",true))
        using (var csv = new CsvReader(reader))
        {
            var records = csv.GetRecords<Item>();
            Items = new ObservableCollection<Item>(records);           
        }
    
        MyDataGrid.ItemsSource = Items;           
    }