-1

I have some XAML that looks (trimmed) like this, with a button tying its IsEnabled attribute to a subproperty:

<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=Window}}">
...
    <Button x:Name="continueButton" Content="Continue" IsEnabled="{Binding CurrentQuestion.AnswerSelected, Mode=OneWay}" Click="continueButton_Click"/>
...

CurrentQuestion is a property that pulls the current one from a collection:

public Question CurrentQuestion {
        get
        {
            return Questions[QuestionNo];
        }
        set
        {
            Questions[QuestionNo] = value;
        }
}

AnswerSelected checks whether any of the Answers are marked as selected.

public bool AnswerSelected
{
        get
        {
            return Answers.Any(a => a.Selected);
        }
}

The Selected property itself is set by radio buttons bound to the possible answers. Thus, the user should be able to continue after choosing an answer.

The Answers collection is monitored for changes, and calls the OnPropertyChanged() method from INotifyPropertyChanged for the AnswerSelected bool property like so:

public Answer[] Answers
{
        get
        {
            return _answers;
        }
        set
        {
            _answers = value;
            OnPropertyChanged("Answers");
            OnPropertyChanged("AnswerSelected");
        }
}

The binding successfully sets the button to disabled to begin with, but no change to the radio buttons then re-enables the button. I tried moving AnswerSelected to be a property at the same level as CurrentQuestion but this didn't work either.

What am I missing to get this button to re-enable? Also, is there a better way to accomplish this same thing?

Edit:

This is the code for the radio button setting.

<Grid DataContext="{Binding CurrentQuestion, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}">
        <ItemsControl ItemsSource="{Binding Answers}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <RadioButton GroupName="AnswerGroup" IsChecked="{Binding Selected}">
                            <TextBlock Text="{Binding Text}" />
                        </RadioButton>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </Grid>

So it looks like this:

CurrentAnswer (Questions[QuestionNo])
    AnswerSelected (Answers.Any(a => a.Selected))

Edit 2:

I think my question, effectively, is this: The bound property is a calculated property, but the calculation uses the subproperty of an array element. How do I, therefore, raise notification when that subproperty is changed, which itself is in a different class that defines each array element?

Dan
  • 1,130
  • 2
  • 20
  • 38
  • Try triggering `OnPropertyChanged("CurrentQuestion.AnswerSelected");` in your viewmodel – NtFreX Sep 21 '16 at 17:03
  • 1
    maybe you should add `OnPropertyChanged("CurrentQuestion");` somethere. or better use Button.Command property instead of IsEnabled+Click event. – ASh Sep 21 '16 at 17:04
  • I allways writte wrappers in my viewmodels instead of using neasted bindings. Its easier and nicer in my opinion – NtFreX Sep 21 '16 at 17:06
  • 1
    I've tried adding each of those `OnPropertyChanged` items to no avail. – Dan Sep 21 '16 at 17:10
  • If `CurrentQuestion` is still the same object that's not gonna work. `Question` needs to implement `INotifyPropertyChanged` and raise `PropertyChanged` appropriately. – 15ee8f99-57ff-4f92-890c-b56153 Sep 21 '16 at 17:30
  • OnPropertyChanged("AnswerSelected") is only going to be called when the array of answers is set, this does not happen when you select an answer. You should add the code for the answer selection radio buttons to your question. – ndonohoe Sep 21 '16 at 17:36
  • Hi @EdPlunkett. `Question` does implement `INotifyPropertyChanged` and currently `Answers[]` fires it for `Answers` (to update radio buttons) and `AnswerSelected` (probably out of desperation). I presumably need to add something to `Answer.Selected` but that's a different class, an array of which is within each `Question`. – Dan Sep 22 '16 at 09:21
  • Good point, @ndonohoe. I've added the radio button binding. – Dan Sep 22 '16 at 09:23

1 Answers1

0

What I eventually needed to do, in a way that was influenced by this question, was to subscribe to the PropertyChanged event of each Answer from the Question class.

void SubscribeToSelect(Answer item)
{
    item.PropertyChanged += (s, e) => this.AnswerSelected = e.PropertyName == "Selected" && item.Selected ? true : this.AnswerSelected;
}

When that fired, I updated the Question.AnswerSelected property and fired an update on that too, which in turn updated the binding to the button:

private bool _answerSelected;
public bool AnswerSelected
{
    get
    {
        return _answerSelected;
    }
    set
    {
        _answerSelected = value;
        OnPropertyChanged("AnswerSelected");
    }
}
Dan
  • 1,130
  • 2
  • 20
  • 38