Search code examples
c#wpfdatatabledatagrid

DataGrid not showing Data from datatable


So i have been into wpf from 3 days now , and im not able to figur out why the datatable values are not showing up in the data grid , this was not the case for datagridview in windows forms , which iwas using since 10 days

im have tried both programatical and xaml binding , but none of them was working for me

first i had created the datagrid as a seprate user control and had attached the file with the Main Window but the data was not able to be seen , so i thought maybe i should do the testing if the data is shown in the mainwinow itself , then i will septate the datagrid into its own user control, but both of them didnt worked

Here is the MainWindow.xaml

<Border> 
  <Grid>
       <Border Grid.Row="1" CornerRadius="20" Margin="15,0,15,15" >
                <!-- Apply Style with Rounded Corners to DataGrid -->
                <DataGrid 
                        IsReadOnly="True"
                        x:Name="dataGrid"
                        AutoGenerateColumns="False">
                    <DataGrid.Resources>
                        <!-- Cell Background -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#121212"/>
                        <!-- Cell Foreground (Text) -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlTextBrushKey}" Color="#FFFFFF"/>
                        <!-- Grid Lines -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveBorderBrushKey}" Color="#1E1E1E"/>
                        <!-- Header Background -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlDarkDarkBrushKey}" Color="#2E2E2E"/>
                        <!-- Header Foreground (Text) -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlLightLightBrushKey}" Color="#FFFFFF"/>
                    </DataGrid.Resources>
                    <DataGrid.Style>
                        <Style TargetType="DataGrid">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type DataGrid}">
                                        <Border Background="{TemplateBinding Background}" CornerRadius="20">
                                            <ScrollViewer>
                                                <!-- ContentPresenter displays the actual DataGrid content -->
                                                <ContentPresenter/>
                                            </ScrollViewer>
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </DataGrid.Style>
                </DataGrid>
            </Border>
  </Grid>
</Border>

Here is the MainWindow.xaml.cs

 public partial class MainWindow : Window
    {
        private DataTable dataTable;
        public MainWindow()
        {
            InitializeComponent();
            InitializeDataGridAsync();


        }

        private async void InitializeDataGridAsync()
        {
            var newDT = CreateDataTable();
            

            // Simulate a delay for loading data (replace this with your actual data loading logic)
            await Task.Delay(3000);

            // Set the DataTable as the DataGrid's ItemsSource
            dataGrid.ItemsSource = newDT.DefaultView;

        }

        private DataTable CreateDataTable()
        {
          
        // Create a DataTable with columns
        dataTable = new DataTable("MyDataTable");

            // Add 10 sample columns
            for (int i = 1; i <= 100; i++)
            {
                dataTable.Columns.Add($"Column{i}", typeof(int));
            }

            // Add 100 rows of sample data
            for (int row = 1; row <= 100; row++)
            {
                // Create an array to hold values for each column
                object[] values = new object[100];

                // Assign sample values to each column
                for (int col = 0; col < 100; col++)
                {
                    values[col] = row * 100 + col + 1; // You can change this to your desired data
                }

                // Add the row to the DataTable
                dataTable.Rows.Add(values);
            }
            return dataTable;
        }

    }

Here is a screen shot for refrecne, the first grey card is where the datagrid is located

enter image description here


Solution

  • Your ControlTemplate for the DataGrid is wrong. There is no chance for the DataGrid to display any data.

    The DataGrid is an ItemsControl. As such, it must contain an ItemsPresenter and not a ContentPresenter.

    ContentPresenter is for ContentControl and ItemsPresenter is for ItemsControl.

    The DataGrid template is more complex than a simple ItemsPresenter as it has e.g. column headers etc. to show.

    You can find the Style for the DataGrid at Microsoft Docs: DataGrid Styles and Templates.
    Or use the Visual Studio XAML designer to edit a copy of the original Style (by right clicking on the DataGrid element in the designer view).
    Or use Blend to edit the default Style.


    As a note: don't call async methods from the constructor. A method is async because it is considered long-running (enough to freeze the main thread). And long-running methods should not be executed from the constructor. Constructing an instance must be a brief operation (the constructor must return fast and not block the thread).

    Instead, defer the long-running initialization routine. Use the constructor to initialize the property to a useful default and execute the long-running initialization routine later.
    This has a few advantages:

    • initialization code can be asynchronous
      (asynchronous methods can be properly awaited using await)
    • expensive resources can be allocated when actually requested
      (to avoid heavy instances that allocate unused resources)
    • initialization can be further customized (increased flexibility in general)
    • instantiation of the type is no longer a blocking operation
      (blocking is an unexpected constructor behavior)
    • in the UI context you can avoid freezing (bad UX)
    • better testability for unit tests as expensive initialization can be explicitly avoided

    Just to name a few. You surely find more.

    Deferring the initialization of a FrameworkElement or its dependencies is especially easy, as we can use the FrameworkElement.Loaded event for this purpose. This has another advantage: you can now show a busy indicator on the UI to avoid giving the user the feel that the application hangs (which it actually would had the long-running routine ran in the constructor).

    public MainWindow()
    {
      InitializeComponent();
    
      this.Loaded += OnLoaded;
    
      // Return quickly 
      // to make instantiation of this type a non-blocking operation
    }
    
    private async void OnLoaded(object sender, EventArgs)
    {
      // TODO::Show busy indicator
    
      // Properly await the async operation
      await InitializeDataGridAsync();
    }