1

My DataGrid's ItemSource returns empty objects or null. What can be the case ? All properties are bound. While adding data, it shows proper on the Grid, but while retrieving it gives null.

XML

  <DataGrid AutoGenerateColumns="False" Grid.Row="2" Height="208" HorizontalAlignment="Left" Margin="20,71,0,0" Name="dgvWell" VerticalAlignment="Top" Width="528" HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Visible" BorderBrush="#FFB7B39D" Background="LightYellow" RowBackground="LightGray" AlternatingRowBackground="#FFFFFFF5" BorderThickness="10" CanUserReorderColumns="False" CanUserSortColumns="False" FontSize="13" CanUserAddRows="False">
      <DataGrid.Columns>
          <DataGridTextColumn Header="Layer Name" Width="80" Binding="{Binding LayerName}"/>
          <DataGridTextColumn Width="100" Binding="{Binding Porosity}">
          <DataGridTextColumn.Header>
              <Grid Width="100">
                  <Grid.RowDefinitions>
                      <RowDefinition />
                      <RowDefinition/>
                  </Grid.RowDefinitions>
                  <TextBlock Text="Porosity" Grid.Row="0"/>
                  <ComboBox Grid.Row="1" Width="70" HorizontalAlignment="Center" Name="cboPorosity">
                      <ComboBoxItem Content="pascal" IsSelected="True" />
                      <ComboBoxItem Content="psi"/>
                      <ComboBoxItem Content="bar"/>
                      <ComboBoxItem Content="barye"/>
                  </ComboBox>
              </Grid>
          </DataGridTextColumn.Header>
          </DataGridTextColumn>   


          <DataGridTextColumn Header="Permeability" Binding="{Binding Permeability}"/>
          <DataGridTextColumn Width="120" Binding="{Binding Path= PerforationStartDepth,Mode=TwoWay}" ClipboardContentBinding="{Binding PerforationStartDepth}">
              <DataGridTextColumn.Header>

                  <Grid>
                      <Grid.RowDefinitions>
                          <RowDefinition Height="25"/>
                          <RowDefinition/>
                      </Grid.RowDefinitions>
                      <TextBlock Text="Perforation Start" Grid.Row="0"/>
                      <ComboBox Grid.Row="1" Width="60" Name="cboPerfStart">
                          <ComboBoxItem Content="ft" IsSelected="True" />
                          <ComboBoxItem Content="M"/>
                          <ComboBoxItem Content="cm"/>
                      </ComboBox>
                  </Grid>

              </DataGridTextColumn.Header>
          </DataGridTextColumn>
          <DataGridTextColumn Width="145"  Binding="{Binding PerforationEndDepth}">
              <DataGridTextColumn.Header>

                  <Grid>
                      <Grid.RowDefinitions>
                          <RowDefinition Height="25"/>
                          <RowDefinition/>
                      </Grid.RowDefinitions>
                      <TextBlock Text="Perforation End" Grid.Row="0"/>
                      <ComboBox Grid.Row="1" Width="60" Name="cboPerfEnd">
                          <ComboBoxItem Content="ft" IsSelected="True"/>
                          <ComboBoxItem Content="M"/>
                          <ComboBoxItem Content="cm"/>
                      </ComboBox>
                  </Grid>

              </DataGridTextColumn.Header>
          </DataGridTextColumn>

          <DataGridTextColumn Width="140"  Binding="{Binding ReservoirPressure,Mode=TwoWay}">
              <DataGridTextColumn.Header>                                    
                  <Grid>
                      <Grid.RowDefinitions>
                          <RowDefinition Height="25"/>
                          <RowDefinition/>
                      </Grid.RowDefinitions>
                      <TextBlock Text="Reservoir Pressure" Grid.Row="0"/>
                      <ComboBox Grid.Row="1" Width="60" Name="cboResPress">
                          <ComboBoxItem Content="pascal" IsSelected="True" />
                          <ComboBoxItem Content="psi"/>
                          <ComboBoxItem Content="bar"/>
                          <ComboBoxItem Content="barye"/>
                      </ComboBox>
                  </Grid>
              </DataGridTextColumn.Header>                               
          </DataGridTextColumn>
          <DataGridTextColumn Width="145" Header="Water Cut" Binding="{Binding WaterCut}"></DataGridTextColumn>
      </DataGrid.Columns>
</DataGrid>

The backend object:

public struct Step2Data
{
    public string LayerName { get; set; }
    public int Porosity { get; set; }
    public int Permeability { get; set; }
    public int PerforationStartDepth { get; set; }
    public int PerforationEndDepth { get; set; }
    public int ReservoirPressure { get; set; }
    public int WaterCut { get; set; }
}

 List<Step2Data> step2datas = dgvWell.ItemsSource as List<Step2Data>;

The above retrieval returns null.

Can you help me know, why does this grid doesn't return proper ItemSource.

EDIT

Based on your eg which helped me greatly I implemented my code. In my view, I have a combobox that's lets user select a number. Based on that number, that many number of rows get added to the grid. I tried to work on it, but it doesn't show any rows :

In my Model class:

public ObservableCollection<Step2Model> Step2ModelList 
{
    get {
        if (step2ModelList == null)
            step2ModelList = new ObservableCollection<Step2Model>();

        return step2ModelList;
    }
    set
    {
        step2ModelList = value;
        Changed("Step2ModelList");
    }
}

public void AddStep2ModelToList(Step2Model step2Model)
{
    Step2ModelList.Add(step2Model);
}

public void addRowsToList(int count)
{
    for (int i = 0; i < count; i++)
    {
        Step2ModelList.Add(new Step2Model());  // UPDATED
        /*
        AddItemCommand = new ActionCommand
        {
            ExecuteDelegate = o => Step2ModelList.Add(new Step2Model())
        };
        */
    }
}

