views:

114

answers:

3

Someone please help me understand why this binding does not work...

I have a class called SelectionManager with a property called 'dates' which is populated by a WCF service. The property is an array of structs which bundles a DateTime and an integer count of business objects.

public class SelectionManager : INotifyPropertyChanged {

    ... other properties ...

    public DQMServiceDateCountPair[] dates { get; private set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName) {
        if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }
    }

I have another class called DateSelector which has a DependencyProperty called 'pairs' setup to be the binding target of 'dates'.

public partial class DateSelector : UserControl {

... other stuff ...

public static readonly DependencyProperty pairsProperty = DependencyProperty.Register(
    "pairs",
    typeof(DQMServiceDateCountPair[]),
    typeof(DateSelector),
    new PropertyMetadata(new DQMServiceDateCountPair[0])
);

public DQMServiceDateCountPair[] pairs {
    get { return (DQMServiceDateCountPair[])GetValue(pairsProperty); }
    set { 
        Debug.WriteLine("adding dates");
        SetValue(pairsProperty, value);
        dateMode = DateMode.Years;
    }
}

}

In my MainPage.xaml, I have a line like this:

<date:DateSelector x:Name="dateSelector" pairs="{Binding dates}" />

It's weird, because all my other bindings in MainPage.xaml update correctly, including a ComboBox bound to 'dates'. My UserControl however, will not update. The Debug.Writeline doesn't get called in the set statement of the 'pairs' property.

In playing around with it, I've tried making the DQMServiceDateCountPair[] property into an ObservableCollection and implementing INotifyCollectionChanged, but that doesn't help.

If I leave either the source property or the target property as an array, and make the other an ObservableCollection, then I get a binding error that says it can't automatically convert one to the other, so Silverlight seems aware of the binding, it just doesn't update it.

Can anyone help?

P.S. I'm using Silverlight 3.

A: 

Try changing your code as follows:
1. Add DataMember/DataContract attributes
2. Make "set" public

[DataContract]
public class SelectionManager : INotifyPropertyChanged {

    [DataMember]
    public DQMServiceDateCountPair[] dates { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;

    public void NotifyPropertyChanged(string propertyName) {
        if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }
    }
Boris Modylevsky
I think you might be misunderstanding the problem. The SelectionManager class is updating correctly from the WCF Service. The problem is that the DateSelector class, whose property 'pairs' is bound to 'dates', is not updating.Unless I'm misunderstanding, the DataContract/DataMember stuff is used in the WebService to facilitate serialization. There's no serialization going on between the UserControls in my app.
Klay
Is the problem, that the NotifyPropertyChanged event is not being thrown? If so, Anthony's answer below addresses this issue.
Boris Modylevsky
A: 

Whats actually wierd is that the other stuff is working when you've coded your class the way you have. My guess is that the dates array gets set by some code that runs internally in your selection manager on completion of a WCF request.

Howerver whilst you have implemented INotifyPropertyChanged you aren't actually raising the event that it defines. You can't really combine INotifyPropertyChanged with the Auto-property C# syntax. You need this:-

public SelectionManager : INotifyPropertyChanged
{
   private DQMServiceDateCountPair[] myDates;
   public DQMServiceDateCountPair[] dates
   {
     get { return myDates; }
     set
     {
       myDates = value;
       NotifyPropertyChanged("dates");
     }
     // rest of your code
}
AnthonyWJones
Actually, I am raising the event in the callback from the WCF service call when it sets the 'dates' property--just forgot to include that bit of code. I've now rewritten my code to what you've got above. Still doesn't update the binding target.
Klay
A: 

So, here's what what going on. The binding has been working perfectly well this whole time. For the past week I've been struggling with this, it's been happily updating along--but because of a faulty assumption on my part, I could never see it.

In case anyone else harbors this faulty assumption, let me spell it out:

The GetValue and SetValue calls are not made automatically by virtue of the fact that you are declaring a Dependency Property. The "new PropertyMetadata()" part of the declaration has an overload that takes a callback method. In this callback method, you have to set the property value yourself. For instance, in my code, I made this the PropertyMetadata call:

new PropertyMetadata(new PropertyChangedCallback(OnPairsPropertyChanged))

and the callback method reads like this:

private static void OnPairsPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) {
    ((DateSelector)d).pairs = (DQMServiceDateCountPair[])e.NewValue;
}

Thanks to everyone who tried to help!

Klay