views:

35

answers:

3

I'm trying to bind a property in my DataContext to a property in a ValidationRule:

public class ReleaseValidationRule : ValidationRule
{
    // I want to bind a value from my DataContext to this property:
    public CheckboxViewModels ValidReleases { get; set; }
    ...
}

Based on this thread, I created the CheckboxViewModels class just to act as a wrapper for a List<CheckboxViewModel> so that the list could be a DependencyProperty so that I could bind to it. However, in my Validate method on my ValidationRule, the ValidReleases list is always empty. Here's my XAML:

<TextBox>
    <TextBox.Text>
        <Binding Path="Release" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:ReleaseValidationRule>
                    <local:ReleaseValidationRule.ValidReleases>
                        <local:CheckboxViewModels List="{Binding Path=Releases,
                            Converter={StaticResource debugConverter}}"/>
                    </local:ReleaseValidationRule.ValidReleases>
                </local:ReleaseValidationRule>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

I know the Releases property (what I'm binding to the List property of CheckboxViewModels) has content because I have a TreeView just above the TextBox that shows the contents of Releases. The converter I have on the CheckboxViewModels.List binding does nothing, it's just a place where I can set a breakpoint. The funny thing is, that converter breakpoint never gets hit. It's as if the whole line <local:CheckboxViewModels List="{Binding Path=Releases, Converter={StaticResource debugConverter}}"/> never gets executed, so the ValidReleases property in my ValidationRule never gets set. What's going on?

Edit: here's what CheckboxViewModels looks like:

public class CheckboxViewModels : DependencyObject, IList<CheckboxViewModel>,
    IEnumerable<CheckboxViewModel>
{
    ...members necessary to implement IList, IEnumerable...

    public static readonly DependencyProperty ListProperty =
        DependencyProperty.Register(
            "List",
            typeof(List<CheckboxViewModel>),
            typeof(CheckboxViewModels),
            new PropertyMetadata(new List<CheckboxViewModel>())
        );

    public List<CheckboxViewModel> List
    {
        get { return (List<CheckboxViewModel>)GetValue(ListProperty); }
        set { SetValue(ListProperty, value); }
    }
}
A: 

Hi Sarah.

Smells like a missing Property Changed notification somewhere. Hard to see what CheckboxModels is about from this, but if it were ObservableCollection you'd get property changed without any extra work. Does this make sense?

HTH,
Berryl

Berryl
I updated my question to include `CheckboxViewModels` code. I'm not sure what events I should hook up.
Sarah Vessels
I do not see a requirement here for making the list a DP, since it looks like the binding Source and not the target. I would add a new property, for now, of ObservableCollection<CheckBoxViewModel> and try and re-work the solution with it. You can call it something clever like Releases_NEW and post any bindings that are giving you trouble. If it becomes clear that a DP is necessary, I see an avenue to try and make it work, and you will still have a starting point.
Berryl
A: 

Okay, now I just feel silly. I had had a constructor in CheckboxViewModels that set List = new List<CheckboxViewModel>(). I think this was somehow resetting something? I removed that constructor and the initial value of List is set only in the Register method for the DependencyProperty: new PropertyMetadata(new List<CheckboxViewModel>()). ValidReleases is now populated as expected with the following XAML:

<TextBox>
    <TextBox.Text>
        <Binding Path="Release" UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:ReleaseValidationRule ValidatesOnTargetUpdated="True">
                    <local:ReleaseValidationRule.ValidReleases>
                        <local:CheckboxViewModels
                            List="{Binding Path=Releases, Mode=OneWay}"/>
                    </local:ReleaseValidationRule.ValidReleases>
                </local:ReleaseValidationRule>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

Edit: not so silly afterall: not having a constructor in CheckboxViewModels resulted in two dependency properties of type CheckboxViewModels using the same list, so I had releases and other data in both the Releases property and another property. Adding the constructor back to CheckboxViewModels results in ValidReleases not having any items again. I think I must be binding something incorrectly.

Sarah Vessels
A: 

I stopped using validation rules and instead followed this tutorial about implementing IDataErrorInfo. That was my class instance is fully initialized by the time I get into this[string] to figure out the error message. The data I had been trying to pass in was just data from another property on the same instance. That is, I wanted to validate Property1 using some data from Property2. With IDataErrorInfo, when I'm validating Property1 and assembling an error message if necessary, I have access to Property2 as desired, without having to pass anything in.

Sarah Vessels