UWP C# / XAML Slider Value doesn't honor bound backing property

I've run into an issue where the Slider control value isn't honor the value of the backing property to which it's bound. Is this a bug, or am I doing something wrong?

XAML Code:

<Slider x:Name="DefenseSlider" Width="220" StepFrequency="1"
                            Minimum="0"
                            Maximum="10"
                            Value="{Binding CharacterDefense, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

C# backing code:

        public int CharacterDefense
    {
        get { return NewCharacter.CharacterDefense; }
        set
        {
            CalculateCharacterPointsRemaining();
            if (value <= CharacterPointsAvailable)
            {
                NewCharacter.CharacterDefense = value;
            }
            if (value > CharacterPointsAvailable)
            {
                NewCharacter.CharacterDefense = CharacterPointsAvailable;
            }


            CalculateCharacterPointsRemaining();
        }
    }

If it's a bug, does anyone know of a workaround, to ensure the value of the slider can go no higher than the backing value?

Regards...

Answers


For the binding to be aware of CharacterDefense property changes, you need to raise the PropertyChanged event of INotifyPropertyChanged interface.

set
{
    CalculateCharacterPointsRemaining();
    if (value <= CharacterPointsAvailable)
    {
        NewCharacter.CharacterDefense = value;
    }
    if (value > CharacterPointsAvailable)
    {
        NewCharacter.CharacterDefense = CharacterPointsAvailable;
    }
    CalculateCharacterPointsRemaining();
    OnPropertyChanged();
}

However, the binding ignores the event if it is raised in the property setter call that was triggered by the binding itself. To make it work, you will need to send the event to the end of the dispatcher queue:

set
{
    CalculateCharacterPointsRemaining();
    if (value <= CharacterPointsAvailable)
    {
        NewCharacter.CharacterDefense = value;
    }
    if (value > CharacterPointsAvailable)
    {
        NewCharacter.CharacterDefense = CharacterPointsAvailable;
    }
    CalculateCharacterPointsRemaining();
    Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => 
        OnPropertyChanged(nameof(CharacterDefense)));
}

Dispatcher is a property of the Page class and you won't have access to it in the view model, unless you pass it from the view. While you could do that, it is generally a bad idea.

Slider control has Maximum property for a reason. If you want to limit the allowed range of values dynamically, you should add a view model property that returns CharacterPointsAvailable. Of course, whenever this value changes, you will need to RaisePropertyChanged to notify the binding that it should update the value:

public int MaxCharacterDefense
{
    get { return CharacterPointsAvailable; }
}

private void CharacterPointsAvailable()
{
    // ... existing method logic
    OnPropertyChanged(nameof(MaxCharacterDefense));
}

You can now bind your slider to this property:

<Slider x:Name="DefenseSlider" Width="220" StepFrequency="1"
    Minimum="0"
    Maximum="{Binding MaxCharacterDefense}"
    Value="{Binding CharacterDefense, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

The control now won't allow invalid values any more, so you could simplify the CharacterDefense setter:

set
{
    NewCharacter.CharacterDefense = value;
    CalculateCharacterPointsRemaining();
}

Need Your Help

Confusion about what ref/heads/[branch-name] means

git branch

Currently I want to perform a rebase on my local branch , lets call this branch X. I want to rebase it onto my local branch Y. I'm using the WebStorm IDE to do this and in the onto dropdown it list...

Authentication with CakePHP 2.4 only with sha1?

authentication login cakephp-2.4

I got some troubles with the authentication in CakePHP 2.4. I baked a simple App to create a login. I did everything like in the book (Auth and Tutorial). But only sha1 worked. But not sha256 or md5.