1

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;
    }
}
Ashutosh
  • 107
  • 1
  • 5
  • It is not being populated - it is being created. PropChanged does not work on a collection same way. If you Clear the OC and then Add the values it should work. – paparazzo Jun 11 '15 at 16:51
  • Is the Binding working correctly? You're binding the DataContext to your own DataContext, which seems pretty odd and useless... Are you sure that's what you wanted to achieve? – almulo Jun 11 '15 at 17:02
  • @almulo Yup binding is working correctly, but i am facing one problem which i must mention regarding binding.. Editing the question.. – Ashutosh Jun 11 '15 at 17:17
  • Did you try my answer? Yes or No? – paparazzo Jun 11 '15 at 17:33
  • It sounds like your `DataGrid.DataContext` is incorrect. Can you confirm what object it is? You can use a 3rd party tool like [WPF Snoop](https://snoopwpf.codeplex.com/) to verify. (Also @almulo is probably correct that you do not need the `DataContext="{Binding Mode=Default}"`... that bit of XAML makes no sense whatsoever) – Rachel Jun 11 '15 at 17:37
  • @Blam I tried your method, and am getting this runtime exception.. "Additional information: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread." Now what?? :( – Ashutosh Jun 11 '15 at 17:40
  • What are you not disclosing? Where is the CollectionView or another thread? Post complete code to reproduce the solution. – paparazzo Jun 11 '15 at 17:44
  • adding complete code of mainviewmodel and downloader class – Ashutosh Jun 11 '15 at 18:07
  • @Rachel I tried without that Binding Mode=Default too.. It is just that this was tried last before i posted the question.. – Ashutosh Jun 11 '15 at 18:15
  • You are passing a UIelement to another thread? – paparazzo Jun 11 '15 at 20:12
  • Does it work if you don't use a Background thread to set the collection? I've had issues with the property changed notifications not getting run when triggered from a background thread – Rachel Jun 11 '15 at 20:50
  • @Rachel No, even if i dont use background thread, it doesnt work... Now even simple things like reflecting input of textbox in a label is not working... Please correct me where am i doing the mistake.. editing the question.. – Ashutosh Jun 12 '15 at 06:46

3 Answers3

1

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.

James Harcourt
  • 6,017
  • 4
  • 22
  • 42
  • Are you asking me whether you can post your complete code? Why not try giving your "Option" class properties get/set as shown and report back ... – James Harcourt Jun 11 '15 at 18:28
  • As I say there's every chance your data context is wrong - if it is a main window make it 'self' at Window level in XAML. Download https://snoopwpf.codeplex.com to check your bindings at runtime. – James Harcourt Jun 11 '15 at 19:19
  • will do that and report back... am trying to remove excess codes like viewmodellocator, as i have only one view and ViewModel.. also creating a new List to show in datagrid.. And am still not able to get label updated after text is changed in textbox.. it is reflected in viewmodel as i can see it by pausing execution, but Propertychanged event is showing no response, i.e. the places where the property is used is not being updated... – Ashutosh Jun 11 '15 at 19:28
0

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);
}
paparazzo
  • 44,497
  • 23
  • 105
  • 176
  • It should work just with the NotifyPropertyChanged, no need to add items one by one. – almulo Jun 11 '15 at 17:01
  • @almulo But op stated it is not working. NotifyPropertyChanged does not work the same way with a collection. Did you vote me down? – paparazzo Jun 11 '15 at 17:12
  • Not a downvoter, but your question showed up in the low quality posts review queue. More explanation would be helpful. – Jeff B Jun 11 '15 at 21:56
0

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" />
almulo
  • 4,918
  • 1
  • 20
  • 29
  • Worked, thanks... now back to Datagrid binding of ObservableCollection... will revert back after implementing this fully.... – Ashutosh Jun 12 '15 at 15:14