1

I bind as follows:

views:SciChartUserControl Name="SciChartUserControl" Quotes="{Binding QuoteCollection}"></views:SciChartUserControl>

I know for sure that QuoteCollection updates because a grid also binds to it and I see it updated.I want to be notified in the code-behind of my SciChartUserControl view but QuotesPropertyChanged is never invoked. This is driving me crazy, I have tried different ways for hours...something obvious I am overlooking?

public partial class SciChartUserControl : UserControl
{
    private SciChartControlViewModel _viewModel;

    public SciChartUserControl()
    {

        //Set ViewModel Datacontext
        _viewModel = new SciChartControlViewModel();
        DataContext = _viewModel;

        InitializeComponent();
    }

    public static DependencyProperty QuotesProperty = DependencyProperty.Register("Quotes", typeof(List<Quote>), typeof(SciChartUserControl), new PropertyMetadata(QuotesPropertyChanged));

    public List<Quote> Quotes
    {
        get
        {
            return (List<Quote>)GetValue(QuotesProperty);
        }

        set
        {
            SetValue(QuotesProperty, value);
        }
    }

    private static void QuotesPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        throw new NotImplementedException();

        var quotes = (List<Quote>) e.NewValue;
    }



}

EDIT: I added part of the view that hosts the SciChartUserControl.

 <dxdo:LayoutPanel Caption="Time Series Visualization">

                        <views:SciChartUserControl Name="SciChartUserControl" Quotes="{Binding QuoteCollection}"></views:SciChartUserControl>

                    </dxdo:LayoutPanel>

                    <dxdo:LayoutPanel Caption="Time Series Data">
                        <dxg:GridControl Name="SampleDataGridControl" ItemsSource="{Binding QuoteCollection}" AutoGenerateColumns="AddNew" EnableSmartColumnsGeneration="True" AutoGeneratedColumns="SampleDataGridControl_OnAutoGeneratedColumns">
                            <dxg:GridControl.View>
                                <dxg:TableView AllowEditing="False" AutoWidth="True" BestFitArea="All" AllowBestFit="True" ShowGroupPanel="True" ShowSearchPanelMode="Always"/>
                            </dxg:GridControl.View>
                        </dxg:GridControl>
                    </dxdo:LayoutPanel>
Matt
  • 7,004
  • 11
  • 71
  • 117
  • So `QuoteCollection` is a property of class `SciChartControlViewModel`, and it is initialized in the SciChartControlViewModel constructor? You might show us the SciChartControlViewModel code, too. – Clemens Feb 05 '15 at 13:41
  • No, I host the SciChartControl inside a different WPF UserControl. The viewmodel does in fact include a QuoteCollection. I edited my question and added part of the view to show that another control also binds to QuoteCollection and that updates just fine. – Matt Feb 05 '15 at 13:52
  • But then don't set the DataContext in the SciChartUserControl's constructor. That overwrites the inherited DataContext from the parent control. – Clemens Feb 05 '15 at 13:54
  • I need access to the view model because it is supposed to act on the updated `Quotes`. How else would I access the view model? – Matt Feb 05 '15 at 14:02
  • When you said you're hosting the SciChartControl inside a different WPF UserControl, my assumption was that the DataContext (that holds the view model object) is inherited by that outer control. Why else would you have told us that? Anyway, that doesn't seem to be the case here. – Clemens Feb 05 '15 at 14:07
  • The outer control's datacontext exposes the `QuoteCollection` property. But as mentioned this is not the issue here, `QuoteCollection` is updated but the update was so far not reflected in the inner controls DependencyProperty. Sheridan's solution only works if I do not set the datacontext within my code behind. But then I lose access to the view model. How can I now reflect the updated `Quotes` DependencyProperty in the viewmodel? – Matt Feb 05 '15 at 14:10
  • When the outer control's DataContext holds your view model, you must not overwrite the DataContext in the SciChartUserControl's constructor. The binding `Quotes="{Binding QuoteCollection}"` uses the inherited DataContext as its source object. – Clemens Feb 05 '15 at 14:52
  • And just to clarify that: we are talking about replacing the entire QuoteCollection list, not about changing list elements like adding or removing? – Clemens Feb 05 '15 at 15:00
  • Yes, replacing the entire collection. – Matt Feb 05 '15 at 15:38

3 Answers3

1

Try using another constructor for the PropertyMetadata class:

public static DependencyProperty QuotesProperty = DependencyProperty.Register("Quotes", 
    typeof(List<Quote>), typeof(SciChartUserControl), 
    new PropertyMetadata(someDefaultvalue, QuotesPropertyChanged));

