WPF DataGrid adds rows but not the data (blank rows)
Asked Answered
I

3

5

Alright so this is going to be hard to explain.

Scenario:

I have a DataGrid defined as follows:

<DataGrid Height="100" Name="test" IsReadOnly="False">
    <DataGrid.Columns>
        <DataGridTextColumn Header="URL"></DataGridTextColumn>
        <DataGridTextColumn Header="PORT"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

data grid visual

It has two headers and I need to add data, I've done a lot of research that suggests using an ObservableCollection since that will fire the DataChanged event.

I can formulate this data with long boring code that probably isn't relevant (you'll see why below).

Problem:

The 200 rows are added but the text itself isn't in the table

blank rows

Troubleshooting:

I turned on debugging and with screenshots help, you can see there is actual data but it won't insert it into the rows, but it adds the rows.

Data Collection

Relevant Code:

ObservableCollection<Proxy> collection = new ObservableCollection<Proxy>();
collection = GetData(ips,ports);
test.CanUserAddRows = true;
test.ItemsSource = null;
test.ItemsSource = collection;
MessageBox.Show("Done");

NOTE: I added the .ItemSource = null; and then set it equal to the collection as that enabled the rows to show up. I've tried using the suggested: test.DataContext = collection; But, no rows get added at all, and yes just as this test the data is visible in debug mode as being part of the context/itemsource.

UPDATE:

I've tried implementing the following XAML with the same results

<DataGrid Height="100" Name="test" IsReadOnly="False" ItemsSource="{Binding collection}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="URL" Binding="{Binding ip}"></DataGridTextColumn>
        <DataGridTextColumn Header="PORT" Binding="{Binding port}"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

Proxy Class:

public class Proxy
{
    public string ip;
    public string port;
}

UPDATE 2: When adding get and set methods the following was my result:

four columns?

Ivelisseivens answered 25/2, 2015 at 5:38 Comment(5)
Where do you tell your app what do write into the columns? You just set the itemssource (what you should do in xaml if you ask me)Byelorussian
Hi, can you explain a little more please? Do you mean to create DataBindings in XAML?Ivelisseivens
You have no binding in your DataGridTextColumn and hence they don't show any data.Perspex
@PhilipStuyck, if I have a ObservableCollection, how would I bind to this or do I have to split it?Ivelisseivens
There is already 2 answers overlapping mostly. You have to bind to your Proxy members. You can also experiment with AutogenerateColumns = true. just to be sure there is data.Perspex
D
14

You are missing to define the Properties for the bindings: at least, change the Proxy class like this:

public class Proxy
{
    public string ip {get; set;}
    public string port {get; set;}
}
Dactylic answered 25/2, 2015 at 6:8 Comment(8)
Wow that is very interesting. See my updated question, that kind of worked.Ivelisseivens
Maybe you can delete the autogenerate columns if you have the explicit bindingsDactylic
Bingo, had to force it to be false.Ivelisseivens
Actually this is just the beginning because you need to implement INotifyPropertyChanged on the Proxy class. user3596113's answer is more complete and should work.Perspex
If the only changes of those properties are from that datagrid you don't need to notify. That is incomplete if you have to reflect updates from other sources than the data grid itself.Dactylic
Thank you so much, so saved me!Regimen
Wow!! I was just missing the {get; set;} . Never thought this could be the reason. Insane!Clumsy
that helped also for structsHomegrown
P
2

You have no binding for your columns. This is an example on how to do it :

<DataGrid x:Name="RelatieSearchGrid" AutoGenerateColumns="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" 
                       ItemsSource="{Binding Relaties.View}" IsReadOnly="True"   
                       SelectionMode="Single">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Naam" Binding="{Binding Naam}"/>
            <DataGridTextColumn Header="Straat" Binding="{Binding Straat}"/>
            <DataGridTextColumn Header="Postcode" Binding="{Binding Postcode}"/>
            <DataGridTextColumn Header="Gemeente" Binding="{Binding Gemeente}"/>
            <DataGridTextColumn Header="BTW" Binding="{Binding BTW}"/>
        </DataGrid.Columns>
    </DataGrid>

In your case since the collection contains proxy, you need to bind to the proxy members. You didn't show the proxy code so I can only guess what those members are. If you want to go via the datacontext, then you need to work with a viewmodel. In that case I suggest you read something about MVVM first.

Perspex answered 25/2, 2015 at 5:50 Comment(4)
Hi, I think I started to implement what you're suggesting here, check my updated question. Or I may be completely off base hereIvelisseivens
Your binding has to contain the exact member names to proxy ie ip and port and not Url and Port. Binding is case sensitive!!Perspex
Sorry, I've updated the question and updated my xaml with sadly no change.Ivelisseivens
try this first AutoGenerateColumns="True"Perspex
B
1

You should first set the ItemsSource in xaml:

<DataGrid ItemsSource="{Binding test}" ... >

Then you should add your TemplateColumns like this:

<DataGrid ItemsSource="{Binding test}" ...>
    <DataGrid.Columns>
        <DataGridTextColumn Binding="{Binding Url}"
                                            Header="URL" />
        <DataGridTextColumn Binding="{Binding Port}"
                                            Header="Port" />
    </DataGrid.Columns>
</DataGrid>

Note that this will need your Objects stored in the ObservableCollection test to have an Url and a Port Porperty.

Change your Model class to implement INPC and adjust your properties like this:

public class Proxy : INPC
{
    public String Url
    {
        get
        {
            return url;
        }
        set
        {
            if (url== value) {
                return;
            }
            url= value;
            RaisePropertyChanged("Url");
        }
    }
    private string url;

    public String Port
    {
        get
        {
            return port;
        }
        set
        {
            if (port== value) {
                return;
            }
            port= value;
            RaisePropertyChanged("Port");
        }
    }
    private string port;
}
Byelorussian answered 25/2, 2015 at 5:49 Comment(8)
Hi, ok I gave that a shot and it didn't produce a different result, check my updated questionl.Ivelisseivens
Did you read my last sentence? Do you have any binding errors in your output window at runtime?Byelorussian
System.Windows.Data Error: 40 : BindingExpression path error: 'ip' property not found on 'object' ''Proxy' (HashCode=6855507)'. BindingExpression:Path=ip; DataItem='Proxy' (HashCode=6855507); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String') System.Windows.Data Error: 40 : BindingExpression path error: 'port' property not found on 'object' ''Proxy Yes I doIvelisseivens
Show the model class which is stored in your ObservableCollection please.Byelorussian
Either you need to rename your properties to Url and Port. Or you need to change your xaml code. Also your model class should implement INPC. Maybe you should read a little bit about WPF and MVVM first.Byelorussian
Everything I have read stated that INPC was implemented if you use the ObservableCollection. Also, just changed xaml to ip, port and still no change.Ivelisseivens
What do you mean by no change? Still binding errors?Byelorussian
Actually not if I add the get; set; method. By the way as I'm trying to add INPC I keep getting told that this isn't a type: Proxy:INotifyPropertyChangeIvelisseivens

© 2022 - 2024 — McMap. All rights reserved.