DataGrid is bound to Step2ModelList

ItemsSource="{Binding Step2ModelList, Mode=TwoWay}">

On combo box selection,

private void cboNumZones_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    int num = (int)cboNumZones.SelectedItem;
    Console.WriteLine("Numer of Zones SElected = " + num);
    if (num > 0)
    {
        Step2InfoData st = this.DataContext as Step2InfoData;
        st.addRowsToList(count);
    }
}

After this the grid doesn't reflect the 2 added rows in Step2ModelList.

Yael
  • 1,566
  • 3
  • 18
  • 25
Tvd
  • 4,463
  • 18
  • 79
  • 125
  • First remark: Mode=TwoWay is default you don't have to specify it. – mswietlicki Aug 29 '13 at 12:52
  • 1
    You use "AddItemCommand = new ActionCommand" in addRowsToList incorrectly. Try simply Step2ModelList.Add(new Step2Model()) – mswietlicki Aug 29 '13 at 12:59
  • Removed Mode from dataGrid & replaced ActionCommand to Step2ModelList.Add(new Step2Model()) in addRowsToList(). But yet no difference. Added the same Step2ModelList.Add(new Step2Model()) in for loop in cboNumZones_SelectionChanged, that did the job. – Tvd Aug 29 '13 at 14:23

1 Answers1

1

I think, you don't understand concept of DataGrid.ItemSource. Read http://msdn.microsoft.com/en-us/library/system.windows.controls.datagrid.itemssource(v=vs.95).aspx

DataGrid.ItemSource is used to populate DataGrid not the other way around.

If you want to access DataGrid items use:

dgvWell.Items;

Update, ObservableCollection Sample:

ViewModel:

public class DataGridSampleViewModel
{
    public ObservableCollection<Step2Data> Data { get; set; }
    public ICommand AddItemCommand { get; set; }

    public DataGridSampleViewModel()
    {
        Data = new ObservableCollection<Step2Data>();

        AddItemCommand = new ActionCommand
        {
            ExecuteDelegate = o => Data.Add(new Step2Data { LayerName = DateTime.Now.Ticks.ToString() })
        };
    }
}

View code behind:

public partial class DataGridSampleView : Window
{
    public DataGridSampleView()
    {
        InitializeComponent();
        this.DataContext = new DataGridSampleViewModel();
    }
}

View:

<Window x:Class="SimpleMVVMApp.DataGridSampleView"
        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" 
        xmlns:simpleMvvmApp="clr-namespace:SimpleMVVMApp"
        mc:Ignorable="d"
        Title="DataGridSampleView" Height="300" Width="300" 
        d:DataContext="{d:DesignInstance simpleMvvmApp:DataGridSampleViewModel}">
    <StackPanel>
        <Button Content="Add new item" Command="{Binding AddItemCommand}" />
        <ListBox ItemsSource="{Binding Data}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding LayerName}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
</Window>

Full source code may be found at https://github.com/mswietlicki/SimpleMVVMApp

mswietlicki
  • 1,413
  • 12
  • 16
  • Gets or sets a collection that is used to generate the content of the control. So either you can use ItemSource to populate the grid or retrieve data from the grid. – Tvd Aug 26 '13 at 17:56
  • But it sync only one way with Items property. When ItemSource is set Items collection is readonly. http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemssource.aspx and http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.items.aspx – mswietlicki Aug 26 '13 at 18:58
  • If you wish to use ItemsSource you should read ObservableCollection sample in http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.itemssource.aspx – mswietlicki Aug 26 '13 at 19:00
  • To be honest I really don't understand how do I implement ObservableCollection in my case. I have an event on combo box selection where a numer is selected and based on that selection I create blank objects of Step2Data in List and assign the list as ItemSource. That's how the DataGrid items get started and user can input data in the rows added. Do I have to create the ObservableCollection object as public in the UI class ? Can you show me a small demo as is my case. Thanks a lot. – Tvd Aug 27 '13 at 11:22
  • Are you using MVVM pattern (or Prism)? – mswietlicki Aug 27 '13 at 11:31
  • I've added simple code that uses ObservableCollection bind to ListBox. – mswietlicki Aug 27 '13 at 14:30
  • Will the same be affective with DataGrid too instead of ListBox ? – Tvd Aug 27 '13 at 16:21
  • Yes and in MVVM you should try to never access view controls directly. Even using events is not recommended. – mswietlicki Aug 27 '13 at 20:16
  • How do you retrieve or access the binded object in code behind. Suppose I have a TextBox (individual not in List or so) that is binded to LayerName. How do I retrieve the value of LAyerName from the object in code behind ? – Tvd Aug 28 '13 at 09:20
  • 1
    All logic suppose to be in ViewModel not in code behind. But if you need LayerName for some visual adjustment you should access ViewModel from this.DataContext not TextBox. – mswietlicki Aug 28 '13 at 10:33
  • I can't access / find ActionCommand anywhere ? Seems you have implemented it separately ? – Tvd Aug 28 '13 at 13:33
  • 1
    See link to Github from the end of the answer. – mswietlicki Aug 28 '13 at 16:01
  • mswieticki, Thanks a lot. I highly appreciate your support. If you can help in this problem also, would be great. http://stackoverflow.com/questions/18493749/wpf-exception-binding-combbox/18494189?noredirect=1#comment27190244_18494189 – Tvd Aug 29 '13 at 07:33
  • Please have a look at the Update part of the Question. Am not able to add rows to the grid dynamically. – Tvd Aug 29 '13 at 12:35