0

I'm doing some binding, and using a third party control.

The issue I have is (or so I've worked (and therefore think)) the control is not part of the visual tree. So, I can't bind direct to the DataContext in the normal manner. Instead, I have to do the following

 <StackPanel.Resources>
                <loc:BackupResultsViewModel x:Key="MyVm" />
                <CollectionViewSource x:Key="StatusCollection" Source="{Binding Source={StaticResource MyVm}, Path=PassFailStatus}" />
            </StackPanel.Resources>


                    <xctk:Chart Height="300" Width="300" ShowLegend="True" >
                        <xctk:Chart.Areas>
                                <xctk:Area.Series>
                                    <xctk:Series Title="Overall status" DataPointsSource="{Binding Source={StaticResource StatusCollection}}">
                                        <xctk:Series.Layout>
                                            <xctk:PieLayout />
                                        </xctk:Series.Layout>
                                        <xctk:Series.DataPointBindings>
                                            <xctk:BindingInfo PropertyName="Y">
                                                <xctk:BindingInfo.Binding>
                                                    <Binding Path="Y"/>
                                                </xctk:BindingInfo.Binding>
                                            </xctk:BindingInfo>
                                            <xctk:BindingInfo PropertyName="Label">
                                                <xctk:BindingInfo.Binding>
                                                    <Binding Path="Label"/>
                                                </xctk:BindingInfo.Binding>
                                            </xctk:BindingInfo>
                                        </xctk:Series.DataPointBindings>


                                    </xctk:Series>
                                </xctk:Area.Series>
                            </xctk:Area>
                        </xctk:Chart.Areas>
                    </xctk:Chart>

        </StackPanel>

So, the line of code

<xctk:Series Title="Overall status" DataPointsSource="{Binding Source={StaticResource StatusCollection}}">

Shows it's binding the source to a StaticResource, and this is defined under StackPanel.Resources

And it works when I set the data in the constructor of my ViewModel.

However, I won't know the data at that point, the user will have to make some selections first and then press a button at which point I need to pass the new data to my control.

The problem I have is it does not work! The graph still renders but, with no data.

This is my property I'm binding too

    private ObservableCollection<DataPoint> _passFailStatus;
    public ObservableCollection<DataPoint> PassFailStatus
    {
        get { return this._passFailStatus; }
        set
        {
            if (this._passFailStatus == value)
                return;

            this._passFailStatus = value;
            OnPropertyChanged("PassFailStatus");

        }
    }

And the control

    private void ShowComplete(int backupComplete, int backupFailed, int backupSkipped)
    {
        //this.PassFailStatus initialized in constructor and in this method, same result
        App.Current.Dispatcher.Invoke((Action) (() =>
            {
                try
                {
                    this.PassFailStatus.Add(new DataPoint(-99, backupComplete, "Copied"));
                    this.PassFailStatus.Add(new DataPoint(-99, backupFailed, "Failed"));
                    this.PassFailStatus.Add(new DataPoint(-99, backupSkipped, "Skipped"));
                }
                catch (Exception ex)
                {
                    string s = ex.ToString();//for debugging
                }

            }));
    }

There are no exceptions thrown, and if I put a watch in my Property, I can see the setter is set, but afterwards, the getter is never called. I'm lost what I need to do.

MyDaftQuestions
  • 4,487
  • 17
  • 63
  • 120
  • Most likely issue is in oxyPlot which is not refreshed when binding model changes. You have to manually refresh it. Check out the details [here](http://stackoverflow.com/questions/20927669/how-to-refresh-oxyplot-plot-when-data-changes). – Rohit Vats Sep 28 '14 at 08:19
  • @RohitVats, whilst I'm sure this is correct, how is this possible when using MVVM? I don't have a direct reference to it and as far as I know, I can't reference by name when using MVVM. I guess my only other option is make it a UserControl and when I need it, create it, passing the data via the constructor – MyDaftQuestions Sep 28 '14 at 08:33
  • How about creating an attached behavior to refresh the oxyPlot on model change? – Rohit Vats Sep 28 '14 at 08:39
  • @RohitVats Right, yes. In that case, if it does require a refresh in this manner, my current approach won't work. I'm happy with that because as least it appears as if it's not my coding! :) – MyDaftQuestions Sep 28 '14 at 08:54

3 Answers3

1

It won't be enough to raise a OnPropertyChanged on your ObservableCollection, you need to raise it in the element thats in the ObservableCollection.

An example:

Your model:

public class Foo
{
    public int Bar { get; set; }
}

Which is used in:

private ObservableCollection<Foo> somthing;
public ObservableCollection<Foo> Something
{
    get { return something; }
    set
    {
        if (something == value)
            return;

        something = value;
        OnPropertyChanged("Something");

    }
}

Now OnPropertyChanged is only called when the Collection itself is changed. You have to change your model to:

public class Foo
{
    private int bar;
    public int Bar
    {
        get { return bar; }
        set
        {
            if(bar == value)
                return;
            bar = value;
            OnPropertyChanged("Bar");
        }
    }
}

Now your ObservableCollection should be aware of changes inside itself and update your view.

coder0815
  • 219
  • 2
  • 8
1

As stated under comments section, issue is not in your code but instead with OxyPlot which doesn't update the points when underlying model changes. For that to work you either need to call Refresh Or InvalidatePlot. Refer to the details provided here.

Also, in case you want to do it in MVVM way, I would suggest to create a attached behavior for your oxyPlot to manually refresh it.

Community
  • 1
  • 1
Rohit Vats
  • 79,502
  • 12
  • 161
  • 185
  • Is Attached behavior the same as a dependancy property? – MyDaftQuestions Sep 28 '14 at 10:35
  • Yeah they are termed as [Attached Properties](http://msdn.microsoft.com/en-us/library/ms749011(v=vs.110).aspx). Refer to the sample [here](http://www.mindscapehq.com/blog/index.php/2009/02/01/attached-behaviours-in-wpf/), [here](http://blogs.msdn.com/b/dgartner/archive/2009/11/11/wpf-attached-behavior-example-watermark-text.aspx) and [here](http://www.bjoernrochel.de/2009/08/19/the-attached-behavior-pattern/). – Rohit Vats Sep 28 '14 at 10:36
-1

Problem is in using ObservableCollections and adding to them. Try initializing oc using new, it should work. Offcourse, you will need to handle adding elements to collection in some other way.

Sasa
  • 32
  • 3
  • In the post, in the last code snippet, I explained that I initialize the OC with new, in the constructor – MyDaftQuestions Sep 28 '14 at 07:18
  • Yes, but using Add wont do the trick. It wont update your ui. – Sasa Sep 28 '14 at 07:20
  • I'm still lost. I'm adding to an ObservableCollection, not to a list. I have other properties on the page whcih use ObservableCollection and I just add and they update as and when they're added... – MyDaftQuestions Sep 28 '14 at 07:27