Praxiom
Praxiom

Reputation: 646

Empty Rows in WPF DataGrid

I have both a DataGrid and a ComboBox on wpf UserControl.

namespace ApSap
{ 
public partial class DocumentView : UserControl
{
    public Document document;
    public DocumentView(Document selectedDoc)
    {          
        document = selectedDoc;
        InitializeComponent();
        DocBrowser.Navigate(document.FilePath);
     
        // shows only empty rows
        SapGrid.ItemsSource = document.SapDocNumbers;   
        // shows list of values correctly       
        Combo.ItemsSource = document.SapDocNumbers;
       }
    }
}

The combo Box correctly displays the content of the public property "SapDocNumbers" (a list of integers),

However the datagrid only displays empty rows, albiet the correct number of them.

the XAML is as follows:

<UserControl x:Class="ApSap.DocumentView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         HorizontalAlignment="Stretch"
         VerticalAlignment="Stretch"
        >
<Grid  VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    
    <StackPanel  Grid.Column="1" Grid.Row="1"> 
        <DataGrid  AutoGenerateColumns="True"  x:Name="SapGrid"   Margin="10,10,10,10" >    
    </DataGrid>
        <Button x:Name="CreateInvoice" Content="Create Invoice"  Margin="10,10,10,10"  />  
        <Button x:Name="Save" Content="Save and Exit"   Margin="10,10,10,10"  />
        <ComboBox x:Name="Combo" Margin="10,10,10,10" />
    </StackPanel>
    


</Grid>

Is there anything I am missing from XAML grid definition that would mean the combo works correctly, but the datagrid does not?

as requested here is the definition of the class:

public class Document : INotifyPropertyChanged
{
    private int _docID; 

    private List<Int64> _sapDocNumbers;     

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    } 

    public int DocID
    {
        get { return _docID; }
        set
        {
            if (value != _docID)
            {
                _docID = value;
                NotifyPropertyChanged();  
            }
        }
    }  

    public List<Int64> SapDocNumbers
    {
        get { return _sapDocNumbers; }
        set
        {
            if (value != _sapDocNumbers)
            {
                _sapDocNumbers = value;
                NotifyPropertyChanged();
            }
        }
    }

Thank you

Upvotes: 0

Views: 1114

Answers (2)

EldHasp
EldHasp

Reputation: 7908

one final question, How do i get a blank row on the DataGrid so the user can add their own SapDocNumbers to the list ?

  1. The item of the collection goes to the Data Context of the DataGrid row. UI elements cannot edit their DataContext. Therefore, for a string, you need to create a reference ty with a property of the desired type and edit this property. And this type must have a default constructor.

  2. Since the list can be used in several bindings, the type of the list should not be a simple collection, but an observable collection.

For examples used class BaseInpc

using Simplified;

namespace ApSap
{
    public class DocumentRow : BaseInpc
    {
        private long _sapDocNumber;

        public long SapDocNumber { get => _sapDocNumber; set => Set(ref _sapDocNumber, value); }

        public DocumentRow(long sapDocNumber) => SapDocNumber = sapDocNumber;

        public DocumentRow() { }
    }

}
using Simplified;
using System.Collections.ObjectModel;

namespace ApSap
{
    public class Document : BaseInpc
    {
        private int _docID;

        public int DocID { get => _docID; set => Set(ref _docID, value); }

        public ObservableCollection<DocumentRow> SapDocNumbers { get; }
            = new ObservableCollection<DocumentRow>();

        public Document()
        {
        }

        public Document(int docID, params long[] sapDocNumbers)
        {
            DocID = docID;
            foreach (var number in sapDocNumbers)

                SapDocNumbers.Add(new DocumentRow(number));
        }

        public static Document ExampleInstance { get; } = new Document(123, 4, 5, 6, 7, 8, 9, 0);
    }

}
<Window x:Class="ApSap.DocumentWindow"
        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:ApSap"
        mc:Ignorable="d"
        Title="DocumentWindow" Height="450" Width="800"
        DataContext="{x:Static local:Document.ExampleInstance}">

    <Grid  VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>

        <StackPanel  Grid.Column="1" Grid.Row="1">
            <TextBlock Margin="10,10,10,0">
                <Run Text="DocID:"/>
                <Run Text="{Binding DocID}"/>
            </TextBlock>
            <DataGrid  AutoGenerateColumns="True"  Margin="10"
                       ItemsSource="{Binding SapDocNumbers}"/>
            <Button x:Name="CreateInvoice" Content="Create Invoice"  Margin="10"  />
            <Button x:Name="Save" Content="Save and Exit"   Margin="10"  />
            <ComboBox x:Name="Combo" Margin="10" />
        </StackPanel>

        <DataGrid Grid.Row="1" AutoGenerateColumns="True"  Margin="10"
                  ItemsSource="{Binding SapDocNumbers}" VerticalAlignment="Top"/>
    </Grid>
</Window>

P.S. Learn to set the Data Context and bindings to it. Using the names of UI elements, referring to them in Sharp is most often very bad code.

Upvotes: 0

EldHasp
EldHasp

Reputation: 7908

The answer to your question depends on the implementation of the collection item type.
ComboBox uses ToString () by default to represent the item.
And DataGrid renders the properties of the element - for each property there is a separate column.
If the element type has no properties, the DataGrid will not create columns and will not display anything.

For a more precise answer, show the type of the collection and the implementation of the type of its element.

Completion of the answer in connection with the clarification of the question:
You want to display the ulong collection.
This type has no properties and therefore autogenerating columns in the DataGrid cannot create columns.

For your task you need:

    <DataGrid  AutoGenerateColumns="False"  x:Name="SapGrid"   Margin="10" >
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding Mode=OneWay}" Header="Number"/>
        </DataGrid.Columns>
    </DataGrid>

Upvotes: 1

Related Questions