It could be that the single parameter constructor that takes a PropertyChangedCallback object that you are using is getting mixed up with the one that takes a single object parameter.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Ha, you nailed it. But how is this possible? I would like to understand why this made all the difference – Matt Feb 05 '15 at 13:57
  • This only works if I don't set the datacontext in my code-behind. But then I am not able to reflect the updated `QuoteCollection` in my view model. How to go about this? Thanks. – Matt Feb 05 '15 at 14:10
  • It is possible because one constructor is expecting an object of type `PropertyChangedCallback` and the other is expecting one of type `object`. The compiler tries to map your call to the correct constructor, but as your `QuotesPropertyChanged` method isn't actually a `PropertyChangedCallback` object, it chose the single `object` default value parameter constructor instead, so you had a default value of your method. It's poor programming on Microsoft's part, not yours. – Sheridan Feb 05 '15 at 14:19
  • *How to go about this?*... try using a [`RelativeSource Binding`](https://msdn.microsoft.com/en-us/library/system.windows.data.binding.relativesource(v=vs.110).aspx) instead of setting the `DataContext`. – Sheridan Feb 05 '15 at 14:21
  • Maybe I miscommunicated: What I have is a data object in an outer control to which I can bind inside that outer control. The outer control hosts an inner control. I need to perform an action with the updated data object each time it changes within the view model of the inner control. – Matt Feb 05 '15 at 14:25
  • Dude, that's another question, so ask a new question for a solution. You can link to this one if it helps. – Sheridan Feb 05 '15 at 14:39
  • 1
    @Sheridan Why should QuotesPropertyChanged not be a PropertyChangedCallback? It has the correct signature. I've never noticed that my compiler won't choose the right PropertyMetadata constructor when writing `new PropertyMetadata(CallbackMethod)`. – Clemens Feb 05 '15 at 14:55
  • You'd better ask Microsoft, because the compiler seems to select the constructor with the single `object` parameter instead... I don't know why it does that, but I know what you mean. – Sheridan Feb 05 '15 at 14:58
  • @Sheridan Just checked this again (with .Net 4.5). The compiler choses the correct PropertyMetadata constructor. Everything else would frighten me. – Clemens Feb 05 '15 at 15:17
  • @Clemens, I didn't actually check this... I just noticed the two single property constructors and guessed that that's what happened. If the compiler *does* choose the right constructor, I'm not sure why using another one fixed this problem... very peculiar. – Sheridan Feb 05 '15 at 15:50
  • @Sheridan, I dug a bit further into this matter, and your suggestion actually does not work as originally intended. The DependencyProperty does not work if the inner control view's DataContext is set to its matching viewmodel. I removed the creation of a new DataContext from code-behind and instead set the DataContext in the view xaml to its viewmodel. So the inner view's DatraContext is its matching viewModel and then the DependencyProperty does not work. Any idea why that is the case? – Matt Feb 05 '15 at 17:15
  • It's probably just a `Binding` error... do you have any errors in the Output Window in Visual Studio? – Sheridan Feb 05 '15 at 17:17
  • Got it to work `` – Matt Feb 05 '15 at 17:31
0

try this... in the dependency property declaration change PropertyMetadata to the following..

new PropertyMetadata(null, new PropertyChangedCallback(QuotesPropertyChanged))
Bathineni
  • 3,436
  • 18
  • 25
0

I believe this is because you have set your DataContext in your code behind, I ran into the same issue when setting it in XAML? It seems as though a DependencyProperty is being bound relative to the DataContext of the UserControl. UserControl's DependencyProperty is null when UserControl has a DataContext

<views:SciChartUserControl Name="SciChartUserControl"
                           Quotes="{Binding DataContext.QuoteCollection, RelativeSource={RelativeSource AncestorType={x:Type dxdo:LayoutPanel}}}" />
Community
  • 1
  • 1
Derrick Moeller
  • 4,808
  • 2
  • 22
  • 48
  • "It seems as though a DependencyProperty is being bound relative to the DataContext of the UserControl". What? Of course it does that, unless you explicitly set the Source or RelativeSource of the binding. This is the exact purpose of the DataContext property. – Clemens Feb 05 '15 at 14:49
  • @Clemens You are correct(obviously), that's the issue at hand(imo) and what my solution addresses. I don't feel however as though this is universally understood. As evidence, my question was downvoted and didn't receive an answer for two weeks? Certainly the community is aware that we can bind elements within a UserControl relative to the DataContext of the UserControl e.g. the Text property of a TextBox would be bound relative to it's inherited DataContext. What we do less frequently is bind to a property of the UserControl itself. – Derrick Moeller Feb 05 '15 at 15:00