Databinding ObservableCollection<T> to Datagrid not working

330 views Asked by At

Update Now I think I have narrowed the problem. I created single class

public class OptionStrike
{
    public OptionStrike(double p1, double p2, int p3)
    {
        // TODO: Complete member initialization
        P_OI = p1;
        StrikePrice = p2;
        P_Volume = p3;
    }

    public OptionStrike()
    {
        // TODO: Complete member initialization
    }

    public double P_OI { get; set; }
    public double P_Volume { get; set; }
    public double StrikePrice { get; set; }
}

Now, if i load the values to this OptionStrike as

private void Test(object obj)
{
    oOs = new ObservableCollection<OptionStrike>(new OptionStrike[]
    {
        new OptionStrike(4201, 7500.00, 12345),
        new OptionStrike(818859, 7500.00, 123),
        new OptionStrike(84545, 8000.00, 23645),
        new OptionStrike(8889955, 8000.00,99999)
    });
}

it shows in the datagrid in the window, but if I do it like this:

    _oOC = new ObservableCollection<OptionStrike>();
    OptionStrike os = new OptionStrike();
    os.StrikePrice=7500;
    os.P_Volume=545;
    os.P_OI=45454;
    _oOC.Add(os);
    os.StrikePrice = 7600;
    os.P_Volume = 5566;
    os.P_OI = 45455;
    _oOC.Add(os);

The datagrid is blank..

The field oOC is populating allright, and I have checked it, but it is still not showing in the Datagrid... Any suggestions...

oOC is declared as

private ObservableCollection<OptionStrike> _oOC;
public ObservableCollection<OptionStrike> oOC
{
    get { return _oOC; }
    set
    {
        if (value != _oOC)
        {
            _oOC = value;
            OnPropertyChanged(new PropertyChangedEventArgs("oOC"));
        }
    }
}

Old Question I have an ObservableCollection which I am trying to bind to a DataGrid..

private ObservableCollection<Option> _optionChain = new ObservableCollection<Option>();
public ObservableCollection<Option> OptionChain
{
    get { return _optionChain; }
    set
    {
        if (value != _optionChain)
        {
            _optionChain = value;
            PropChanged("OptionChain");
        }
    }
}

My OptionChain collection is being populated like

private void ProcessOptionsData()
{
    OptionChain = d.ProcessOptionChainData(OptionChainHtmlElement, Ticker, Expiry);
}

Option Class has

public string type;             // option typ (put/call)
public string stock;            // option stock ticker
public string symbol;           // option symbol
public double strike;           // option strike price

And XAML is

<DataGrid ItemsSource="{Binding OptionChain}" AutoGenerateColumns="False" DataContext="{Binding Mode=Default}">
  <DataGrid.Columns>
    <DataGridTextColumn Header="Type" Binding="{Binding type}" />
    <DataGridTextColumn Header="Strike" Binding="{Binding strike}" />
  </DataGrid.Columns>
</DataGrid>

Now the Datagrid is not being populated. I tried AutoGenerateColumn="True", but to no avail... also tried DataGridTextColumn Binding to Option.strike and so on, but was unsuccessful..

Where am I going wrong?

(I am using ViewModelLocator)

Edit
Now i have cleared everything.. Just have one textbox, and one label. When i write something in textbox, it is not being reflected in label.. code is as

public class MainViewModel : INotifyPropertyChanged
    {
        #region Fields

        private string _ticker;
        public string Ticker
        {
            get { return _ticker; }
            set
            {
                if (value != _ticker)
                {
                    _ticker = value;
                    OnPropertyChanged("Ticker");
                }
            }
        }

        private string _status;
        public string Status
        {
            get { return _status;}
            set
            {
                if (value!=_status)
                {
                    _status = value;
                    OnPropertyChanged("Status");
                }
            }
        }

        public string PostBack
        {
            get { return string.Format("{0}, for expiry at ", Ticker); }
        }
        #endregion Fields

        public event PropertyChangedEventHandler PropertyChanged;
        // Create the OnPropertyChanged method to raise the event 
        protected void OnPropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }
    }

` MainWindow's XAML is like

<Grid>
  <StackPanel Orientation="Horizontal">
    <TextBox Background="Transparent" Foreground="White" Text="{Binding Ticker}" HorizontalContentAlignment="Left" Width="150" VerticalContentAlignment="Center" Height="28" FontSize="18" Margin="10,0,0,0" />
    <Label Content="{Binding PostBack}" Width="250" Height="28" Margin="10,0,0,0" />
  </StackPanel>
</Grid>

Codebehind of MainWindow is being used for datacontext..

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        MainViewModel mvm = new MainViewModel();
        this.DataContext = mvm;
    }
}
3

There are 3 answers

1
almulo On BEST ANSWER

With the new code provided, it looks like you'd just need to add a PropertyChanged notification for the PostBack property.

Since that property is calculated, it won't be recalculated automatically unless you notify it's changed. And you should do so in the Ticker setter because PostBack depends on its value. Like this:

    private string _ticker;
    public string Ticker
    {
        get { return _ticker; }
        set
        {
            if (value != _ticker)
            {
                _ticker = value;
                OnPropertyChanged("Ticker");
                OnPropertyChanged("PostBack");
            }
        }
    }

That way, every time you type something on your TextBox, you'll notify the view that PostBack's value has changed too, and that it has to refresh the Label's Binding.

Oh, by the way, TextBox's default Bindings have UpdateSourceTrigger set to LostFocus, I think. If you want the Label to be updated every time you write something without having to wait for leaving the TextBox, you might want to set it to PropertyChanged (and even use a Delay for better performance):

<TextBox Background="Transparent"
         Foreground="White"
         Text="{Binding Ticker, UpdateSourceTrigger=PropertyChanged, Delay=1000}"
         HorizontalContentAlignment="Left"
         Width="150"
         VerticalContentAlignment="Center"
         Height="28"
         FontSize="18"
         Margin="10,0,0,0" />
3
paparazzo On

NotifyPropertyChanged does not work the same way with a collection

try

private void ProcessOptionsData()
{   
    OptionChain.Clear();
    ForEach(Option opt in d.ProcessOptionChainData(OptionChainHtmlElement, Ticker, Expiry);
       OptionChain.Add(opt);
}
3
James Harcourt On

One problem is that you don't have getters or setters on your Option class properties.

It should look like this:

public string type { get; set; }
public string stock { get; set; } 
public string symbol { get; set; }
public double strike { get; set; }

As you had it, it would cause binding exceptions as the properties would not be found.

Also your DataContext in the XAML maybe wrong - but this is not possible to check with the code you have given.